1 पॉइंट द्वारा GN⁺ 2025-07-02 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Donkey Kong Country 2 के कुछ rotating barrel सेक्शन में पुराने SNES emulator ZSNES पर ऐसा bug है कि direction key छोड़ने के बाद भी barrel घूमता रहता है, और इसका कारण open bus behavior का emulation न होना है
  • असली SNES में unmapped address पढ़ने पर data bus पर मौजूद आखिरी value फिर से पढ़ी जाती है, और DKC2 bank $B3 में $2000/$2001 read के दौरान इसी विशेषता पर निर्भर करता है
  • समस्या वाला routine barrel की पिछली direction और नई direction को XOR करने के बाद and $2000 चलाता है, और असली hardware पर यह 16-bit open bus read 0x2020 लौटाता है जिससे direction boundary पार होने का पता चलता है
  • ZSNES की तरह अगर open bus read 0 लौटाए, तो AND result हमेशा 0 बनता है और rotation रोकने वाली branch कभी execute नहीं होती, इसलिए barrel तब तक घूमता रहता है जब तक उलटी direction न दबाई जाए
  • संभव है कि यह instruction वास्तव में and #$2000 होना चाहिए था, और एक ROM revision में $33EDAC पर opcode को 0x2D से 0x29 बदलने पर open bus के बिना भी यह सही काम करता है

ZSNES में rotating barrel का न रुकने वाला व्यवहार

  • Donkey Kong Country 2 में कुछ stages के rotating barrel ZSNES पर सही तरह काम नहीं करने वाला एक पुराना bug मौजूद है
  • सामान्य behavior में player barrel के अंदर left/right direction key दबाए रखने के दौरान ही rotation को control कर सकता है
  • ZSNES में left या right एक बार दबाने पर barrel उसी दिशा में लगातार घूमता रहता है, और उलटी दिशा दबाने पर दूसरी ओर लगातार घूमने लगता है
  • बाद के हिस्सों में barrel spikes या दूसरे hazards के ऊपर रखे गए हैं, इसलिए यह bug stage की difficulty को developers की मंशा से काफी ज्यादा बढ़ा देता है
  • यही समस्या लगभग 20 साल पहले Anomie ने खोजी थी और लगता है कि Snes9x में इसे ठीक किया गया था, लेकिन उस समय का fix पूरे open bus emulation के बजाय game जिन specific address values पर निर्भर था उन्हें hardcode करने का था
  • ZSNES में यह bug आखिर तक ठीक नहीं हुआ, और project की आखिरी release 2007 में आई थी

SNES का open bus और 65816 addressing

  • SNES में गलत memory address पढ़ने पर भी आमतौर पर program crash नहीं होता
  • unmapped address पढ़ने पर CPU data bus पर आखिरी बार मौजूद value को फिर से पढ़ता है; इसे open bus behavior कहा जाता है
  • SNES का main CPU 65C816 है, यानी 65816, जो Ricoh 5A22 S-CPU package के अंदर शामिल है
  • 65816, 6502 का 16-bit extended CPU है, और SNES में 24-bit address bus इस्तेमाल होती है, लेकिन ज्यादातर addresses 8-bit bank और 16-bit offset के combination से बनते हैं
  • कई instructions अंदरूनी तौर पर 16-bit address इस्तेमाल करते हैं, और instruction fetch में program bank register, जबकि data access में data bank register शामिल होता है
  • DKC2 के rotating barrel state में bank $B3 से $2000 और $2001 पढ़े जाते हैं, और ये addresses bank $B3 में कहीं mapped नहीं हैं, इसलिए यहाँ open bus read होता है

समस्या वाले routine की memory access

  • rotating barrel के अंदर left/right direction छोड़ने पर हर frame चलने वाला routine open bus read करता है
  • शुरुआती state में data bank register $B3, direct page $0000, और M/X flags दोनों clear होते हैं, इसलिए registers और memory access 16-bit हैं
  • यह routine $0000-$2001 range के कई addresses इस्तेमाल करता है
    • $0EE6: मौजूदा barrel direction
    • $0E0A: प्रति frame rotation amount
    • $0032: संभवतः एक temporary variable
  • bank $00-$3F और $80-$BF में $0000-$1FFF console की 128KB WRAM के पहले 8KB पर mapped होते हैं
  • $2000-$20FF unmapped area है, इसलिए and $2000 instruction एक open bus read बन जाता है

