sc_report_handler.cc revision 13182:9e030f636a8c
11758SN/A/*
21762SN/A * Copyright 2018 Google, Inc.
31758SN/A *
41758SN/A * Redistribution and use in source and binary forms, with or without
51758SN/A * modification, are permitted provided that the following conditions are
61758SN/A * met: redistributions of source code must retain the above copyright
71758SN/A * notice, this list of conditions and the following disclaimer;
81758SN/A * redistributions in binary form must reproduce the above copyright
91758SN/A * notice, this list of conditions and the following disclaimer in the
101758SN/A * documentation and/or other materials provided with the distribution;
111758SN/A * neither the name of the copyright holders nor the names of its
121758SN/A * contributors may be used to endorse or promote products derived from
131758SN/A * this software without specific prior written permission.
141758SN/A *
151758SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161758SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171758SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
181758SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
191758SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
201758SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
211758SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
221758SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
231758SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
241758SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
251758SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
261758SN/A *
272665Ssaidi@eecs.umich.edu * Authors: Gabe Black
282665Ssaidi@eecs.umich.edu */
292665Ssaidi@eecs.umich.edu
301758SN/A#include <fstream>
312SN/A#include <map>
322984Sgblack@eecs.umich.edu#include <sstream>
33732SN/A#include <string>
343565Sgblack@eecs.umich.edu
35732SN/A#include "base/logging.hh"
362984Sgblack@eecs.umich.edu#include "systemc/core/process.hh"
373536Sgblack@eecs.umich.edu#include "systemc/core/scheduler.hh"
38732SN/A#include "systemc/ext/core/sc_main.hh"
39732SN/A#include "systemc/ext/utils/sc_report_handler.hh"
401858SN/A
411717SN/Anamespace sc_core
422683Sktlim@umich.edu{
432680Sktlim@umich.edu
44676SN/Anamespace
452710Sstever@eecs.umich.edu{
462SN/A
471858SN/Astd::unique_ptr<std::string> logFileName;
482SN/Astd::unique_ptr<std::ofstream> logFile;
491147SN/A
501147SN/Astruct ReportCatInfo
512SN/A{
522SN/A    explicit ReportCatInfo(sc_actions actions) :
532SN/A        actions(actions), count(0), limit(-1)
542SN/A    {}
552SN/A    ReportCatInfo() : ReportCatInfo(SC_UNSPECIFIED) {}
562680Sktlim@umich.edu
572SN/A    bool
582680Sktlim@umich.edu    checkLimit(sc_actions &actions)
59190SN/A    {
602680Sktlim@umich.edu        if (limit == 0 || count < limit)
612680Sktlim@umich.edu            return false;
622114SN/A        if (limit != -1)
633468Sgblack@eecs.umich.edu            actions |= SC_STOP;
642700Sktlim@umich.edu        return true;
654172Ssaidi@eecs.umich.edu    }
662680Sktlim@umich.edu
672700Sktlim@umich.edu    sc_actions actions;
682700Sktlim@umich.edu    int count;
692SN/A    int limit;
702SN/A};
712SN/A
721133SN/Aconst char *severityNames[] = {
73716SN/A    [SC_INFO] = "Info",
741133SN/A    [SC_WARNING] = "Warning",
75716SN/A    [SC_ERROR] = "Error",
76716SN/A    [SC_FATAL] = "Fatal"
77716SN/A};
78716SN/A
79716SN/AReportCatInfo catForSeverity[SC_MAX_SEVERITY] =
80716SN/A{
814172Ssaidi@eecs.umich.edu    [SC_INFO] = ReportCatInfo(SC_DEFAULT_INFO_ACTIONS),
82716SN/A    [SC_WARNING] = ReportCatInfo(SC_DEFAULT_WARNING_ACTIONS),
83716SN/A    [SC_ERROR] = ReportCatInfo(SC_DEFAULT_ERROR_ACTIONS),
844172Ssaidi@eecs.umich.edu    [SC_FATAL] = ReportCatInfo(SC_DEFAULT_FATAL_ACTIONS)
85716SN/A};
86716SN/A
874172Ssaidi@eecs.umich.edustd::map<std::string, ReportCatInfo> catForMsgType;
88716SN/Astd::map<std::pair<std::string, sc_severity>, ReportCatInfo>
89716SN/A    catForSeverityAndMsgType;
90716SN/A
91716SN/Aint verbosityLevel = SC_MEDIUM;
92716SN/A
93716SN/Asc_actions suppressedActions = SC_UNSPECIFIED;
94716SN/Asc_actions forcedActions = SC_UNSPECIFIED;
951133SN/Asc_actions catchActions = SC_UNSPECIFIED;
96716SN/A
97716SN/Asc_report_handler_proc reportHandlerProc = &sc_report_handler::default_handler;
98716SN/A
99716SN/Asc_actions maxAction = SC_ABORT;
100716SN/A
101716SN/Astd::unique_ptr<sc_report> globalReportCache;
102716SN/A
103716SN/A} // anonymous namespace
104716SN/A
105716SN/Avoid
106716SN/Asc_report_handler::report(sc_severity severity, const char *msg_type,
107716SN/A                          const char *msg, const char *file, int line)
1084172Ssaidi@eecs.umich.edu{
1094172Ssaidi@eecs.umich.edu    report(severity, msg_type, msg, SC_MEDIUM, file, line);
1104172Ssaidi@eecs.umich.edu}
1112147SN/A
112716SN/Avoid
1134172Ssaidi@eecs.umich.edusc_report_handler::report(sc_severity severity, const char *msg_type,
114716SN/A                          const char *msg, int verbosity, const char *file,
115716SN/A                          int line)
116716SN/A{
117716SN/A    if (severity == SC_INFO && verbosity > verbosityLevel)
1181133SN/A        return;
119716SN/A
1201133SN/A    ReportCatInfo &sevInfo = catForSeverity[severity];
121716SN/A    ReportCatInfo &msgInfo = catForMsgType[msg_type];
122716SN/A    ReportCatInfo &sevMsgInfo = catForSeverityAndMsgType[
123739SN/A        std::make_pair(std::string(msg_type), severity)];
124739SN/A
1252683Sktlim@umich.edu    sevInfo.count++;
1262683Sktlim@umich.edu    msgInfo.count++;
127716SN/A    sevMsgInfo.count++;
128716SN/A
1292SN/A    sc_actions actions = SC_UNSPECIFIED;
1302683Sktlim@umich.edu    if (sevMsgInfo.actions != SC_UNSPECIFIED)
1312SN/A        actions = sevMsgInfo.actions;
1323521Sgblack@eecs.umich.edu    else if (msgInfo.actions != SC_UNSPECIFIED)
1332147SN/A        actions = msgInfo.actions;
1342SN/A    else if (sevInfo.actions != SC_UNSPECIFIED)
1354172Ssaidi@eecs.umich.edu        actions = sevInfo.actions;
1362SN/A
1372SN/A    actions &= ~suppressedActions;
1382341SN/A    actions |= forcedActions;
1392341SN/A
1402SN/A    if (sevMsgInfo.checkLimit(actions) && msgInfo.checkLimit(actions))
1412SN/A        sevInfo.checkLimit(actions);
1422SN/A
1432154SN/A    ::sc_gem5::Process *current = ::sc_gem5::scheduler.current();
1442SN/A    sc_report report(severity, msg_type, msg, verbosity, file, line,
1452SN/A            sc_time::from_value(::sc_gem5::scheduler.getCurTick()),
1462245SN/A            current ? current->name() : nullptr, -1);
1472245SN/A
1482245SN/A    if (actions & SC_CACHE_REPORT) {
1493459Sgblack@eecs.umich.edu        if (current) {
1502245SN/A            current->lastReport(&report);
1512245SN/A        } else {
1522245SN/A            globalReportCache =
1532245SN/A                std::unique_ptr<sc_report>(new sc_report(report));
1542245SN/A        }
1553459Sgblack@eecs.umich.edu    }
1562245SN/A
1572245SN/A    reportHandlerProc(report, actions);
1584997Sgblack@eecs.umich.edu}
1594997Sgblack@eecs.umich.edu
1604997Sgblack@eecs.umich.eduvoid
1614997Sgblack@eecs.umich.edusc_report_handler::report(sc_severity, int id, const char *msg,
1624997Sgblack@eecs.umich.edu                          const char *file, int line)
1634997Sgblack@eecs.umich.edu{
1644997Sgblack@eecs.umich.edu    warn("%s:%d %s\n", file, line, msg);
1654997Sgblack@eecs.umich.edu    warn("%s not implemented.\n", __PRETTY_FUNCTION__);
1664997Sgblack@eecs.umich.edu}
1674997Sgblack@eecs.umich.edu
1684997Sgblack@eecs.umich.edusc_actions
1694997Sgblack@eecs.umich.edusc_report_handler::set_actions(sc_severity severity, sc_actions actions)
1704997Sgblack@eecs.umich.edu{
1714997Sgblack@eecs.umich.edu    ReportCatInfo &info = catForSeverity[severity];
1724997Sgblack@eecs.umich.edu    sc_actions previous = info.actions;
1734997Sgblack@eecs.umich.edu    info.actions = actions;
1744997Sgblack@eecs.umich.edu    return previous;
1754997Sgblack@eecs.umich.edu}
1762159SN/A
1773468Sgblack@eecs.umich.edusc_actions
1782159SN/Asc_report_handler::set_actions(const char *msg_type, sc_actions actions)
1795543Ssaidi@eecs.umich.edu{
1802SN/A    ReportCatInfo &info = catForMsgType[msg_type];
1812SN/A    sc_actions previous = info.actions;
1823459Sgblack@eecs.umich.edu    info.actions = actions;
1833459Sgblack@eecs.umich.edu    return previous;
1843459Sgblack@eecs.umich.edu}
1853459Sgblack@eecs.umich.edu
1863459Sgblack@eecs.umich.edusc_actions
1873459Sgblack@eecs.umich.edusc_report_handler::set_actions(
1883459Sgblack@eecs.umich.edu        const char *msg_type, sc_severity severity, sc_actions actions)
1893459Sgblack@eecs.umich.edu{
1903459Sgblack@eecs.umich.edu    ReportCatInfo &info = catForSeverityAndMsgType[
1913459Sgblack@eecs.umich.edu        std::make_pair(std::string(msg_type), severity)];
1923459Sgblack@eecs.umich.edu    sc_actions previous = info.actions;
1933459Sgblack@eecs.umich.edu    info.actions = actions;
1943459Sgblack@eecs.umich.edu    return previous;
1953459Sgblack@eecs.umich.edu}
1963459Sgblack@eecs.umich.edu
1973459Sgblack@eecs.umich.eduint
1983459Sgblack@eecs.umich.edusc_report_handler::stop_after(sc_severity severity, int limit)
1993459Sgblack@eecs.umich.edu{
2003459Sgblack@eecs.umich.edu    ReportCatInfo &info = catForSeverity[severity];
2013459Sgblack@eecs.umich.edu    int previous = info.limit;
2023459Sgblack@eecs.umich.edu    info.limit = limit;
2033459Sgblack@eecs.umich.edu    return previous;
2043459Sgblack@eecs.umich.edu}
2053459Sgblack@eecs.umich.edu
2063459Sgblack@eecs.umich.eduint
2072SN/Asc_report_handler::stop_after(const char *msg_type, int limit)
2083459Sgblack@eecs.umich.edu{
2093459Sgblack@eecs.umich.edu    ReportCatInfo &info = catForMsgType[msg_type];
2103459Sgblack@eecs.umich.edu    int previous = info.limit;
2113459Sgblack@eecs.umich.edu    info.limit = limit;
2123459Sgblack@eecs.umich.edu    return previous;
2133459Sgblack@eecs.umich.edu}
2143459Sgblack@eecs.umich.edu
2153459Sgblack@eecs.umich.eduint
2163459Sgblack@eecs.umich.edusc_report_handler::stop_after(
2173459Sgblack@eecs.umich.edu        const char *msg_type, sc_severity severity, int limit)
2183459Sgblack@eecs.umich.edu{
2193459Sgblack@eecs.umich.edu    ReportCatInfo &info = catForSeverityAndMsgType[
2203459Sgblack@eecs.umich.edu        std::make_pair(std::string(msg_type), severity)];
2213459Sgblack@eecs.umich.edu    int previous = info.limit;
2223459Sgblack@eecs.umich.edu    info.limit = limit;
2233459Sgblack@eecs.umich.edu    return previous;
2243459Sgblack@eecs.umich.edu}
2252SN/A
2262SN/Aint
2272SN/Asc_report_handler::get_count(sc_severity severity)
2282SN/A{
2293459Sgblack@eecs.umich.edu    return catForSeverity[severity].count;
230597SN/A}
2312680Sktlim@umich.edu
232597SN/Aint
233597SN/Asc_report_handler::get_count(const char *msg_type)
2343459Sgblack@eecs.umich.edu{
2352SN/A    return catForMsgType[msg_type].count;
2362SN/A}
2372SN/A
2383459Sgblack@eecs.umich.eduint
2393459Sgblack@eecs.umich.edusc_report_handler::get_count(const char *msg_type, sc_severity severity)
2403459Sgblack@eecs.umich.edu{
2413459Sgblack@eecs.umich.edu    return catForSeverityAndMsgType[
2423459Sgblack@eecs.umich.edu        std::make_pair(std::string(msg_type), severity)].count;
2432SN/A}
2442SN/A
2452SN/Aint
2463459Sgblack@eecs.umich.edusc_report_handler::set_verbosity_level(int vl)
2472SN/A{
2485004Sgblack@eecs.umich.edu    int previous = verbosityLevel;
2495004Sgblack@eecs.umich.edu    verbosityLevel = vl;
2502SN/A    return previous;
2515004Sgblack@eecs.umich.edu}
2525004Sgblack@eecs.umich.edu
2535004Sgblack@eecs.umich.eduint
2545004Sgblack@eecs.umich.edusc_report_handler::get_verbosity_level()
2555004Sgblack@eecs.umich.edu{
2565004Sgblack@eecs.umich.edu    return verbosityLevel;
2575004Sgblack@eecs.umich.edu}
2582SN/A
2592SN/A
2602SN/Asc_actions
2612SN/Asc_report_handler::suppress(sc_actions actions)
2623459Sgblack@eecs.umich.edu{
2633459Sgblack@eecs.umich.edu    sc_actions previous = suppressedActions;
2643459Sgblack@eecs.umich.edu    suppressedActions = actions;
2653459Sgblack@eecs.umich.edu    return previous;
2663459Sgblack@eecs.umich.edu}
2673459Sgblack@eecs.umich.edu
2683459Sgblack@eecs.umich.edusc_actions
2693459Sgblack@eecs.umich.edusc_report_handler::suppress()
2703459Sgblack@eecs.umich.edu{
2713468Sgblack@eecs.umich.edu    return suppress(SC_UNSPECIFIED);
2722SN/A}
2732SN/A
2742SN/Asc_actions
2752SN/Asc_report_handler::force(sc_actions actions)
2763468Sgblack@eecs.umich.edu{
2772SN/A    sc_actions previous = forcedActions;
2782SN/A    forcedActions = actions;
2792SN/A    return previous;
2802SN/A}
2812SN/A
2822SN/Asc_actions
2832SN/Asc_report_handler::force()
2842SN/A{
2852SN/A    return force(SC_UNSPECIFIED);
2862SN/A}
2872SN/A
2883468Sgblack@eecs.umich.edu
2892680Sktlim@umich.edusc_actions
2902SN/Asc_report_handler::set_catch_actions(sc_actions actions)
291710SN/A{
2922SN/A    sc_actions previous = catchActions;
2932680Sktlim@umich.edu    catchActions = actions;
2943468Sgblack@eecs.umich.edu    return previous;
2952SN/A}
2962SN/A
2973459Sgblack@eecs.umich.edusc_actions
2983459Sgblack@eecs.umich.edusc_report_handler::get_catch_actions()
2993459Sgblack@eecs.umich.edu{
3003459Sgblack@eecs.umich.edu    return catchActions;
3013459Sgblack@eecs.umich.edu}
3023459Sgblack@eecs.umich.edu
3033459Sgblack@eecs.umich.edu
3043459Sgblack@eecs.umich.eduvoid
3053459Sgblack@eecs.umich.edusc_report_handler::set_handler(sc_report_handler_proc proc)
3063459Sgblack@eecs.umich.edu{
3073459Sgblack@eecs.umich.edu    reportHandlerProc = proc;
3083459Sgblack@eecs.umich.edu}
3093459Sgblack@eecs.umich.edu
3103459Sgblack@eecs.umich.eduvoid
3113459Sgblack@eecs.umich.edusc_report_handler::default_handler(
3123459Sgblack@eecs.umich.edu        const sc_report &report, const sc_actions &actions)
3133459Sgblack@eecs.umich.edu{
3143459Sgblack@eecs.umich.edu    if (actions & SC_DISPLAY)
3153459Sgblack@eecs.umich.edu        cprintf("\n%s\n", sc_report_compose_message(report));
3163459Sgblack@eecs.umich.edu
3173459Sgblack@eecs.umich.edu    if ((actions & SC_LOG) && logFile) {
3183459Sgblack@eecs.umich.edu        ccprintf(*logFile, "%s: %s\n", report.get_time().to_string(),
3193459Sgblack@eecs.umich.edu                 sc_report_compose_message(report));
3203459Sgblack@eecs.umich.edu    }
3213459Sgblack@eecs.umich.edu    if (actions & SC_STOP) {
3223459Sgblack@eecs.umich.edu        sc_stop_here(report.get_msg_type(), report.get_severity());
3233459Sgblack@eecs.umich.edu        sc_stop();
3242SN/A    }
3252SN/A    if (actions & SC_INTERRUPT)
3262SN/A        sc_interrupt_here(report.get_msg_type(), report.get_severity());
3272SN/A    if (actions & SC_ABORT)
3283459Sgblack@eecs.umich.edu        sc_abort();
329596SN/A    if (actions & SC_THROW) {
330596SN/A        ::sc_gem5::Process *current = ::sc_gem5::scheduler.current();
331596SN/A        if (current)
332596SN/A            current->isUnwinding(false);
333596SN/A        throw report;
334596SN/A    }
3353459Sgblack@eecs.umich.edu}
336596SN/A
337596SN/Asc_actions
338596SN/Asc_report_handler::get_new_action_id()
339596SN/A{
340596SN/A    maxAction = maxAction << 1;
341596SN/A    return maxAction;
3423459Sgblack@eecs.umich.edu}
3432SN/A
344710SN/Asc_report_handler_proc
3452SN/Asc_report_handler::get_handler()
3464997Sgblack@eecs.umich.edu{
3472680Sktlim@umich.edu    return reportHandlerProc;
3482680Sktlim@umich.edu}
3494997Sgblack@eecs.umich.edu
3502SN/Asc_report *
3512SN/Asc_report_handler::get_cached_report()
3523459Sgblack@eecs.umich.edu{
3532SN/A    ::sc_gem5::Process *current = ::sc_gem5::scheduler.current();
3542SN/A    if (current)
3552SN/A        return current->lastReport();
3562SN/A    return globalReportCache.get();
3573459Sgblack@eecs.umich.edu}
3582SN/A
3592SN/Avoid
3602SN/Asc_report_handler::clear_cached_report()
3612SN/A{
3623459Sgblack@eecs.umich.edu    ::sc_gem5::Process *current = ::sc_gem5::scheduler.current();
3633459Sgblack@eecs.umich.edu    if (current) {
3642SN/A        current->lastReport(nullptr);
3652SN/A    } else {
3662SN/A        globalReportCache = nullptr;
3672SN/A    }
3683459Sgblack@eecs.umich.edu}
3692SN/A
3702SN/Abool
3712SN/Asc_report_handler::set_log_file_name(const char *new_name)
3722SN/A{
3732SN/A    if (!new_name) {
3742SN/A        logFile = nullptr;
3752SN/A        logFileName = nullptr;
3764997Sgblack@eecs.umich.edu        return false;
3772680Sktlim@umich.edu    } else {
3782680Sktlim@umich.edu        if (logFileName)
3794997Sgblack@eecs.umich.edu            return false;
3802SN/A        logFileName = std::unique_ptr<std::string>(new std::string(new_name));
3812SN/A        logFile = std::unique_ptr<std::ofstream>(new std::ofstream(new_name));
3823459Sgblack@eecs.umich.edu        return true;
3834997Sgblack@eecs.umich.edu    }
3842330SN/A}
3852680Sktlim@umich.edu
3863548Sgblack@eecs.umich.educonst char *
3872341SN/Asc_report_handler::get_log_file_name()
3882680Sktlim@umich.edu{
3893548Sgblack@eecs.umich.edu    if (!logFileName)
3902330SN/A        return nullptr;
3914997Sgblack@eecs.umich.edu    else
3922SN/A        return logFileName->c_str();
3933459Sgblack@eecs.umich.edu}
3942SN/A
3952SN/Avoid
3962SN/Asc_interrupt_here(const char *msg_type, sc_severity)
3972SN/A{
3983459Sgblack@eecs.umich.edu    // Purposefully empty, for setting breakpoints supposedly.
3992SN/A}
4002SN/A
4012SN/Avoid
4022SN/Asc_stop_here(const char *msg_type, sc_severity)
4033459Sgblack@eecs.umich.edu{
4042SN/A    // Purposefully empty, for setting breakpoints supposedly.
4052SN/A}
4062SN/A
4072SN/Aconst std::string
4083459Sgblack@eecs.umich.edusc_report_compose_message(const sc_report &report)
4092SN/A{
4102SN/A    std::ostringstream str;
4112SN/A
4122SN/A    const char *sevName = severityNames[report.get_severity()];
4133459Sgblack@eecs.umich.edu    int id = report.get_id();
4142SN/A
4152SN/A    str << sevName << ": ";
4162SN/A    if (id >= 0) {
4173459Sgblack@eecs.umich.edu        ccprintf(str, "(%c%d) ", sevName[0], id);
4183459Sgblack@eecs.umich.edu    }
4192SN/A    str << report.get_msg_type();
4202SN/A
4212SN/A    const char *msg = report.get_msg();
4223459Sgblack@eecs.umich.edu    if (msg && msg[0])
4232SN/A        str << ": " << msg;
4242SN/A
4252SN/A    if (report.get_severity() > SC_INFO) {
4263459Sgblack@eecs.umich.edu        ccprintf(str, "\nIn file: %s:%d", report.get_file_name(),
4273459Sgblack@eecs.umich.edu                 report.get_line_number());
4282SN/A
4292SN/A        ::sc_gem5::Process *current = ::sc_gem5::scheduler.current();
4302SN/A        const char *name = report.get_process_name();
4313459Sgblack@eecs.umich.edu        if (current && sc_is_running() && name) {
4322SN/A            ccprintf(str, "\nIn process: %s @ %s", name,
4332SN/A                    report.get_time().to_string());
4342SN/A        }
4353459Sgblack@eecs.umich.edu    }
4362SN/A
4372SN/A    return str.str();
4382SN/A}
4393459Sgblack@eecs.umich.edu
4403459Sgblack@eecs.umich.edubool
4412SN/Asc_report_close_default_log()
4422SN/A{
4432SN/A    if (logFile) {
4442SN/A        logFile = nullptr;
4453459Sgblack@eecs.umich.edu        logFileName = nullptr;
4463459Sgblack@eecs.umich.edu        return false;
4473459Sgblack@eecs.umich.edu    }
4483459Sgblack@eecs.umich.edu    return true;
4493459Sgblack@eecs.umich.edu}
4502SN/A
4513468Sgblack@eecs.umich.edu} // namespace sc_core
4522SN/A