isa.cc revision 11793
12SN/A/* 21762SN/A * Copyright (c) 2009 The Regents of The University of Michigan 32SN/A * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Gabe Black 292665Ssaidi@eecs.umich.edu */ 302SN/A 312SN/A#include "arch/x86/isa.hh" 322SN/A 332SN/A#include "arch/x86/decoder.hh" 342SN/A#include "arch/x86/tlb.hh" 352SN/A#include "cpu/base.hh" 361354SN/A#include "cpu/thread_context.hh" 371354SN/A#include "params/X86ISA.hh" 382SN/A#include "sim/serialize.hh" 392SN/A 405501Snate@binkert.orgnamespace X86ISA 415546Snate@binkert.org{ 427004Snate@binkert.org 432SN/Avoid 442SN/AISA::updateHandyM5Reg(Efer efer, CR0 cr0, 4556SN/A SegAttr csAttr, SegAttr ssAttr, RFLAGS rflags, 465769Snate@binkert.org ThreadContext *tc) 472361SN/A{ 481354SN/A HandyM5Reg m5reg = 0; 496216Snate@binkert.org if (efer.lma) { 5056SN/A m5reg.mode = LongMode; 512SN/A if (csAttr.longMode) 525543Ssaidi@eecs.umich.edu m5reg.submode = SixtyFourBitMode; 532SN/A else 541354SN/A m5reg.submode = CompatabilityMode; 551354SN/A } else { 562SN/A m5reg.mode = LegacyMode; 572SN/A if (cr0.pe) { 582SN/A if (rflags.vm) 592SN/A m5reg.submode = Virtual8086Mode; 605501Snate@binkert.org else 615501Snate@binkert.org m5reg.submode = ProtectedMode; 622SN/A } else { 63395SN/A m5reg.submode = RealMode; 642SN/A } 652SN/A } 662SN/A m5reg.cpl = csAttr.dpl; 675769Snate@binkert.org m5reg.paging = cr0.pg; 685769Snate@binkert.org m5reg.prot = cr0.pe; 695769Snate@binkert.org 705769Snate@binkert.org // Compute the default and alternate operand size. 717059Snate@binkert.org if (m5reg.submode == SixtyFourBitMode || csAttr.defaultSize) { 727059Snate@binkert.org m5reg.defOp = 2; 737059Snate@binkert.org m5reg.altOp = 1; 747059Snate@binkert.org } else { 757059Snate@binkert.org m5reg.defOp = 1; 767059Snate@binkert.org m5reg.altOp = 2; 777059Snate@binkert.org } 787059Snate@binkert.org 797059Snate@binkert.org // Compute the default and alternate address size. 807059Snate@binkert.org if (m5reg.submode == SixtyFourBitMode) { 817059Snate@binkert.org m5reg.defAddr = 3; 827059Snate@binkert.org m5reg.altAddr = 2; 837059Snate@binkert.org } else if (csAttr.defaultSize) { 847059Snate@binkert.org m5reg.defAddr = 2; 857059Snate@binkert.org m5reg.altAddr = 1; 867059Snate@binkert.org } else { 875769Snate@binkert.org m5reg.defAddr = 1; 887058Snate@binkert.org m5reg.altAddr = 2; 897058Snate@binkert.org } 907058Snate@binkert.org 912SN/A // Compute the stack size 925502Snate@binkert.org if (m5reg.submode == SixtyFourBitMode) { 935502Snate@binkert.org m5reg.stack = 3; 945502Snate@binkert.org } else if (ssAttr.defaultSize) { 955503Snate@binkert.org m5reg.stack = 2; 965503Snate@binkert.org } else { 975502Snate@binkert.org m5reg.stack = 1; 985502Snate@binkert.org } 995502Snate@binkert.org 1005502Snate@binkert.org regVal[MISCREG_M5_REG] = m5reg; 1015502Snate@binkert.org if (tc) 1025502Snate@binkert.org tc->getDecoderPtr()->setM5Reg(m5reg); 1035502Snate@binkert.org} 1045602Snate@binkert.org 1055602Snate@binkert.orgvoid 1065501Snate@binkert.orgISA::clear() 1075543Ssaidi@eecs.umich.edu{ 1087058Snate@binkert.org // Blank everything. 0 might not be an appropriate value for some things, 1095769Snate@binkert.org // but it is for most. 1104016Sstever@eecs.umich.edu memset(regVal, 0, NumMiscRegs * sizeof(MiscReg)); 1114016Sstever@eecs.umich.edu regVal[MISCREG_DR6] = (mask(8) << 4) | (mask(16) << 16); 1124016Sstever@eecs.umich.edu regVal[MISCREG_DR7] = 1 << 10; 1134016Sstever@eecs.umich.edu} 1144016Sstever@eecs.umich.edu 1154016Sstever@eecs.umich.eduISA::ISA(Params *p) 1164016Sstever@eecs.umich.edu : SimObject(p) 1174016Sstever@eecs.umich.edu{ 1184016Sstever@eecs.umich.edu clear(); 1195501Snate@binkert.org} 1205605Snate@binkert.org 1215605Snate@binkert.orgconst X86ISAParams * 1225605Snate@binkert.orgISA::params() const 1235605Snate@binkert.org{ 1245501Snate@binkert.org return dynamic_cast<const Params *>(_params); 1254016Sstever@eecs.umich.edu} 1265577SSteve.Reinhardt@amd.com 1275501Snate@binkert.orgMiscReg 1285501Snate@binkert.orgISA::readMiscRegNoEffect(int miscReg) const 1295501Snate@binkert.org{ 1305502Snate@binkert.org // Make sure we're not dealing with an illegal control register. 1315502Snate@binkert.org // Instructions should filter out these indexes, and nothing else should 1325605Snate@binkert.org // attempt to read them directly. 1335502Snate@binkert.org assert(isValidMiscReg(miscReg)); 1345502Snate@binkert.org 1355605Snate@binkert.org return regVal[miscReg]; 1365605Snate@binkert.org} 1375605Snate@binkert.org 1385577SSteve.Reinhardt@amd.comMiscReg 1395502Snate@binkert.orgISA::readMiscReg(int miscReg, ThreadContext * tc) 1405502Snate@binkert.org{ 1415502Snate@binkert.org if (miscReg == MISCREG_TSC) { 1425502Snate@binkert.org return regVal[MISCREG_TSC] + tc->getCpuPtr()->curCycle(); 1432SN/A } 1445769Snate@binkert.org 1455769Snate@binkert.org if (miscReg == MISCREG_FSW) { 1465769Snate@binkert.org MiscReg fsw = regVal[MISCREG_FSW]; 1475769Snate@binkert.org MiscReg top = regVal[MISCREG_X87_TOP]; 1485769Snate@binkert.org return (fsw & (~(7ULL << 11))) + (top << 11); 1495769Snate@binkert.org } 1502SN/A 1515769Snate@binkert.org return readMiscRegNoEffect(miscReg); 1525769Snate@binkert.org} 1535769Snate@binkert.org 1547059Snate@binkert.orgvoid 1555769Snate@binkert.orgISA::setMiscRegNoEffect(int miscReg, MiscReg val) 1565769Snate@binkert.org{ 1572SN/A // Make sure we're not dealing with an illegal control register. 1585769Snate@binkert.org // Instructions should filter out these indexes, and nothing else should 1595769Snate@binkert.org // attempt to write to them directly. 1605769Snate@binkert.org assert(isValidMiscReg(miscReg)); 1615769Snate@binkert.org 1625769Snate@binkert.org HandyM5Reg m5Reg = readMiscRegNoEffect(MISCREG_M5_REG); 1635769Snate@binkert.org switch (miscReg) { 1645769Snate@binkert.org case MISCREG_FSW: 1655769Snate@binkert.org val &= (1ULL << 16) - 1; 1665769Snate@binkert.org regVal[miscReg] = val; 1675769Snate@binkert.org miscReg = MISCREG_X87_TOP; 1685769Snate@binkert.org val <<= 11; 1695769Snate@binkert.org case MISCREG_X87_TOP: 1705769Snate@binkert.org val &= (1ULL << 3) - 1; 1715769Snate@binkert.org break; 1725769Snate@binkert.org case MISCREG_FTW: 1735769Snate@binkert.org val &= (1ULL << 8) - 1; 1745769Snate@binkert.org break; 1755769Snate@binkert.org case MISCREG_FCW: 1765769Snate@binkert.org case MISCREG_FOP: 1775769Snate@binkert.org val &= (1ULL << 16) - 1; 1785769Snate@binkert.org break; 1795769Snate@binkert.org case MISCREG_MXCSR: 1805769Snate@binkert.org val &= (1ULL << 32) - 1; 1815769Snate@binkert.org break; 1825769Snate@binkert.org case MISCREG_FISEG: 1835769Snate@binkert.org case MISCREG_FOSEG: 1845769Snate@binkert.org if (m5Reg.submode != SixtyFourBitMode) 1855769Snate@binkert.org val &= (1ULL << 16) - 1; 1865501Snate@binkert.org break; 1875543Ssaidi@eecs.umich.edu case MISCREG_FIOFF: 1882SN/A case MISCREG_FOOFF: 1892SN/A if (m5Reg.submode != SixtyFourBitMode) 190396SN/A val &= (1ULL << 32) - 1; 191396SN/A break; 192396SN/A default: 193396SN/A break; 1945501Snate@binkert.org } 1957058Snate@binkert.org 1967058Snate@binkert.org regVal[miscReg] = val; 1973329Sstever@eecs.umich.edu} 1987058Snate@binkert.org 1997058Snate@binkert.orgvoid 2007058Snate@binkert.orgISA::setMiscReg(int miscReg, MiscReg val, ThreadContext * tc) 2017058Snate@binkert.org{ 202396SN/A MiscReg newVal = val; 2037058Snate@binkert.org switch(miscReg) 2047058Snate@binkert.org { 2057058Snate@binkert.org case MISCREG_CR0: 2067058Snate@binkert.org { 2073329Sstever@eecs.umich.edu CR0 toggled = regVal[miscReg] ^ val; 2087058Snate@binkert.org CR0 newCR0 = val; 2097058Snate@binkert.org Efer efer = regVal[MISCREG_EFER]; 2107058Snate@binkert.org if (toggled.pg && efer.lme) { 2117058Snate@binkert.org if (newCR0.pg) { 2127058Snate@binkert.org //Turning on long mode 213396SN/A efer.lma = 1; 2147058Snate@binkert.org regVal[MISCREG_EFER] = efer; 2157058Snate@binkert.org } else { 2167058Snate@binkert.org //Turning off long mode 2177058Snate@binkert.org efer.lma = 0; 218396SN/A regVal[MISCREG_EFER] = efer; 2197058Snate@binkert.org } 2207058Snate@binkert.org } 221396SN/A if (toggled.pg) { 2227058Snate@binkert.org tc->getITBPtr()->flushAll(); 2237058Snate@binkert.org tc->getDTBPtr()->flushAll(); 2247058Snate@binkert.org } 2257058Snate@binkert.org //This must always be 1. 226396SN/A newCR0.et = 1; 2277058Snate@binkert.org newVal = newCR0; 2287058Snate@binkert.org updateHandyM5Reg(regVal[MISCREG_EFER], 2297058Snate@binkert.org newCR0, 230396SN/A regVal[MISCREG_CS_ATTR], 2317058Snate@binkert.org regVal[MISCREG_SS_ATTR], 2327058Snate@binkert.org regVal[MISCREG_RFLAGS], 2337058Snate@binkert.org tc); 2344075Sbinkertn@umich.edu } 2357058Snate@binkert.org break; 2367058Snate@binkert.org case MISCREG_CR2: 2375501Snate@binkert.org break; 2387058Snate@binkert.org case MISCREG_CR3: 2397058Snate@binkert.org tc->getITBPtr()->flushNonGlobal(); 2407058Snate@binkert.org tc->getDTBPtr()->flushNonGlobal(); 2417058Snate@binkert.org break; 2427058Snate@binkert.org case MISCREG_CR4: 2437058Snate@binkert.org { 244396SN/A CR4 toggled = regVal[miscReg] ^ val; 2452SN/A if (toggled.pae || toggled.pse || toggled.pge) { 2462SN/A tc->getITBPtr()->flushAll(); 2472SN/A tc->getDTBPtr()->flushAll(); 2482SN/A } 2495605Snate@binkert.org } 2507059Snate@binkert.org break; 251224SN/A case MISCREG_CR8: 2524016Sstever@eecs.umich.edu break; 2535501Snate@binkert.org case MISCREG_CS_ATTR: 2545605Snate@binkert.org { 2555501Snate@binkert.org SegAttr toggled = regVal[miscReg] ^ val; 2565501Snate@binkert.org SegAttr newCSAttr = val; 2575501Snate@binkert.org if (toggled.longMode) { 2585501Snate@binkert.org if (newCSAttr.longMode) { 2594016Sstever@eecs.umich.edu regVal[MISCREG_ES_EFF_BASE] = 0; 260224SN/A regVal[MISCREG_CS_EFF_BASE] = 0; 261224SN/A regVal[MISCREG_SS_EFF_BASE] = 0; 2625768Snate@binkert.org regVal[MISCREG_DS_EFF_BASE] = 0; 2635768Snate@binkert.org } else { 264265SN/A regVal[MISCREG_ES_EFF_BASE] = regVal[MISCREG_ES_BASE]; 2655501Snate@binkert.org regVal[MISCREG_CS_EFF_BASE] = regVal[MISCREG_CS_BASE]; 2665501Snate@binkert.org regVal[MISCREG_SS_EFF_BASE] = regVal[MISCREG_SS_BASE]; 2675501Snate@binkert.org regVal[MISCREG_DS_EFF_BASE] = regVal[MISCREG_DS_BASE]; 2685501Snate@binkert.org } 2695501Snate@binkert.org } 2705501Snate@binkert.org updateHandyM5Reg(regVal[MISCREG_EFER], 2715501Snate@binkert.org regVal[MISCREG_CR0], 2725501Snate@binkert.org newCSAttr, 2735501Snate@binkert.org regVal[MISCREG_SS_ATTR], 2745501Snate@binkert.org regVal[MISCREG_RFLAGS], 2755501Snate@binkert.org tc); 2765501Snate@binkert.org } 2775501Snate@binkert.org break; 2785501Snate@binkert.org case MISCREG_SS_ATTR: 2795501Snate@binkert.org updateHandyM5Reg(regVal[MISCREG_EFER], 2805501Snate@binkert.org regVal[MISCREG_CR0], 2815501Snate@binkert.org regVal[MISCREG_CS_ATTR], 2825501Snate@binkert.org val, 2835501Snate@binkert.org regVal[MISCREG_RFLAGS], 2845501Snate@binkert.org tc); 2855501Snate@binkert.org break; 2862SN/A // These segments always actually use their bases, or in other words 2875769Snate@binkert.org // their effective bases must stay equal to their actual bases. 2882SN/A case MISCREG_FS_BASE: 2892SN/A case MISCREG_GS_BASE: 2905769Snate@binkert.org case MISCREG_HS_BASE: 2912SN/A case MISCREG_TSL_BASE: 2922SN/A case MISCREG_TSG_BASE: 2935769Snate@binkert.org case MISCREG_TR_BASE: 2942SN/A case MISCREG_IDTR_BASE: 2952667Sstever@eecs.umich.edu regVal[MISCREG_SEG_EFF_BASE(miscReg - MISCREG_SEG_BASE_BASE)] = val; 2965769Snate@binkert.org break; 2972667Sstever@eecs.umich.edu // These segments ignore their bases in 64 bit mode. 2982SN/A // their effective bases must stay equal to their actual bases. 2992SN/A case MISCREG_ES_BASE: 3002SN/A case MISCREG_CS_BASE: 3012SN/A case MISCREG_SS_BASE: 3027058Snate@binkert.org case MISCREG_DS_BASE: 3032SN/A { 3045605Snate@binkert.org Efer efer = regVal[MISCREG_EFER]; 3055501Snate@binkert.org SegAttr csAttr = regVal[MISCREG_CS_ATTR]; 3065501Snate@binkert.org if (!efer.lma || !csAttr.longMode) // Check for non 64 bit mode. 3072SN/A regVal[MISCREG_SEG_EFF_BASE(miscReg - 3085501Snate@binkert.org MISCREG_SEG_BASE_BASE)] = val; 3095501Snate@binkert.org } 3105501Snate@binkert.org break; 3112SN/A case MISCREG_TSC: 3122SN/A regVal[MISCREG_TSC] = val - tc->getCpuPtr()->curCycle(); 3132SN/A return; 314224SN/A case MISCREG_DR0: 315224SN/A case MISCREG_DR1: 316237SN/A case MISCREG_DR2: 3175605Snate@binkert.org case MISCREG_DR3: 318571SN/A /* These should eventually set up breakpoints. */ 319571SN/A break; 3207005Snate@binkert.org case MISCREG_DR4: 3217005Snate@binkert.org miscReg = MISCREG_DR6; 3227005Snate@binkert.org /* Fall through to have the same effects as DR6. */ 3237005Snate@binkert.org case MISCREG_DR6: 3247005Snate@binkert.org { 3257005Snate@binkert.org DR6 dr6 = regVal[MISCREG_DR6]; 3267005Snate@binkert.org DR6 newDR6 = val; 3277005Snate@binkert.org dr6.b0 = newDR6.b0; 3287005Snate@binkert.org dr6.b1 = newDR6.b1; 3297005Snate@binkert.org dr6.b2 = newDR6.b2; 3307005Snate@binkert.org dr6.b3 = newDR6.b3; 3317005Snate@binkert.org dr6.bd = newDR6.bd; 3327005Snate@binkert.org dr6.bs = newDR6.bs; 3337005Snate@binkert.org dr6.bt = newDR6.bt; 3347005Snate@binkert.org newVal = dr6; 3357005Snate@binkert.org } 3367005Snate@binkert.org break; 3377005Snate@binkert.org case MISCREG_DR5: 3387005Snate@binkert.org miscReg = MISCREG_DR7; 3397005Snate@binkert.org /* Fall through to have the same effects as DR7. */ 3407005Snate@binkert.org case MISCREG_DR7: 3417005Snate@binkert.org { 3427005Snate@binkert.org DR7 dr7 = regVal[MISCREG_DR7]; 3437005Snate@binkert.org DR7 newDR7 = val; 3447005Snate@binkert.org dr7.l0 = newDR7.l0; 3457005Snate@binkert.org dr7.g0 = newDR7.g0; 3467005Snate@binkert.org if (dr7.l0 || dr7.g0) { 3477005Snate@binkert.org panic("Debug register breakpoints not implemented.\n"); 3487005Snate@binkert.org } else { 3497005Snate@binkert.org /* Disable breakpoint 0. */ 3507005Snate@binkert.org } 3517005Snate@binkert.org dr7.l1 = newDR7.l1; 3527005Snate@binkert.org dr7.g1 = newDR7.g1; 3537005Snate@binkert.org if (dr7.l1 || dr7.g1) { 3547005Snate@binkert.org panic("Debug register breakpoints not implemented.\n"); 3557005Snate@binkert.org } else { 3567005Snate@binkert.org /* Disable breakpoint 1. */ 3577005Snate@binkert.org } 3587005Snate@binkert.org dr7.l2 = newDR7.l2; 3597005Snate@binkert.org dr7.g2 = newDR7.g2; 3607005Snate@binkert.org if (dr7.l2 || dr7.g2) { 3612SN/A panic("Debug register breakpoints not implemented.\n"); 3622SN/A } else { 3632SN/A /* Disable breakpoint 2. */ 364395SN/A } 3652SN/A dr7.l3 = newDR7.l3; 3665605Snate@binkert.org dr7.g3 = newDR7.g3; 367265SN/A if (dr7.l3 || dr7.g3) { 3682SN/A panic("Debug register breakpoints not implemented.\n"); 3692SN/A } else { 3702SN/A /* Disable breakpoint 3. */ 3712SN/A } 3722SN/A dr7.gd = newDR7.gd; 3732SN/A dr7.rw0 = newDR7.rw0; 3742SN/A dr7.len0 = newDR7.len0; 375265SN/A dr7.rw1 = newDR7.rw1; 3762SN/A dr7.len1 = newDR7.len1; 3772SN/A dr7.rw2 = newDR7.rw2; 378512SN/A dr7.len2 = newDR7.len2; 379265SN/A dr7.rw3 = newDR7.rw3; 3802SN/A dr7.len3 = newDR7.len3; 3815738Snate@binkert.org } 3825738Snate@binkert.org break; 3835738Snate@binkert.org case MISCREG_M5_REG: 3842SN/A // Writing anything to the m5reg with side effects makes it update 3855501Snate@binkert.org // based on the current values of the relevant registers. The actual 3862667Sstever@eecs.umich.edu // value written is discarded. 3872SN/A updateHandyM5Reg(regVal[MISCREG_EFER], 3882SN/A regVal[MISCREG_CR0], 3892SN/A regVal[MISCREG_CS_ATTR], 3902SN/A regVal[MISCREG_SS_ATTR], 3915501Snate@binkert.org regVal[MISCREG_RFLAGS], 3925501Snate@binkert.org tc); 3935501Snate@binkert.org return; 3942SN/A default: 3952SN/A break; 3962SN/A } 3972SN/A setMiscRegNoEffect(miscReg, newVal); 3981634SN/A} 3991634SN/A 4001634SN/Avoid 4011634SN/AISA::serialize(CheckpointOut &cp) const 4021634SN/A{ 4032SN/A SERIALIZE_ARRAY(regVal, NumMiscRegs); 4042SN/A} 4052SN/A 4062SN/Avoid 4072SN/AISA::unserialize(CheckpointIn &cp) 4082SN/A{ 4092SN/A UNSERIALIZE_ARRAY(regVal, NumMiscRegs); 4102SN/A updateHandyM5Reg(regVal[MISCREG_EFER], 4115501Snate@binkert.org regVal[MISCREG_CR0], 4122SN/A regVal[MISCREG_CS_ATTR], 4135501Snate@binkert.org regVal[MISCREG_SS_ATTR], 4142SN/A regVal[MISCREG_RFLAGS], 4152SN/A NULL); 4162SN/A} 4175502Snate@binkert.org 4185502Snate@binkert.orgvoid 4195605Snate@binkert.orgISA::startup(ThreadContext *tc) 420217SN/A{ 421237SN/A tc->getDecoderPtr()->setM5Reg(regVal[MISCREG_M5_REG]); 4225605Snate@binkert.org} 4232SN/A 4242SN/A} 4255605Snate@binkert.org 4265605Snate@binkert.orgX86ISA::ISA * 4275605Snate@binkert.orgX86ISAParams::create() 4285605Snate@binkert.org{ 4295605Snate@binkert.org return new X86ISA::ISA(this); 4305605Snate@binkert.org} 4312SN/A