0x2020 का rotation रोकने के निर्णय में उपयोग

  • routine current direction में rotation amount जोड़कर नई direction बनाता है और उसे temporary variable में store करता है
  • इसके बाद पिछली direction और नई direction को XOR किया जाता है, फिर result पर and $2000 लगाया जाता है और देखा जाता है कि result 0 है या नहीं
  • असली SNES hardware पर 16-bit open bus read and $2000 हमेशा 0x2020 लौटाता है
    • and $2000 का machine code 2D 00 20 है
    • 65816 8-bit data bus इस्तेमाल करता है, इसलिए 16-bit read दो 8-bit reads में किया जाता है
    • इस मामले में आखिरी पढ़ा गया byte address का high byte 0x20 होता है, इसलिए दोनों बार 0x20 लौटता है
  • इसलिए वास्तविक behavior कार्यात्मक रूप से and #$2020 जैसा है
  • अगर AND result 0 हो, तो नई direction को ज्यों का त्यों store किया जाता है और अगले frame में भी rotation जारी रहती है
  • अगर 0 न हो, तो rotation amount को 0 कर दिया जाता है, नई direction में 0x1000 जोड़ा जाता है, और फिर 0xE000 से mask करके उसे नज़दीकी 0x2000 multiple direction पर align किया जाता है

ZSNES में यह लगातार क्यों घूमता रहता है

  • barrel direction value का scale ऐसा लगता है कि 0x0000 नीचे की दिशा और 0x4000 बाईं दिशा को दिखाता है
  • विश्लेषित barrel में clockwise rotation amount 0x0300 और counterclockwise rotation amount 0xFD00 है, और 360 degree rotation में 85 frames से थोड़ा ज्यादा समय लगता है
  • 60fps के हिसाब से यह 1.5 सेकंड से थोड़ा कम है
  • 0x2020 के साथ AND में वास्तव में मायने रखने वाला बदलाव bit 13 यानी 0x2000 है
  • direction value में 0x2000 का बदलाव किसी base direction या diagonal direction के एक step बदलने के बराबर है
  • सही hardware पर direction key छोड़ने के बाद barrel अगली base/diagonal direction तक घूमता है और फिर ठीक उसी दिशा की ओर रुक जाता है
  • अगर open bus read हमेशा 0 लौटाए, तो AND result भी हमेशा 0 होगा और rotation रोकने वाला code कभी execute नहीं होगा

टाइपो की संभावना और ROM patch का परिणाम

  • and $2000 एक absolute addressing instruction है, और तर्क के हिसाब से संभव है कि यह and #$2000 immediate addressing होना चाहिए था
  • असली hardware पर open bus 0x2020 लौटाता है, इसलिए and $2000 संयोग से intended behavior के मुताबिक काम करता है
  • यह संयोग इस शर्त पर निर्भर है कि प्रति frame rotation amount के निचले 6 bits हमेशा 0 हों, जिससे 0x2020 कार्यात्मक रूप से 0x2000 के बराबर हो जाता है
  • गलत opcode bank $B3 offset $EDAC पर execute होता है, और विश्लेषित revision में game के 4MB ROM के अंदर यह $33EDAC पर mapped है
  • इस byte को 0x2D से 0x29 बदलने पर, भले ही open bus read हमेशा 0 लौटाए, rotating barrel सही तरह काम करता है
  • game की दूसरी revisions में सटीक ROM location अलग हो सकती है
  • पुराने ZSNES को छोड़कर लगभग सभी SNES emulators में game सही काम करता है, इसलिए यह मामला व्यावहारिक patch से ज्यादा hardware-dependent behavior को trace करने वाला analysis है

