file name: clock_sw.hpp, clock_sw.cpp
classification: pure simulation
contents: class CSoftwareClock
derived from: class CClock
friends: function MakeSystemSnapshot()
use: provides a class for simulating the UTCSU in pure simulation
global items used by the functions:
const INT32
DutyEnabled: enable bit in the DUTYL registers
enum EAmortizationTypes:
the current stage in the amortization phase. Register STARTAMORT is used
for storing the stage and contains one of these values:
struct SInternalRegisters:
Contains those internal registers of the UTCSU that are needed for storing
temporary results.
const double
TwoPow16:
const double
TwoPow21:
const double
TwoPow29:
const double
TwoPow30:
const double
TwoPow32: Some powers of two that are needed for internal computations.
local (static) functions of the implementation file:
double DutyToSeconds
(INT32 dutyh, INT32 dutyl): Converts the contents of the duty timer
registers to seconds.
EClockInterrupt
GetInterruptType (INT8 interruptBit): Returns the interrupt type (INTA,
INTN, INTT) of the bit. The interruptBit is in the range of 0..63.
If the interrupt bit is not used by the UTCSU, an assert fails.
double GetTime
(const CNtpTime& cycles, double frequency): Returns the global
time that corresponds to cycles clock cycles of a clock with the
frequency frequency.
void PrintHex
(const char *str, INT32 reg): Prints the value of str as
a string with a minimum width of 14 characters (left justified), followed
by the hexadecimal value of reg and a newline. The function is
used by DumpRegisters() to print the contents of the UTCSU registers.
Note: the function is only available if macro NDEBUG
is not defined.
template implementation (clock_sw.cpp):
CClockTemplate::NewClock
(double frequency, SINT32 nodeID, int area): Returns a new object
of the software clock. If frequency is not positive, an assert
fails.
member types and variables:
enum EDutyTimer:
The bits of the implemented duty timers (APPDUTY, and the duty timers A
and B
of all SSUs) in the interrupt and status registers.
int area_:
The area of the application. It is necessary for obtaining the interrupt
vector.
default value: parameter area of the ctor
double
assocSimTime_: The simulation time of the last clock update.
default and reset value: the current simulation time
double
fOsc_: The real oscillator frequency (as opposed to the ideal frequency
stored in CClock). fOsc can be manipulated
through parameter ClockDrift.
default value: the ideal frequency which is returned by GetFrequency()
EGpsUnit
gpu_: The GPU that has last called CaptureTime().
default and reset value: EGpsUnitCount
SInternalRegisters
*internals_: The structure contains all internal clock registers that
are needed for keeping track of the state of the UTCSU.
reset values: all members are set to 0, overflow is set to
False
CInterruptList
*listOfInterrupts_: Stores the list of all interrupts that were created
(ie., enabled in UTCINTEN).
SINT32
nodeID_: The nodeID of the application (it is used as process ID of
the interrupt processes).
default value: parameter nodeID of the ctor
member functions:
CSoftwareClock
(double frequency, SINT32 nodeID, int area): Creates internals
and the inherited members utscuRead and utcsuWrite, sets
nodeID and area to their default values and calls Init().
If frequency is not positive, an assert fails.
The function sets registers UTCINTEN, UTCCONF, UTCSTAT and UTCINTSTAT
to zero and register IDENTIFICATION to 0x49435410 ("ICT"+0x10). Please
note that the clock is not reset, so apart from the above-mentioned registers,
all registers are in an unknown state.
Note: in hardware-based simulation, the UTCSUs on all nodes
are reset by the LANCE before SimUTC is started. So if a CSA is deleted
and then created anew, the clock is not reset and the CSA has to set all
registers that it needs. In consequence, in pure simulation the clock is
not reset at all, thus forcing the users of the clock to manually set all
members that they need and enforcing an initialization code that will also
work in hardware-based simulation.
virtual
~CSoftwareClock (): Deletes the dynamic members that were created
in the constructor and calls Dispose(). If the UTCINTEN registers
are not zero (that is, not all interrupts that were enabled during the
life of the CSA were disabled upon its destruction), an assert fails.
void CaptureTime(EGpsUnit
gpu): The clock is updated, then the values of the internal macro-
and timestamp are copied into the MSGPS and TSGPS registers of the specified
GPU. Internal member gpu_ is set to gpu. Bit 31 in MSGPS
is set to 0 to indicate that the GPS receiver is healthy (this is always
the case in this version of SimUTC). If gpu is greater or equal
to EGpsUnitCount, an assert fails.
void ClearSignal
(INT8 signalBit): Sets bit signalBit in the appropriate UTCSTAT
register to 0. The other bits are not modified. If signalBit is
greater than 63, an assert fails.
CClockInterrupt
*CreateInterrupt (INT8 interruptBit): The function first searches
for an existing interrupt in the list of interrupts. If an interrupt process
is found, it is returned. Otherwise, interruptBit is checked.
If it is a GPS1PPS interrupt, a GPS interrupt process is created. If it
is an interrupt of duty timer B on SSU1, an interrupt process of type CDutyB1Interrupt
is created. Otherwise, a normal clock interrupt process is created. In
any case, GetClockIntvec() is used to obtain the interrupt base
vector, to which the type of the interrupt bit (enum INTA, INTN, INTT in
interupt.hpp) is ored. Then, the interrupt
is put into the interrupt list, its status register (read register UTCINTSTAT1
for bits 0..31, UTCINTSTAT2 for bits 32..63) is stored using CClockInterrupt::SetStatusRegister(),
and according to the status of interruptBit in write register
UTCINTEN1(2) the process is enabled or disabled. In any case, CClockInterrupt::SetPendingBit()
is used to set the number of the status bit corresponding to the interrupt.
The function returns the pointer to the new interrupt. If interruptBit
is greater than 63, an assert fails.
void DescheduleInterrupt
(INT8 interruptBit): The function searches for the interrupt in the
list of interrupts, and if it is found, CClockInterrupt::CancelInterrupt()
is called to remove the interrupt process from the scheduler queue.
virtual
void DisableInterrupt (INT8 interruptBit): Searches for the interrupt
process in the list of interrupts. If the process is found, its Disable()
function is called.
virtual
void Dispose(): Deletes the interrupt list, thus cancelling all interrupts
stored in the list. The function must not be called twice in a row!
virtual
void DumpRegisters(): Prints the contents of all registers of the
UTCSU to cout. In the header, the function prints the current simulation
time (split into an integer and a fractional part to avoid rounding errors
because of limited output precision), the difference between the simulation
time and the current associated time of the clock, and the current clock
time (also split into an integral and a fractional part).
Note: the function is only available if macro NDEBUG
is not defined.
virtual
void EnableInterrupt (INT8 interruptBit): Searches for the interrupt
process in the list of interrupts, and if it was found, its Enable()
function is called.
INT32 GetAccuracy():
The function returns the current accuracy, taken from the INTPBUS. That
means that bits [-8,-23] of internal register ALPHAP are stored in the
lower two bytes of the return value, and bits [-8,-23] of internal register
ALPHAN are stored in the upper two bytes. If the ALPHAP(N) register is
negative, 0 is used instead.
virtual
INT32 GetALPHANGETL(): Updates the clock, reads the internal negative
accuracy into ALPHANGET(L) and the nanofractional part into the upper two
bytes of NALPHAPGET and returns the value of ALPHANGET.
virtual
INT32 GetALPHAPGETL(): Updates the clock, reads the internal positive
accuracy into ALPHAPGET(L) and the nanofractional part into the lower two
bytes of NALPHAPGET and returns the value of ALPHAPGET.
INT32 GetAmortCycles
(const CNtpTime& cycles): The function returns the number of amortization
cycles in the next cycles clock cycles. It returns the minimum
of cycles and the value of internal register AMORTTIMER.
virtual
INT32 GetAMORTTIMEGETL(): Updates the clock, then stores the current
value of the internal register AMORTTIMER in AMORTTIMEGET(L) and returns
that value.
void GetClockCycles
(double delta, CNtpTime& cycles): If delta is not positive,
cycles (both ms and ts) is set to 0. Otherwise,
the real frequency of the clock (which is stored in member fOsc)
is used to compute the number of cycles that occur in delta seconds
(real seconds, as measured with an ideal clock). The result is stored in
cycles.
Note: do not get confused: cycles is of type CNtpTime,
but is no time. It should be seen as a 64 bit register (the us
member is not used).
double
GetCurrentClockValue(): The function returns the current clock value
converted in seconds.
void GetEnvelope
(EBool positive, INT32& alpha, INT16& nalpha): If positive
is True, the function copies the internal register ALPHAP into alpha
and internal register NALPHAP into nalpha. If positive
is False, internal registers ALPHAN and NALPHAN are copied instead.
CGpsInterrupt
*GetGpsInterrupt (EGpsUnit gpu): Returns the GPS interrupt process
of the given GPU. If the process does not exist, it is created. If gpu
is greater or equal to EGpsUnitCount, an assert
fails.
EGpsUnit
GetGpsUnit(): Returns member gpu, which contains the GPS
unit that has last called CaptureTime().
virtual
EBool GetParameter (SParameter& param) const: Returns True if the
parameter could be read. All supported parameters of this class assume
that param is of type SSingleParameter.
EBool GetPolarity
(INT8 bitnumber): Checks the appropriate UTCCONF register (the write
registers are used). If bit bitnumber is set to 1, True is returned.
If it is 0, the function returns False. If bitnumber is greater
than 63, an assert fails.
double
GetRate (INT32 step): The function returns the real clock rate (clock
seconds per second) if step and STEPLOW (the uppermost byte of
write register MSSET) is used. The real clock frequency fOsc is
used to compute the rate.
double
GetRealDelay (double delta): The function returns the global time
(in seconds) that will pass until the clock time delta (in seconds)
has passed. If delta is less or equal to 0, the function returns
0. If delta is positive, the clock is updated. Then, the clock
state is checked to find out which part of the total time delta
the clock is in amortization phase, and which part the clock spends in
pure phase. The clock rates of amortization and pure phase are computed
(using function GetRate()) and the real delay (ie. the delay measured
on a clock with ideal rate) is computed from them and returned.
EBool GetSignal
(INT8 signalBit): The appropriate UTCSTAT register is checked, and
if bit signalBit is set to 1, True is returned. If it is 0, the
function returns False. If signalBit is greater than 63, an assert
fails.
virtual
INT32 GetSTATEPGETL(): Updates the clock, calls GetAccuracy()
and sets STATEPGET(L) to its return value. It returns the new value of
the STATEPGET(L) registers.
virtual
INT32 GetTSGETL(): The function first updates the clock, ie., it computes
the current clock state. Then it latches the NTP registers, the STATEPGET(L)
registers of the accuracy and the ALPHAPGET(L), ALPHANGET(L) and NALPHAPGET
registers of the full accuracy envelopes (all values are taken from the
corresponding internal registers). It returns the value of the latched
TSGET register.
virtual
INT32 GetUTCCONF1(): This is a read-back register of the UTCCONF1
register. The UTCCONF1 of the write structure is simply copied into it,
and its value is returned.
virtual
INT32 GetUTCCONF2(): This is a read-back register of the UTCCONF2
register. The UTCCONF2 register of the write structure is copied into it,
and its value is returned.
virtual
INT32 GetUTCSTAT1(): Updates the clock. If the clock is in amortization
phase, bit SCAMA is set to 1, else it is set to 0. The bit is set here
because the value of the status bit is only important when UTCSTAT1 is
read.
Note: the only other status bit that is currently set is SAPPDUTY.
void HwSnapshot():
The function updates the clock and afterwards stores the internal macrostamp
and timestamp into the read registers MSSNU and TSSNU. The current accuracies
are stored in ACCPSNU. If interrupt IHWSNAP is enabled, an interrupt is
generated at once (ie., the interrupt process is scheduled for the current
time).
virtual
void Init(): creates the interrupt list, sets assocSimTime,
gpu and fOsc to their reset values. The function must
not be called twice in a row!
void ModifiedDutyTimer
(EDutyTimer dutyBit, const CNtpTime& duty): If the duty timer
(duty.ms = DutyHigh, duty.ts = DutyLow) is enabled, the
function creates an interrupt process, sets its schedule time to the clock
time specified by the duty timer, and schedules the process. If the duty
timer is disabled, the function searches the list of interrupts for an
existing process, and if one is found, its schedule time is set to a negative
value (to prevent rescheduling) and the process is descheduled (calling
CClockInterrupt::CancelInterrupt()). Its corresponding status
bit is cleared in UTCSTAT. If the duty timer is enabled and dutyBit
is greater than 63, an assert fails.
virtual
int ReportError (EReportType type, char *file, int line, char *expression):
Calls the global error report function with the additional information
module=Clock and the nodeID and area.
void RescheduleInterrupts
(): The function goes through the interrupt list and checks the status
of all interrupts. If an interrupt is active or scheduled, it is rescheduled
calling ScheduleInterrupt().
Note: rescheduling of interrupts is necessary after the clock
state has been changed. Interrupt processes that were idle anyway will
be ignored. Active interrupt processes must be rescheduled as well, because
they may have been already scheduled for the next interrupt.
void ScheduleInterrupt
(INT8 interruptBit): The function simply searches for the interrupt
in the list of interrupts, and if it is found, it calls ScheduleInterrupt()
with the pointer.
void ScheduleInterrupt
(CClockInterrupt *clockint): The function first calls CClockInterrupt::GetScheduleTime()
to find out the global time at which the interrupt should be scheduled.
If the value returned by the function is negative, the interrupt does not
need scheduling and the function has no effect. If the schedule time is
not negative, GetCurrentClockValue() is used to obtain the current
clock time in seconds, and the interrupt is scheduled according to the
time difference. Since the time difference is given in local time, GetRealDelay()
is used to compute the global delay and the interrupt is scheduled for
that delay. If clockint is NULL, an assert fails.
virtual
void SetALPHAPNSET(INT32 val): Updates the clock, then copies the
new accuracy from the write register ALPHASET into the internal accuracy
ALPHAP(N). The nanofractional part NALPHAP(N) is set to 0x1FFF (it is only
13 bit wide).
virtual
void SetAPPDUTYH(INT32 val): First updates the clock. Then, function
ModifiedDutyTimer() is called with the bitnumber corresponding
to the duty timer in the interrupt registers and with the new value of
the duty timer.
virtual
void SetAPPDUTYL(INT32 val): First updates the clock. Then, function
ModifiedDutyTimer() is called with the bitnumber corresponding
to the duty timer and with the new value of the duty timer.
virtual
void SetDUTYAH (ESSUnit ssu, INT32 val): First updates the clock.
Then, function ModifiedDutyTimer() is called with the bitnumber
corresponding to the duty timer of the given SSU in the interrupt registers
and the new value of the duty timer.
virtual
void SetDUTYAL (ESSUnit ssu, INT32 val): First updates the clock.
Then, function ModifiedDutyTimer() is called with the bitnumber
corresponding to the duty timer of the given SSU in the interrupt registers
and the new value of the duty timer.
virtual
void SetDUTYBH (ESSUnit ssu, INT32 val): First updates the clock.
Then, function ModifiedDutyTimer() is called with the bitnumber
corresponding to the duty timer of the given SSU in the interrupt registers
and the new value of the duty timer.
virtual
void SetDUTYBL (ESSUnit ssu, INT32 val): First updates the clock.
Then, function ModifiedDutyTimer() is called with the bitnumber
corresponding to the duty timer of the given SSU in the interrupt registers
and the new value of the duty timer.
void SetEnvelope
(EBool positive, INT32 alpha, INT16 nalpha): If positive is
True, alpha is stored into internal register ALPHAP and nalpha
is written into internal register NALPHAP. If positive is False,
internal registers ALPHAN and NALPHAN are modified instead. Only 13 bits
of nalpha are used, since NALPHA corresponds to bits [-39,-51].
void SetLowerLimit
(EBool positive): If positive is True, internal registers
ALPHAP and NALPHAP are set to their lower limit (which is 1:0...0). If
positive is False, ALPHAN and NALPHAN are set to that limit instead.
Note: normally, this function should raise an interrupt INTNLALPHAP(N),
because the function is only called if the limit was overstepped. But since
the current version of SimUTC does not need the interrupts, and because
the interrupt should be raised at the exact time the limit is reached,
not some time later when UpdateEnvelopes() happens to notice the
overrun, this interrupt is not implemented.
virtual
void SetMSSET(INT32 val): The function checks the most significant
byte (which contains the STEPLOW value). If it has changed, the clock is
updated (using the old steplow value). Then, the new value is taken over
into the MSSET register, and if STEPLOW has changed, interrupts are rescheduled.
virtual
void SetNTPSET(INT32 val): First updates the clock. Then, the NTP
time values of MSSET, TSSET and USSET are taken over into the internal
registers, and the internal nanostamp is set to 0. Interrupts are rescheduled.
Note: if the new NTP time is less than the old, an interrupt
should be raised. This is not implemented.
void SetOverflow
(int overflow): If overflow is not 0, the internal boolean
variable overflow is set to True and the uppermost byte of the
internal macrostamp is set to 0. If overflow is 0, internal variable
overflow is set to False.
virtual
EBool SetParameter (const SParameter& param): Returns True if the
parameter could be set. All supported parameters of this class assume that
param is of type SSingleParameter.
void SetSignal
(INT8 signalBit): The function first searches for an interrupt that
is associated with this bit. If an interrupt was found in the list of interrupts,
and if that interrupt is either scheduled or active, the function has no
effect. If no interrupt process was found, or if the process is idle, the
signal is set in the appropriate UTCSTAT register. If signalBit
is greater than 63, an assert fails.
virtual
void SetSTARTAMORT(INT32 val): Updates the clock. Afterwards, several
write registers are taken over into the internal registers: AMORTTIMESET
into the internal AMORTTIMER, STEPPURE into STEPPUREACT, LAMBDAP(N)PURE
into LAMBDAP(N)PUREACT. If the AMORTTIMER is greater than 0, write register
STARTAMORT is set to the enum BeginAmortization to signify the
start of the amortization phase. If AMORTTIMER is 0, STARTAMORT is set
to NoAmortization.
virtual
void SetSTEPAMORT(INT32 val): Updates the clock, then takes over the
new STEPAMORT value. If the clock is currently in amortization phase (you
should not change the STEPAMORT value during amortization), an error is
reported (because most likely that was not intended) and interrupts are
rescheduled.
virtual
void SetSWRESET(INT32 val): Sets all UTCSU registers, whether internal
or of the read/write structures, to 0. Only write register BOUNDP is set
to 0xFFFFFFFF (all bits are 1) and read register IDENTIFICATION is set
to 0x49435410 ("ICT"+0x10). The internal overflow variable is
set to False, and assocSimTime is set to the current simulation
time. All interrupt processes are disabled, and all except the GPS interrupts
are descheduled as well.
virtual
void SetSWSNAP(INT32 val): calls function SwSnapshot() to
capture all dynamic registers.
void SetUpperLimit
(EBool positive): If positive is True, internal registers
ALPHAP and NALPHAP are set to their upper limit (which is 0:1...1). If
positive is False, ALPHAN and NALPHAN are set to that limit instead.
Note: since the nanofractional part of the accuracy is only
13 bits wide, NALPHAP(N) is set to 0x1FFF.
Note: normally, this function should raise an interrupt INTPLALPHAP(N),
because the function is only called if the limit was overstepped. But since
the current version of SimUTC does not need the interrupts, and because
the interrupt should be raised at the exact time the limit is reached,
not some time later when UpdateEnvelopes() happens to notice the
overrun, this interrupt is not implemented.
virtual
void SetUTCINTCLEAR1(INT32 val): Every bit that is 1 in val
is set to 0 in read register UTCINTSTAT1.
virtual
void SetUTCINTCLEAR2(INT32 val): Every bit that is 1 in val
is set to 0 in read register UTCINTSTAT2.
virtual
void SetUTCINTEN1(INT32 val): First updates the clock. Then each bit
of val is checked, and if it is set to 1, the interrupt process
corresponding to that bit is enabled and scheduled, whereas if it is 0,
the interrupt is disabled and descheduled.
virtual
void SetUTCINTEN2(INT32 val): First updates the clock. Again, each
bit of val is checked. The first three bits are GPS1PPS interrupts,
and if one of these bits is set to 1, the corresponding GPS interrupt is
enabled. If the bit is 0, the interrupt is disabled but not descheduled,
so the interrupt process still gets active every second, but it does not
invoke the ISR (the process needs to stay scheduled, because upon activation
it has to schedule itself for the next second). The other bits and their
interrupts are treated as described for SetUTCINTEN1().
void SwSnapshot():
The function simply calls GetTSGETL() to capture all dynamic registers.
void Update():
The function computes the current clock state and updates the clock registers.
First, the function compares assocSimTime to the current global
time. If assocSimTime is greater or equal to the global time,
no update is necessary and the function returns at once. Otherwise, the
function computes the number of (full) clock cycles that must have occurred
since the last update. If it is zero, the function returns at once (only
full cycles can be updated).
Otherwise, if the clock is in amortization phase (AMORTTIMER is not
0), the number of amortization cycles since the last update is computed,
and the clock state and accuracy envelopes are updated (using the amortization
step values) calling UpdateNtp() and UpdateEnvelopes().
If all amortization cycles were used up, write register STARTAMORT is set
to enum constant NoAmortization, else it is set to MiddleOfAmortization.
The cycles used for amortization are subtracted from the total number of
cycles. If any cycles remain, the clock state and accuracy envelopes are
modified again using the step values for pure phase. UpdateEvelopes()
and UpdateNtp() are used to update the registers. In any case,
the updated time (which is computed through local function GetTime())
is added to assocSimTime, and the clock registers are all up to
date when the function returns.
void UpdateEnvelopes
(EBool pure, const CNtpTime& cycles): The function updates the
internal accuracy envelopes stored in ALPHAP(N) (bits S:[-8,-38]) and NALPHAP(N)
(bits [-39,-51]). If pure is True, internal register LAMBDAP(N)PUREACT
(bits S:[-37,-51]) is added to ALPHAP(N) and NALPHAP(N) for cycles
cycles. If pure is False, write register LAMBDAP(N)AMORT (bits
S:[-37,-51]) is used instead, and if STARTAMORT is equal to BeginAmortization,
the first cycle is used to realign the accuracy envelopes by adding write
register STATEP(N)SET (bits S:[-8,-38]). During the remaining cycles the
envelopes are updated according to LAMBDAP(N)AMORT. If the update of an
envelope (either the positive or negative one) results in an overrun or
underflow of the register, the envelope is set to its upper limit (using
SetUpperLimit()) or its lower limit (through function SetLowerLimit()).
void UpdateNtp
(INT32 step, const CNtpTime& cycles): This function updates the
NTP registers of the clock. It adds the value of step (bits [-20,-51])
and STEPLOW for cycles clock cycles to the NTPTIME (which is the
complete 91 bit time value in the range [+31,-59]; it is split into the
macrostamp (MS) [+31,+8], TS [+7,-24], US [-25,-56] and the NS [-57,-59]).
The uppermost byte of write register MSSET is taken as the STEPLOW portion
(bits [-52,-59]) of step. After the new NTPTIME was computed,
SetOverflow() is called to set the internal overflow
flag in case of an overflow, or to clear it if no overflow has occured.
simulated UTCSU registers:
The UTCSU contains many registers. This is a list of all of them, using
32 bit access (the first name in a line is the name of the 32 bit register
in the UTCSU register structure). Those that are not simulated by
the software clock are marked with a minus sign (-), those that display
a slightly different behaviour are marked with an asteriks (*). The results
of accessing these registers are described below. Accessing the other registers
yields the same results as accessing the real UTCSU registers.
|
|
MSGET/CS
TSGETL USGET TSGET NSGET AMORTTIMEGETL AMORTTIME |
MSSET/STEPLOW
TSSET USSET NTPSET STEPAMORT STEPPURE AMORTTIMESET STARTAMORT |
STATEPGETL/STATENGETL
STATEPGET/STATENGET ALPHAPGETL ALPHANGETL ALPHAPGET ALPHANGET NALPHAPGET/NALPHANGET |
LAMBDAPPURE/LAMBDAPAMORT
LAMBDANPURE/LAMBDANAMORT STATEPSET STATENSET BOUNDP/BOUNDN ALPHASET ALPHAPNSET |
SWRESET | |
IDENTIFICATION
UTCSTAT1 UTCSTAT2 UTCCONF1 UTCCONF2 UTCINTSTAT1 UTCINTSTAT2 |
UTCCONF1
UTCCONF2 UTCINTEN1 UTCINTEN2 UTCINTCLEAR1 UTCINTCLEAR2 |
MSSIG (-)
TSSIG (-) ACCSIG (-) MSSUM (-) TSSUM (-) ACCSUM (-) PUREPHASE (-) |
TESTSEL (-)
TESTGATE (-) |
MSSNU
TSSNU ACCPSNU/ACCNSNU |
SWSNAP (*)
DUTYH (-) DUTYL/E (-) |
MSAPP (-)
TSAPP (-) ACCPAPP/ACCNAPP (-) MSAPPX (-) TSAPPX (-) ACCPAPPX/ACCNAPPX (-) |
APPDUTYH
APPDUTYL APPSEL (-) APPCLEAR (-) |
MSGPS
TSGPS |
|
MSRCV (-)
TSRCV (-) MSXMT (-) TSXMT (-) ACCPXMT/ACCNXMT (-) ACCNPNPLXMT (-) ACCNPNPHXMT (-) |
DUTYAH
DUTYAL DUTYBH DUTYBL |