/* Sparc Softcard operations IMPLEMENTATION module See also SparcSoftcardOpsImpl.Mesa for the Cedar side */ #include "standard.h" #include "SparcSoftcard.h" #include "SparcSoftcardOps.h" static void ControlBitWrite(address, polarity, value) long address; SparcSoftcard_Polarity polarity; BOOLEAN value; { if ( ( ( polarity == Polarity_ActiveLow ) && ( value == TRUE ) ) || ( ( polarity == Polarity_ActiveHigh ) && ( value == FALSE ) ) ) io_poke((long)address, (long)0); else io_poke((long)address, (long)commandBitMask); }; static BOOLEAN ControlBitRead(address, polarity) long address; SparcSoftcard_Polarity polarity; { int value; BOOLEAN result; value = io_peek((long)address) & commandBitMask; if ( ( ( polarity == Polarity_ActiveLow ) && ( value == 0 ) ) || ( ( polarity == Polarity_ActiveHigh ) && ( value == 1 ) ) ) result = TRUE; else result = FALSE; return (result); }; /* Cache Operations */ void SparcSoftcardOps_SparcCacheDisable() { ControlBitWrite((long)sparcCacheEnableRegisterByte, sparcCacheEnablePolarity, FALSE); }; void SparcSoftcardOps_SparcCacheEnable() { ControlBitWrite((long)sparcCacheEnableRegisterByte, sparcCacheEnablePolarity, TRUE); }; /* Interrupt Operations */ void SparcSoftcardOps_SetSparcToIOPInt() { ControlBitWrite((long)sparcToIOPIntRegisterByte, sparcToIOPIntPolarity, TRUE); }; void SparcSoftcardOps_ResetSparcToIOPInt() { ControlBitWrite((long)sparcToIOPIntRegisterByte, sparcToIOPIntPolarity, FALSE); }; void SparcSoftcardOps_SetSparcToMesaInt() { ControlBitWrite((long)sparcToMesaIntRegisterByte, sparcToMesaIntPolarity, TRUE); }; void SparcSoftcardOps_ResetSparcToMesaInt() { ControlBitWrite((long)sparcToMesaIntRegisterByte, sparcToMesaIntPolarity, FALSE); }; void SparcSoftcardOps_SetSparcToSparcInt() { ControlBitWrite((long)sparcToSparcIntRegisterByte, sparcToSparcIntPolarity, TRUE); }; void SparcSoftcardOps_ResetSparcToSparcInt() { ControlBitWrite((long)sparcToSparcIntRegisterByte, sparcToSparcIntPolarity, FALSE); }; void SparcSoftcardOps_SetIOPToSparcInt() { ControlBitWrite((long)iOPToSparcIntRegisterByte, iOPToSparcIntPolarity, TRUE); }; void SparcSoftcardOps_ResetIOPToSparcInt() { ControlBitWrite((long)iOPToSparcIntRegisterByte, iOPToSparcIntPolarity, FALSE); }; void SparcSoftcardOps_SetMesaToSparcInt() { ControlBitWrite((long)mesaToSparcIntRegisterByte, mesaToSparcIntPolarity, TRUE); }; void SparcSoftcardOps_ResetMesaToSparcInt() { ControlBitWrite((long)mesaToSparcIntRegisterByte, mesaToSparcIntPolarity, FALSE); }; void SparcSoftcardOps_SetSparcAbortInt() { ControlBitWrite((long)sparcAbortIntRegisterByte, sparcAbortIntPolarity, TRUE); }; void SparcSoftcardOps_ResetSparcAbortInt() { ControlBitWrite((long)sparcAbortIntRegisterByte, sparcAbortIntPolarity, FALSE); }; void SparcSoftcardOps_EnableInt() { ControlBitWrite((long)enableIntRegisterByte, enableIntPolarity, TRUE); }; void SparcSoftcardOps_DisableInt() { ControlBitWrite((long)enableIntRegisterByte, enableIntPolarity, FALSE); }; /* Peripheral Interrupt Operations */ static void SetInterruptSource(interruptNumber, interruptSource) SparcSoftcardOps_InterruptNumber interruptNumber; SparcSoftcardOps_InterruptSource interruptSource; { long baseByteAddress; /* Select address where to store */ switch (interruptNumber) { case InterruptNumber_interruptA: baseByteAddress = intASourceByte; break; case InterruptNumber_interruptB: baseByteAddress = intBSourceByte; break; case InterruptNumber_interruptC: baseByteAddress = intCSourceByte; break; }; /* write the Source Selection registers one at a time */ io_poke(baseByteAddress + intSourceReg0Offset , (((long) interruptSource) >> 3)); io_poke(baseByteAddress + intSourceReg1Offset , (((long) interruptSource) >> 2)); io_poke(baseByteAddress + intSourceReg2Offset , (((long) interruptSource) >> 1)); io_poke(baseByteAddress + intSourceReg3Offset , (((long) interruptSource) >> 0)); }; static void SetInterruptModeAndDest(interruptNumber, interruptMode, interruptProcessor) SparcSoftcardOps_InterruptNumber interruptNumber; SparcSoftcardOps_InterruptMode interruptMode; SparcSoftcardOps_InterruptProcessor interruptProcessor; { long baseByteAddress; /* Select address where to store */ switch (interruptNumber) { case InterruptNumber_interruptA: baseByteAddress = intAModeByte; break; case InterruptNumber_interruptB: baseByteAddress = intBModeByte; break; case InterruptNumber_interruptC: baseByteAddress = intCModeByte; break; }; /* select the mode (the bits are set and reset by a read at different locations */ switch (interruptMode) { case InterruptMode_activeLow: (void) io_peek(baseByteAddress + intModeSetOffset + intModeReg3Offset); /* set Polarity bit */ (void) io_peek(baseByteAddress + intModeSetOffset + intModeReg4Offset); /* set Direct bit */ break; case InterruptMode_activeHigh: (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg3Offset); /* reset Polarity bit */ (void) io_peek(baseByteAddress + intModeSetOffset + intModeReg4Offset); /* set Direct bit */ break; case InterruptMode_risingEdge: (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg3Offset); /* reset Polarity bit */ (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg4Offset); /* reset Direct bit */ (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg0Offset); /* reset the "edge active" bit */ break; case InterruptMode_fallingEdge: (void) io_peek(baseByteAddress + intModeSetOffset + intModeReg3Offset); /* set Polarity bit */ (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg4Offset); /* reset Direct bit */ (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg0Offset); /* reset the "edge active" bit */ break; }; /* select the processor (the bits are set and reset by a read at different locations */ switch (interruptProcessor) { case InterruptProcessor_cp: /* cp requires bits to be set to 1 1 */ (void) io_peek(baseByteAddress + intModeSetOffset + intModeReg1Offset); (void) io_peek(baseByteAddress + intModeSetOffset + intModeReg2Offset); break; case InterruptProcessor_iOP: /* IOP requires bits to be set to 1 0 */ (void) io_peek(baseByteAddress + intModeSetOffset + intModeReg1Offset); (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg2Offset); break; case InterruptProcessor_sparc: /* sparc requires bits to be set to 0 1 */ (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg1Offset); (void) io_peek(baseByteAddress + intModeSetOffset + intModeReg2Offset); break; case InterruptProcessor_none: /* requires bits to be set to 0 0 */ (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg1Offset); (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg2Offset); break; }; }; void SparcSoftcardOps_SetPeriphIntMode(interruptSource, interruptMode, interruptNumber, interruptProcessor) SparcSoftcardOps_InterruptSource interruptSource; SparcSoftcardOps_InterruptMode interruptMode; SparcSoftcardOps_InterruptNumber interruptNumber; SparcSoftcardOps_InterruptProcessor interruptProcessor; { SparcSoftcardOps_DisableInt(); SetInterruptSource(interruptNumber, interruptSource); SetInterruptModeAndDest(interruptNumber, interruptMode, interruptProcessor); SparcSoftcardOps_EnableInt(); }; BOOLEAN ReadPeriphIntState(interruptNumber) SparcSoftcardOps_InterruptNumber interruptNumber; { long baseByteAddress, direct; /* Select address */ switch (interruptNumber) { case InterruptNumber_interruptA: baseByteAddress = intAModeByte; break; case InterruptNumber_interruptB: baseByteAddress = intBModeByte; break; case InterruptNumber_interruptC: baseByteAddress = intCModeByte; break; }; /* read the "direct" bit to know whitch value to return */ direct = io_peek(baseByteAddress + intModeReadOffset + intModeReg4Offset) & 1; if (direct == 1) { /* return the value of the input bit xored with polarity */ return((BOOLEAN)(io_peek(baseByteAddress+intModeReadOffset+intModeReg5Offset) & 1)); } else { /* return the value of the "edge active" bit */ return((BOOLEAN)(io_peek(baseByteAddress+intModeReadOffset+intModeReg0Offset) & 1)); }; }; void SparcSoftcardOps_ResetPeriphInt(interruptNumber) SparcSoftcardOps_InterruptNumber interruptNumber; { long baseByteAddress; /* Select address */ switch (interruptNumber) { case InterruptNumber_interruptA: baseByteAddress = intAModeByte; break; case InterruptNumber_interruptB: baseByteAddress = intBModeByte; break; case InterruptNumber_interruptC: baseByteAddress = intCModeByte; break; }; /* clear the "edge active" bit */ (void) io_peek(baseByteAddress + intModeResetOffset + intModeReg0Offset); }; /* DMA Operations */ void SparcSoftcardOps_SetDMAState(dMAState) SparcSoftcardOps_DMAState dMAState; { if (dMAState == DMAState_active) ControlBitWrite((long)dMAActiveRegisterByte, dMAActivePolarity, TRUE); else ControlBitWrite((long)dMAActiveRegisterByte, dMAActivePolarity, FALSE); }; void SparcSoftcardOps_SetDMAMode(dMAMode) SparcSoftcardOps_DMAMode dMAMode; { switch (dMAMode) { case DMAMode_printer: ControlBitWrite((long)dMAMode0RegisterByte, dMAMode0Polarity, FALSE); ControlBitWrite((long)dMAMode1RegisterByte, dMAMode1Polarity, FALSE); break; case DMAMode_display: ControlBitWrite((long)dMAMode0RegisterByte, dMAMode0Polarity, FALSE); ControlBitWrite((long)dMAMode1RegisterByte, dMAMode1Polarity, TRUE); break; case DMAMode_versatecOneShot: ControlBitWrite((long)dMAMode0RegisterByte, dMAMode0Polarity, TRUE); ControlBitWrite((long)dMAMode1RegisterByte, dMAMode1Polarity, FALSE); break; case DMAMode_versatecStream: ControlBitWrite((long)dMAMode0RegisterByte, dMAMode0Polarity, TRUE); ControlBitWrite((long)dMAMode1RegisterByte, dMAMode1Polarity, TRUE); break; }; }; void SparcSoftcardOps_DMAAddressRegisterLoad (byteAddress) long byteAddress; { long address = byteAddress / 8; io_poke((long)dMAAddressRegisterLowByte, (long)address); io_poke((long)dMAAddressRegisterHighByte, (long)(address>>16)); }; /* Versatec Operations */ BOOLEAN VersatecPrinterEnd() { return (ControlBitRead((long)pVEndRegisterByte, pVEndPolarity)); }; BOOLEAN VersatecOnLine() { return (ControlBitRead((long)versOnLineRegisterByte, versOnLinePolarity)); }; BOOLEAN VersatecReady() { return (ControlBitRead((long)versReadyRegisterByte, versReadyPolarity)); }; void SetVersatecMode (versatecMode) SparcSoftcardOps_VersatecMode versatecMode; { if ((versatecMode == VersatecMode_print) || (versatecMode == VersatecMode_SPPPrint)) { ControlBitWrite((long)versatecPrintRegisterByte, versatecPrintPolarity, TRUE); } else { ControlBitWrite((long)versatecPrintRegisterByte, versatecPrintPolarity, FALSE); }; if ((versatecMode == VersatecMode_SPPPrint) || (versatecMode == VersatecMode_SPPPlot)) { ControlBitWrite((long)versatecSPPRegisterByte, versatecPrintPolarity, TRUE); } else { ControlBitWrite((long)versatecSPPRegisterByte, versatecPrintPolarity, FALSE); }; }; BOOLEAN SendVersatecRCommand (versatecRCommand) SparcSoftcardOps_VersatecRCommand versatecRCommand; { int byteAddress; switch (versatecRCommand) { case VersatecRCommand_CLEAR : { byteAddress = versatecClearByte; break; }; case VersatecRCommand_RESET : { byteAddress = versatecResetByte; break; }; case VersatecRCommand_RLTER : { byteAddress = versatecRLTERByte; break; }; case VersatecRCommand_RFFED : { byteAddress = versatecRFFEDByte; break; }; case VersatecRCommand_REOTR : { byteAddress = versatecREOTRByte; break; }; }; (void) io_peek ((long)byteAddress); while ((VersatecOnLine() == TRUE) & (VersatecReady() == FALSE)) ; return (VersatecOnLine()); }; BOOLEAN VersatecSendOneByte (data) unsigned char data; { unsigned char s[16], *p; long byteAddress; if (VersatecOnLine() == FALSE) { return(FALSE); } else { byteAddress = (long) s; byteAddress = (byteAddress + 7) & (~ 7); p = ( unsigned char * ) byteAddress; *p = data; SparcSoftcardOps_SetDMAState(DMAState_inactive); SparcSoftcardOps_SetDMAMode(DMAMode_versatecOneShot); SparcSoftcardOps_DMAAddressRegisterLoad(byteAddress); SparcSoftcardOps_SetDMAState(DMAState_active); while ((VersatecOnLine() == TRUE) && (VersatecPrinterEnd() == FALSE)) ; SparcSoftcardOps_SetDMAState(DMAState_inactive); return (VersatecOnLine()); }; }; void SetTimer(byteCount) long byteCount; { long count, data; count = (byteCount - 64) / 16; io_poke((long)timAddress3Byte, (long)0x32); /* command: timer 0 mode 1 */ data = count; io_poke((long)timAddress0Byte, data); /* store count value LS byte first */ data = data / 256; io_poke((long)timAddress0Byte, data); /* store count value MS byte last */ }; BOOLEAN VersatecSendSmallBuffer (byteAddress, byteCount) long byteAddress, byteCount; { if (VersatecOnLine() == FALSE) { return(FALSE); } else { SparcSoftcardOps_SetDMAState(DMAState_inactive); SparcSoftcardOps_SetDMAMode(DMAMode_versatecStream); SparcSoftcardOps_DMAAddressRegisterLoad(byteAddress); SetTimer(byteCount); SparcSoftcardOps_SetDMAState(DMAState_active); while ((VersatecOnLine() == TRUE) && (VersatecPrinterEnd() == FALSE)) ; SparcSoftcardOps_SetDMAState(DMAState_inactive); return (VersatecOnLine()); }; }; BOOLEAN VersatecSendBuffer (byteAddress, byteCount) long byteAddress, byteCount; { long bytesToSend; unsigned char *p; while ( (byteAddress % 16) != 0 ) { /* align on an 16 bytes word bondary */ p = (unsigned char *) byteAddress; if (VersatecSendOneByte (*p) == FALSE) return (FALSE); byteAddress += 1; byteCount -= 1; }; while ( byteCount > 1024 * 1024 ) { /* send 1 mega byte chunk at a time */ bytesToSend = 1024 * 1024; byteCount -= 1024 * 1024; if ( byteCount < 96 ) { /* impossible to send less than 96 bytes at a time */ bytesToSend -= 96; byteCount += 96; }; if (VersatecSendSmallBuffer (byteAddress, bytesToSend) == FALSE) return (FALSE); byteAddress += bytesToSend; }; bytesToSend = byteCount - byteCount % 16; if (bytesToSend >= 96 ) { /* send a multiple of sixteen bigger or equal than 96 bytes */ if (VersatecSendSmallBuffer (byteAddress, bytesToSend) == FALSE) return (FALSE); byteAddress += bytesToSend; byteCount -= bytesToSend; }; while ( byteCount != 0 ) { /* last bytes */ p = (unsigned char *) byteAddress; if (VersatecSendOneByte (*p) == FALSE) return (FALSE); byteAddress += 1; byteCount -= 1; }; return (TRUE); }; /* Those fonctions are the one defined by the interface but return a too complex argument... they are not used now */ /* Map Access */ static long ComputeEntryAddress (mapEntry) SparcSoftcardOps_MapEntry mapEntry; { long mapEntryNumber, entryAddressHighByte; switch (mapEntry.vMSpace.name) { case VMSpaceName_dMA : { mapEntryNumber = 0x0E000; if (mapEntry.virtualAddressByte >= 0x4000000) goto eRROR; break; }; case VMSpaceName_iOP : { mapEntryNumber = 0x0A000; if (mapEntry.virtualAddressByte >= 0x1000000) goto eRROR; break; }; case VMSpaceName_cP : { mapEntryNumber = 0x0A000 + 0x1000000/softcardPageSizeByte; if (mapEntry.virtualAddressByte >= 0x400000) goto eRROR; break; }; case VMSpaceName_sparcUserData : { mapEntryNumber = 0; if (mapEntry.virtualAddressByte >= 0x8000000) goto eRROR; break; }; case VMSpaceName_sparcUserProgram : { mapEntryNumber = 0x4000; if (mapEntry.virtualAddressByte >= 0x8000000) goto eRROR; break; }; case VMSpaceName_sparcSuperData : { mapEntryNumber = 0x8000; if (mapEntry.virtualAddressByte >= 0x4000000) goto eRROR; break; }; case VMSpaceName_sparcSuperProgram : { mapEntryNumber = 0xC000; if (mapEntry.virtualAddressByte >= 0x4000000) goto eRROR; break; }; default : { eRROR: for(;;){}; }; }; mapEntryNumber = mapEntryNumber + mapEntry.virtualAddressByte/softcardPageSizeByte; entryAddressHighByte = mapBaseByte + mapEntryNumber * mapEntrySizeByte; return (entryAddressHighByte); }; static long ConcreteFromEntry (mapEntry) SparcSoftcardOps_MapEntry mapEntry; { long mapEntryConcreteCard, *p; SparcSoftcardOps_MapEntryConcrete mapEntryConcrete, *q; mapEntryConcrete.readOnly = mapEntry.flags.readOnly; mapEntryConcrete.referenced = mapEntry.flags.referenced; mapEntryConcrete.dirty = mapEntry.flags.dirty; mapEntryConcrete.nonCachable = mapEntry.flags.nonCachable; mapEntryConcrete.interrupt = mapEntry.flags.interrupt; /* Implemented for 128 Mega in task 0 only */ mapEntryConcrete.task = 0; mapEntryConcrete.virtualPageHiHi = 0; mapEntryConcrete.virtualPageHiLow = 0; mapEntryConcrete.realPage = mapEntry.realAddressByte/softcardPageSizeByte; /* Convert this machine dependant structure into a long */ q = &mapEntryConcrete; p = (long *) q; mapEntryConcreteCard = *p; return (mapEntryConcreteCard); }; void SparcSoftcardOps_WriteMapEntry (mapEntry) SparcSoftcardOps_MapEntry mapEntry; { long entryAddressHighByte, entryAddressLowByte; long mapEntryConcrete; entryAddressHighByte = ComputeEntryAddress (mapEntry); entryAddressLowByte = entryAddressHighByte + mapEntryLowByteOffset - mapEntryHighByteOffset; mapEntryConcrete = ConcreteFromEntry (mapEntry); io_poke((long)entryAddressHighByte, ( mapEntryConcrete>>16)); io_poke((long)entryAddressLowByte, (mapEntryConcrete)); }; ÊW˜˜J˜J˜/J˜J˜5—J˜J˜J˜J˜Jšœ˜J˜J˜J˜˜5J˜ J˜ J˜˜˜@J˜BJ˜ —J˜2—J˜—J˜˜0J˜ J˜ ˜J˜ J˜J˜0˜=J˜>J˜—J˜J˜—J˜—J˜J˜J˜J˜J˜˜+J˜UJ˜—J˜˜*J˜TJ˜—J˜J˜J˜J˜J˜˜*J˜NJ˜—˜,J˜OJ˜—J˜˜+J˜PJ˜—˜-J˜QJ˜—J˜˜,J˜RJ˜—˜.J˜SJ˜—J˜˜*J˜NJ˜—˜,J˜OJ˜—J˜˜+J˜PJ˜—˜-J˜QJ˜—J˜˜*J˜NJ˜—˜,J˜OJ˜—J˜˜#J˜FJ˜—˜$J˜GJ˜—J˜J˜J˜J˜J˜J˜˜@J˜1J˜1˜J˜J˜#˜˜ J˜!J˜—˜ J˜!J˜—˜ J˜!J˜—J˜—J˜9J˜QJ˜QJ˜QJ˜QJ˜——J˜˜WJ˜1J˜-J˜7˜J˜J˜#˜˜ J˜J˜—˜ J˜J˜—˜ J˜J˜—J˜—J˜T˜˜˜GJ˜—˜GJ˜—J˜—˜˜IJ˜—˜GJ˜—J˜—˜˜IJ˜—˜IJ˜—˜IJ˜!—J˜—˜˜GJ˜—˜IJ˜—˜IJ˜!—J˜—J˜—J˜X˜˜DJ˜GJ˜GJ˜—˜FJ˜GJ˜IJ˜—˜JJ˜IJ˜GJ˜—˜CJ˜IJ˜IJ˜—J˜—J˜——J˜˜kJ˜1J˜-J˜1J˜7˜J˜J˜5J˜LJ˜J˜—J˜—˜+J˜1˜J˜J˜˜˜ J˜J˜—˜ J˜J˜—˜ J˜J˜—J˜—J˜:J˜N˜NJ˜TJ˜—˜6J˜TJ˜—J˜—J˜—˜5J˜1˜J˜J˜˜˜ J˜J˜—˜ J˜J˜—˜ J˜J˜—J˜—J˜!J˜IJ˜—J˜—J˜J˜J˜J˜˜+J˜#J˜˜ J˜F—˜J˜G—J˜—J˜˜)J˜!J˜˜˜J˜EJ˜EJ˜—˜J˜EJ˜DJ˜—˜J˜DJ˜EJ˜—˜J˜DJ˜DJ˜—J˜—J˜—J˜˜:J˜J˜J˜J˜8J˜?J˜—J˜J˜J˜J˜J˜J˜˜˜J˜@J˜J˜J˜——˜˜J˜JJ˜J˜J˜——˜˜J˜HJ˜J˜J˜——˜#J˜+˜˜VJ˜NJ˜—˜J˜OJ˜J˜—˜XJ˜LJ˜—˜J˜MJ˜—J˜J˜——˜/J˜3˜J˜˜˜J˜ J˜J˜—˜J˜ J˜J˜—˜J˜ J˜J˜—˜J˜ J˜J˜—˜J˜ J˜J˜—J˜—J˜#˜!J˜—J˜J˜——J˜˜"J˜˜J˜J˜˜ J˜J˜—˜J˜J˜(J˜$J˜ J˜0J˜5J˜5J˜.˜!J˜%—J˜0J˜J˜—J˜——J˜˜J˜˜J˜J˜J˜IJ˜ J˜KJ˜J˜JJ˜——J˜˜8J˜˜˜ J˜J˜—˜J˜0J˜4J˜5J˜J˜.˜!J˜%—J˜0J˜J˜—J˜——J˜˜3J˜˜J˜J˜J˜˜KJ˜"J˜6J˜J˜J˜—J˜˜JJ˜J˜˜NJ˜J˜J˜—J˜PJ˜J˜—J˜J˜)˜XJ˜PJ˜J˜J˜—J˜˜+J˜"J˜6J˜J˜J˜—J˜J˜——J˜˜J˜o—J˜J˜J˜J˜ J˜J˜˜*J˜#J˜J˜J˜*˜ ˜J˜J˜9J˜J˜—˜J˜J˜9J˜J˜—˜J˜:J˜8J˜J˜—˜"J˜J˜9J˜J˜—˜%J˜J˜9J˜J˜—˜#J˜J˜9J˜J˜—˜&J˜J˜9J˜J˜—˜ J˜J˜—J˜—J˜SJ˜GJ˜J˜—J˜˜(J˜#J˜J˜J˜7J˜J˜4J˜8J˜.J˜:J˜6J˜J˜-J˜J˜%J˜&J˜J˜JJ˜J˜:J˜J˜J˜J˜J˜J˜—J˜˜.J˜#J˜J˜/J˜J˜J˜6J˜\J˜0J˜J˜=J˜7J˜—J˜J˜—…—AÚI7