1 टिप्पणियां

 
GN⁺ 2025-07-02
Hacker News टिप्पणियां
  • 6502 assembly लिखते समय immediate value से पहले # लगाना भूलकर memory access कर बैठने जैसी गलती में मैंने अपनी ज़िंदगी का बहुत समय गंवाया है
    इस उदाहरण की तरह, कई बार यह संयोग से कुछ परिस्थितियों में काम भी कर जाता है। इससे भी बुरा मामला uninitialized RAM पर निर्भर होना है; DRAM की प्रकृति के कारण यह मेरी मशीन या emulator पर हमेशा ठीक चल सकता है, लेकिन किसी और की मशीन में अलग DRAM chip होने पर टूट सकता है। आम तौर पर यह बात demoparty में presentation से 15 मिनट पहले party machine पर न चलने पर पता चलती है

    • सोच रहा हूं कि क्या 6502 CPU और dynamic memory साथ इस्तेमाल करने वाला कोई architecture था। मेरे सीमित अनुभव में तो लगता है कि उस platform ने हमेशा static RAM ही इस्तेमाल की
    • 6502 मेरी पहली assembly language थी, और मैं हमेशा LDA #2 को “A में संख्या 2 load करो” और LDA 2 को “memory location 2 में मौजूद value को A में load करो” की तरह अलग-अलग सोचता था
    • ऐसी स्थिति में code को LLM में डालकर देखना सच में मददगार हो सकता है। ऐसे typos या गलतियों का असर बड़ा होता है, फिर भी इंसानी आंखों से बहुत आसानी से छूट जाते हैं, और LLM इन्हें काफी अच्छी तरह ढूंढ लेते हैं
  • title में Open Bus capital letters में लिखा था, इसलिए शुरू में पढ़ना मैंने यह सोचकर शुरू किया कि यह कोई पुराना bus protocol या standard का proper noun होगा जिसके बारे में मैंने नहीं सुना
    पढ़ने पर पता चला कि address line decoder specified address $2000 पर किसी भी memory device को activate नहीं करता, इसलिए bus किसी चीज़ से connected न होकर “open” state में है। immediate addressing वाले # को भूल जाने की समस्या, पुराने emulator द्वारा actual hardware की तरह memory read handle न करने पर ही सामने आई—यह काफी मज़ेदार है। fix में absolute addressing की जगह immediate addressing इस्तेमाल करने से memory read नहीं होगा, इसलिए execution time भी तेज़ होगा। उस code chunk में लगभग 2µs की तेजी आ सकती है, लेकिन शायद यह bare metal पर ही मायने रखेगा और emulator में वैसे भी पूरी timing accuracy होने की संभावना कम है

    • Rare के games में कई ऐसे case हैं जहां testing में सब ठीक चलता था, लेकिन कई साल बाद नए architecture पर ही hidden bug सामने आया। इसका मतलब यह नहीं कि दूसरी companies में ऐसा नहीं होता; बस इस topic में Rare refer करने के लिए आसान नाम है
      Donkey Kong 64 में memory leak था, जिससे उस समय के हिसाब से अव्यावहारिक रूप से लंबे continuous play time, यानी 8–9 घंटे बाद game crash हो जाता था। development के दौरान यह पकड़ में नहीं आया, लेकिन emulator save state इस्तेमाल करके in-game save feature की जगह लगातार आगे बढ़ते रहने पर यह समय जल्दी जमा हो जाता है। हालांकि history थोड़ी अस्पष्ट है। कुछ sources दावा करते हैं कि Memory Pak bundle करना crash time को 8–9 घंटे से 13–20 घंटे तक धकेलकर bug छिपाने के लिए last-minute कदम था, लेकिन recent research के हिसाब से यह संयोग था और ऐसा नहीं लगता कि Rare या Nintendo ने bug जानते हुए release किया था
    • कुछ SNES emulators इस point पर timing तक के मामले में भी लगभग perfect हैं [0]। फिर भी, 2µs असाधारण cases को छोड़कर महसूस होने लायक अंतर नहीं बनाएगा
      [0] https://arstechnica.com/gaming/2021/06/how-snes-emulators-go...
  • RetroArch के RunAhead feature पर काम करते हुए, जब मैं save states के mismatch होने वाले points देख रहा था, तब मैंने SNES Puyo Puyo को PPU open bus इस्तेमाल करते देखा था
    state load करने के बाद PPU Open Bus से पढ़ी गई value बदल गई, इसलिए CPU execution trace logs match नहीं हुए

  • 6502 family वाली गलतियां मैं हमेशा नहीं करता, लेकिन जब करता हूं तो आम तौर पर immediate value की जगह memory address लिख देने की गलती होती है
    यह बहुत आम और आसानी से हो जाने वाली गलती है, और मेरा मानना है कि Chuck Peddle खुद भी immediate value में #$1234 की तरह # लगाने वाली syntax पर गहरा पछताते होंगे। IDE में # को bright red दिखाने लगा तो थोड़ी मदद हुई। Rare के assembly देवता भी इसी problem में फंस गए

    • बहुत पहले GNU assembler के intel_syntax noprefix mode में मुझे ऐसी ही problem हुई थी
      उन instructions में जो immediate value और memory address दोनों ले सकते हैं, आगे reference किए जाने वाले named constant immediate value को unknown symbol reference के रूप में interpret कर सकने वाली syntax ambiguity थी। नतीजा यह हुआ कि expected immediate value के बजाय instruction ऐसे placeholder memory address के साथ assemble हो गया, जिसे link time पर symbol के relocation address से भरा जाना था। debugging बेहद कष्टदायक थी
    • ARM जैसे instruction sets ने ऐसी गलती को practically impossible बना दिया। memory handle करनी हो तो अलग instruction इस्तेमाल करनी पड़ती है
  • ऐसे लेख मुझे पसंद हैं। assembly code को मैं हमेशा लगभग 60% ही follow कर पाता हूं, इसलिए साथ में दी गई prose explanation सच में मदद करती है
    classic software के अंदर ऐसी bugs की कहानियां सुनना भी मज़ेदार है जिन्हें शायद किसी ने समझा नहीं था, या शायद अब तक notice भी नहीं किया था

    • इस दौर के systems आकर्षक होने की एक वजह यह है कि उनमें वे modern checks नहीं थे जिन्हें आज हम लगभग हर जगह default मानते हैं
      ऐसे checks जो network से connect हो सकने वाले systems के लिए जरूरी हैं, और अब इतने सस्ते हो गए हैं कि पूरी तरह isolated embedded architectures में भी डाले जा सकते हैं। original NES में कई reads और writes असल में कहीं की lines पर voltage toggle करने भर थे, और उसके बाद जो होना था वह हो जाता था। desired effect CRT blanking interval दिखाने वाले signal के साथ बिल्कुल align करके voltage को बहुत controlled तरीके से toggle करने से मिलता था। Super Mario Bros 3 की कुछ animations RAM multiplexer को toggle करके कई sprite data banks में से एक चुनवाती थीं, और graphics hardware जब sprite fetch करता था तो वह थोड़ा अलग दिखने वाले पूरी तरह अलग chip से पढ़ता था। TV timing महत्वपूर्ण थी, इसलिए NTSC और PAL TV regions के लिए software भी अलग release करना पड़ता था; दोनों में refresh rate अलग था और वही refresh rate rendering logic को drive करने वाली clock थी। सचमुच बहुत rough दौर था
  • जहां तक मुझे पता है, open bus सिर्फ शुरुआती systems में दिखता है जो simple synchronous bus इस्तेमाल करते थे
    बाकी ज्यादातर systems में non-existent address access करने पर केवल 0s से भरी या 1s से भरी constant value मिलती है। क्योंकि bus protocol में handshake होता है जिससे master जान सकता है कि कोई response नहीं है, और PCI terminology में इसे “master abort” कहा जाता है

  • Open bus का मतलब शाब्दिक रूप से डेटा बस लाइन का open circuit होना है
    CPU ने address bus पर ऐसा address रखा जो mapped नहीं था या write-only था, और bus पर किसी भी hardware ने जवाब नहीं दिया, इसलिए bus lines drive नहीं हुईं और floating state में रह गईं। नाममात्र तौर पर यह hardware level पर undefined behavior है
    असल में क्या होता है, यह समझने के लिए data bus की physical structure को थोड़ा और देखना होगा। motherboard और cartridge के आसपास signals ले जाने वाले लंबे conductors होते हैं, और वे पतली insulating substrate layer के बीच से ground plane से अलग रहते हैं। यह capacitor जैसा दिखता है, और सच में engineers इसे parasitic capacitance के रूप में समझाते और model करते हैं। यह effect bus की maximum data transfer speed को limit करता है, इसलिए इसे minimize करने की कोशिश की जाती है। लेकिन इसी effect की वजह से, जब bus drive नहीं हो रही होती, तो वह आख़िरी बार drive किए गए voltage पर बने रहने की प्रवृत्ति रखती है। यह छोटी DRAM cell की तरह काम करती है, जिससे लेख में बताया गया “open bus read, bus से आख़िरी बार गुज़रे value को return करता है” वाला effect पैदा होता है
    DKC2 की तरह, games का गलती से open bus effect पर निर्भर हो जाना दुर्लभ नहीं है। NES में controller connection के लिए serial port register सिर्फ lower bits drive करता है और upper bits open bus रहते हैं। कुछ games LDA $4016 instruction से controller input पढ़कर $40 या $41 value की उम्मीद भी करते हैं। यहाँ 4 open bus की वजह से बची हुई value है
    memory corruption या arbitrary code execution exploits के हिस्से के रूप में open bus behavior पर निर्भर करने वाली speedrun strategies भी हैं। उदाहरण के लिए Super Mario World credits warp program counter को unmapped memory में भेजकर उसे काफी देर तक आगे बढ़ने देता है, फिर अंत में RAM तक पहुँचाता है, और enemy positions को बहुत बारीकी से manipulate करके बनाए गए payload को execute करता है [1]
    हालांकि आम तौर पर predictable open bus behavior में भी exceptions होते हैं। non-standard cartridges unmapped memory पर default value return कर सकते हैं, या pull-up/pull-down resistors शामिल करके open bus behavior को प्रभावित कर सकते हैं। DMA के साथ भी दिलचस्प interaction है। SNES HDMA नाम की feature support करता है, जिससे application frame के बीच में data upload करने या settings बदलने के लिए CPU से graphics hardware तक data को exact timing पर transfer करने के लिए schedule कर सकती है [2]। यह DMA transfer bus का उपयोग करके transfer करने के लिए CPU को थोड़ी देर रोकता है, और अगर DMA transfer instruction execution के बीच में, यानी target address पढ़ने के बाद लेकिन वास्तविक open bus read से पहले आ जाए, तो open bus read behavior बदल सकता है
    यह बेहद खास edge case Super Metroid speedrun exploit [3] पर बड़ा असर डालता है। यह exploit out-of-bounds memcpy कराकर open bus से RAM में data का बड़ा block ले जाने की कोशिश करता है। open bus read लगभग हमेशा 0 return करता है, क्योंकि संबंधित load instruction का आख़िरी byte 0 होता है। लेकिन जिन खास rooms में HDMA graphics effects बहुत होते हैं, वहाँ DMA transfer के उन reads में से किसी एक को प्रभावित करने की संभावना काफी होती है, और तब non-zero byte किसी critical location में घुसकर exploit को ठीक से काम करने से रोकता है और crash करा देता है। इसकी वजह से community में हल्की बहस हुई। कुछ routes और strategies केवल emulators और non-standard firmware पर ही stable हैं। original hardware या बहुत accurate emulator इस्तेमाल करने वाले players को crash का सामना करने की संभावना ज़्यादा होती है, लेकिन Nintendo के सभी official re-releases समेत ज़्यादातर emulators instruction के बीच HDMA transfer द्वारा open bus read value बदलने वाले इस खास edge case को emulate नहीं करते
    साथ ही, वर्तमान में सबसे तेज़ Super Metroid TAS clear [4] इसी HDMA interaction पर निर्भर करता है। open bus execute करने की कोशिश में crash होने वाली स्थिति मिली थी, लेकिन सामान्यतः उसे उपयोगी तरीके से control नहीं किया जा सकता था। room में enemies को manipulate करके CPU timing को प्रभावित किया गया, और HDMA से सही timing पर bus पर उपयोगी instructions रखे जा सके। अंत में console controller input को code के रूप में execute कराने में सफल हुआ और पूरी arbitrary code execution हासिल हुई
    [1]: https://youtu.be/vAHXK2wut_I
    [2]: https://youtu.be/K7gWmdgXPgk
    [3]: https://youtu.be/CnThmKhtfOs
    [4]: https://tasvideos.org/8214S

    • data bus की physical structure देखने वाली बात पर मैं एक बार फिर Ben Eater की तारीफ़ करना चाहूँगा
      6502 से breadboard computer बनाने वाली उनकी video series की वजह से लेख की बात और hardware problem की explanation सच में समझ आती है। बेशक, यह उनके basic bus example को commercial machine तक extend करके सोचने जैसा है। वरना मुझे लगभग कुछ भी पता नहीं होता
      https://eater.net
  • Parallax Propeller chip को program करते समय भी कुछ हद तक मिलती-जुलती समस्या होती है
    specified memory location पर jump करने के लिए JMP #address इस्तेमाल करना चाहिए, लेकिन मैं हमेशा JMP address लिख देता हूँ, जो specified memory location से पढ़े गए address पर jump करता है। शायद 6502 assembler अब भी muscle memory में बसा हुआ है
    Propeller: JMP #address
    6502: JMP address
    Propeller: JMP address
    6502: JMP (address)
    सबसे बुरी बात यह है कि इस लेख की तरह buggy Propeller code कभी-कभी चल भी जाता है। फिर किसी पल रुक जाता है, और क्यों हुआ यह पता लगाने में घंटों लग जाते हैं

  • DKC 1 के SGI pre-rendered 3D graphics उस समय cutting-edge थे। Genesis के Vector Man ने भी कुछ ऐसा ही किया था, लेकिन उसे कम attention मिला

    • 1995 के आसपास मैं 11 साल का बच्चा था, यानी DKC का बिल्कुल target audience, और वह game सचमुच चौंकाने वाला था
      जो देख रहा था उस पर विश्वास नहीं हो रहा था। release के आसपास game को teaser करने और development की behind-the-scenes चीज़ें दिखाने वाली एक videotape थी, शायद cereal box जैसी किसी जगह से apply करके मिली promotional चीज़ याद आती है। मैंने वह tape बहुत बार देखी। DKC मेरे पास खुद नहीं था, लेकिन दोस्त के घर पर खेल सकता था
    • बचपन में वे graphics कहीं न कहीं नकली जैसे लगते थे। क्योंकि किसी स्तर पर यह महसूस हो जाता था कि वे “असली” नहीं हैं
      उस समय magazines इस विषय पर काफी vague तरीके से लिखती थीं, और ऐसा इशारा करती थीं जैसे SNES की performance characters वगैरह को real-time में render कर रही हो। जबकि असल में वह मूल रूप से flipbook animation के ज्यादा करीब था
  • emulation पर गेम खेलते-खेलते अगर कहीं अटक जाऊँ, तो आखिर में यह सोचने लगता हूँ कि कहीं यह emulator bug तो नहीं है
    इस खास समस्या के मामले में, मैं यही सोचता कि गेम को मूल रूप से ऐसे ही design किया गया है और यह बस कठिन है। यह बहुत सीधे तौर पर संबंधित नहीं है, लेकिन जब कोई गेम सच में बहुत कठिन लगता है, तब भी मैं कुछ ऐसा ही सोचता हूँ: “क्या यह emulation delay की वजह से है?” इस समस्या में गहराई तक जाते-जाते आखिरकार मैंने खुद एक MiSTer FPGA बना लिया

    • Chrono Trigger में भी ऐसा कुछ था
      याद है कि एक जगह चूहे को पकड़ने के बाद चार keys को एक साथ input करना पड़ता था। लेकिन USB input एक बार में सिर्फ 3 ही भेजता था, इसलिए आगे बढ़ने के लिए चारों keys को बेतहाशा दबाना पड़ता था ताकि बहुत छोटे समय के भीतर आखिरकार सभी register हो जाएँ। कई बार कोशिश करनी पड़ी और यह बहुत झुंझलाहट भरा था
    • DKC मैंने सिर्फ ZSNES पर खेला था, और यह लेख पढ़ने से पहले मुझे बिल्कुल पता नहीं था कि यह emulator bug था
      जैसा कहा गया है, मैं बस यही सोचता था कि barrel से launch करने की timing मिलाकर सही angle बनाना intended game design है। यह जानकर सच में हैरानी हुई कि यह bug था
    • बचपन में मैंने Bionic Commando बहुत खेला था
      2000 के दशक की शुरुआत में emulator पर चलाकर देखा तो यह मेरी याद से कहीं ज्यादा कठिन था। बाद में पता चला कि bases को blast करने के बाद भी enemies गायब नहीं होते थे—यह emulation bug था, और Ladd फिर भी freeze रहता था। इसलिए level clear करने के लिए लगभग 2 extra health bars चाहिए थीं। यह देखने के लिए कि क्या यह संभव है, मैंने एक बार वैसे clear किया, लेकिन फिर कभी नहीं किया