Subversion Repositories pentevo

Rev

Rev 921 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "vars.h"
  5. #include "memory.h"
  6. #include "util.h"
  7.  
  8. // input: ports 7FFD,1FFD,DFFD,FFF7,FF77,EFF7, flags CF_TRDOS,CF_CACHEON
  9. void set_banks()
  10. {
  11.    bankw[1] = bankr[1] = RAM_BASE_M + 5*PAGE;
  12.    bankw[2] = bankr[2] = RAM_BASE_M + 2*PAGE;
  13.  
  14.    // screen begining
  15.    temp.base = memory + ((comp.p7FFD & 8) ? 7*PAGE : 5*PAGE);
  16. /*
  17.    if(conf.mem_model == MM_QUORUM)
  18.        temp.base = memory + (comp.p80FD & 7) * 0x2000 + 5*PAGE;
  19. */
  20.  
  21.    if (temp.base_2)
  22.        temp.base_2 = temp.base;
  23.  
  24.    // these flags will be re-calculated
  25.    comp.flags &= ~(CF_DOSPORTS | CF_Z80FBUS | CF_LEAVEDOSRAM | CF_LEAVEDOSADR | CF_SETDOSROM);
  26.  
  27.    unsigned char *bank0, *bank3;
  28.  
  29.    if (comp.flags & CF_TRDOS)
  30.    {
  31.        if(comp.p7FFD & 0x10)
  32.        {
  33.            bank0 = base_dos_rom;
  34.        }
  35.        else
  36.        {
  37.            bank0 = base_sys_rom;
  38.        }
  39.    }
  40.    else
  41.        bank0 = (comp.p7FFD & 0x10)? base_sos_rom : base_128_rom;
  42.  
  43.    unsigned bank = (comp.p7FFD & 7);
  44.  
  45.    switch (conf.mem_model)
  46.    {
  47.       case MM_PENTAGON:
  48.          if(!(comp.pEFF7 & EFF7_LOCKMEM))
  49.          {
  50.              // 7FFD bits
  51.              //    210 - 128
  52.              //   6210 - 256
  53.              //  76210 - 512
  54.              // 576210 - 1024
  55.              bank |= (comp.p7FFD & 0xC0) >> 3;
  56.              bank |= (comp.p7FFD & 0x20);
  57.          }
  58.  
  59.          bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE;
  60.  
  61.          if (comp.pEFF7 & EFF7_ROCACHE)
  62.              bank0 = RAM_BASE_M + 0*PAGE; //Alone Coder 0.36.4
  63.          break;
  64.  
  65.       case MM_PROFSCORP:
  66.          membits[0x0100] &= ~MEMBITS_R;
  67.          membits[0x0104] &= ~MEMBITS_R;
  68.          membits[0x0108] &= ~MEMBITS_R;
  69.          membits[0x010C] &= ~MEMBITS_R;
  70.       case MM_SCORP:
  71.          bank += ((comp.p1FFD & 0x10) >> 1) + ((comp.p1FFD & 0xC0) >> 2);
  72.          bank3 = RAM_BASE_M + (bank & temp.ram_mask) * PAGE;
  73.  
  74. /*
  75.          // юсЁрсюЄър ярь Єш gmx (ъюэЇышъЄєхЄ ёю ёЄрэфрЁЄэ√ь profrom)
  76.          // эєцэю ёфхырЄ№ Їыру чряшёш т яюЁЄ 7EFD, ш хёыш с√ыр їюЄ№ юфэр чряшё№
  77.          // Єю юсЁрсрЄ√трЄ№ rom яю ёЄрэфрЁЄє gmx
  78.          comp.profrom_bank = ((comp.p7EFD >> 4) & 3) & temp.profrom_mask;
  79.          {
  80.              unsigned char *base = ROM_BASE_M + (comp.profrom_bank * 64*1024);
  81.              base_128_rom = base + 0*PAGE;
  82.              base_sos_rom = base + 1*PAGE;
  83.              base_sys_rom = base + 2*PAGE;
  84.              base_dos_rom = base + 3*PAGE;
  85.          }
  86. */
  87.  
  88.          // ─юЁрсюЄър шч ъэшцъш gmx (тъы■ўхэшх яюЁЄют dos шч ╬╟╙, ёфхырэю эхьэюую эх Єръ ъръ т Ёхры№эющ ёїхьх)
  89.          if(comp.p1FFD & 4)
  90.              comp.flags |= CF_TRDOS;
  91.          if(comp.p1FFD & 2)
  92.             bank0 = base_sys_rom;
  93.          if(comp.p1FFD & 1)
  94.             bank0 = RAM_BASE_M + 0 * PAGE;
  95.          if(conf.mem_model == MM_PROFSCORP)
  96.          {
  97.              if (bank0 == base_sys_rom)
  98.                  comp.flags |= CF_PROFROM;
  99.              else
  100.                  comp.flags &= ~CF_PROFROM;
  101.          }
  102.          break;
  103.  
  104.       case MM_KAY:
  105.       {
  106.          bank += ((comp.p1FFD & 0x10) >> 1) + ((comp.p1FFD & 0x80) >> 3) + ((comp.p7FFD & 0x80) >> 2);
  107.          bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE;
  108.          unsigned char rom1 = (comp.p1FFD >> 2) & 2;
  109.          if (comp.flags & CF_TRDOS) rom1 ^= 2;
  110.          switch (rom1+((comp.p7FFD & 0x10) >> 4))
  111.          {
  112.             case 0: bank0 = base_128_rom; break;
  113.             case 1: bank0 = base_sos_rom; break;
  114.             case 2: bank0 = base_sys_rom; break;
  115.             case 3: bank0 = base_dos_rom; break;
  116.             default: __assume(0);
  117.          }
  118.          if (comp.p1FFD & 1) bank0 = RAM_BASE_M + 0*PAGE;
  119.          break;
  120.       }
  121.  
  122.       case MM_PROFI:
  123.          bank += ((comp.pDFFD & 0x07U) << 3U); bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE;
  124.          if(comp.pDFFD & 0x08)
  125.          {
  126.              bankr[1] = bankw[1] = bank3;
  127.              bank3 = RAM_BASE_M + 7 * PAGE;
  128.          }
  129.          if (comp.pDFFD & 0x10) bank0 = RAM_BASE_M+0*PAGE;
  130.          if (comp.pDFFD & 0x20) comp.flags |= CF_DOSPORTS;
  131.          if (comp.pDFFD & 0x40) bankr[2] = bankw[2] = RAM_BASE_M + 6*PAGE;
  132.          break;
  133.  
  134.       case MM_ATM450:
  135.       {
  136.          // RAM
  137.          // original ATM uses D2 as ROM address extension, not RAM
  138.          bank += ((comp.pFDFD & 0x07U) << 3U);
  139.          bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE;
  140.          if (!(comp.aFE & 0x80))
  141.          {
  142.             bankw[1] = bankr[1] = RAM_BASE_M + 4*PAGE;
  143.             bank0 = RAM_BASE_M;
  144.             break;
  145.          }
  146.  
  147.          // ROM
  148.          if (comp.p7FFD & 0x20)
  149.              comp.aFB &= ~0x80;
  150.          if ((comp.flags & CF_TRDOS) && (comp.pFDFD & 8))
  151.              comp.aFB |= 0x80; // more priority, then 7FFD
  152.  
  153.          if (comp.aFB & 0x80) // CPSYS signal
  154.          {
  155.              bank0 = base_sys_rom;
  156.              break;
  157.          }
  158.          // system rom not used on 7FFD.4=0 and DOS=1
  159.          if (comp.flags & CF_TRDOS)
  160.              bank0 = base_dos_rom;
  161.          break;
  162.       }
  163.  
  164.       case MM_ATM3:
  165.          if (comp.pBF & 1) // shaden
  166.             comp.flags |= CF_DOSPORTS;
  167.  
  168.       case MM_ATM710:
  169.       {
  170.          if (!(comp.aFF77 & 0x200)) // ~cpm=0
  171.             comp.flags |= CF_TRDOS;
  172.  
  173.          if (!(comp.aFF77 & 0x100))
  174.          { // pen=0
  175.             bankr[1] = bankr[2] = bank3 = bank0 = ROM_BASE_M + PAGE * temp.rom_mask;
  176.             break;
  177.          }
  178.  
  179.          unsigned i = ((comp.p7FFD & 0x10) >> 2);
  180.          for (unsigned bank = 0; bank < 4; bank++)
  181.          {
  182.                         // lvd added 6 or 3 bits from 7FFD to page number insertion in pentevo (was only 3 as in atm2)
  183.                         unsigned int mem7ffd = (comp.p7FFD & 7) | ( (comp.p7FFD & 0xE0)>>2 );
  184.                         unsigned int mask7ffd = 0x07;
  185.                        
  186.                         if( conf.mem_model==MM_ATM3 && ( !(comp.pEFF7 & EFF7_LOCKMEM) ) )
  187.                                 mask7ffd = 0x3F;
  188.                        
  189.                         switch (comp.pFFF7[i+bank] & 0x300)
  190.             {
  191.                case 0x000: // RAM from 7FFD (lvd patched)
  192.                   bankr[bank] = bankw[bank] = RAM_BASE_M + PAGE * ((mem7ffd & mask7ffd) | (comp.pFFF7[i+bank] & (~mask7ffd) & temp.ram_mask));
  193.                   break;
  194.                case 0x100: // ROM from 7FFD
  195.                   bankr[bank] = ROM_BASE_M + PAGE*((comp.pFFF7[i+bank] & 0xFE & temp.rom_mask) + ((comp.flags & CF_TRDOS)?1:0));
  196.                   break;
  197.                case 0x200: // RAM from FFF7
  198.                   bankr[bank] = bankw[bank] = RAM_BASE_M + PAGE*(comp.pFFF7[i+bank] & 0xFF & temp.ram_mask);
  199.                   break;
  200.                case 0x300: // ROM from FFF7
  201.                   bankr[bank] = ROM_BASE_M + PAGE*(comp.pFFF7[i+bank] & 0xFF & temp.rom_mask);
  202.                   break;
  203.             }
  204.          }
  205.          bank0 = bankr[0]; bank3 = bankr[3];
  206.  
  207.                 if( conf.mem_model==MM_ATM3 ) // lvd added pentevo RAM0 to bank0 feature if EFF7_ROCACHE is set
  208.                 {
  209.                         if( cpu.nmi_in_progress )
  210.                                 bank0 = RAM_BASE_M + PAGE * cpu.nmi_in_progress;
  211.                         else if( comp.pEFF7 & EFF7_ROCACHE )
  212.                                 bank0 = RAM_BASE_M + PAGE * 0x00;
  213.                 }
  214.          break;
  215.       }
  216.  
  217.       case MM_PLUS3:
  218.       {
  219.           if(comp.p7FFD & 0x20) // paging disabled (48k mode)
  220.           {
  221.               bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE;
  222.               break;
  223.           }
  224.  
  225.           if(!(comp.p1FFD & 1))
  226.           {
  227.               unsigned RomBank = ((comp.p1FFD & 4) >> 1) | ((comp.p7FFD & 0x10) >> 4);
  228.               switch(RomBank)
  229.               {
  230.                  case 0: bank0 = base_128_rom; break;
  231.                  case 1: bank0 = base_sys_rom; break;
  232.                  case 2: bank0 = base_dos_rom; break;
  233.                  case 3: bank0 = base_sos_rom; break;
  234.               }
  235.               bank3 = RAM_BASE_M + (bank & temp.ram_mask)*PAGE;
  236.           }
  237.           else
  238.           {
  239.               unsigned RamPage = (comp.p1FFD >> 1) & 3; // d2,d1
  240.               static const unsigned RamDecoder[4][4] =
  241.               { {0, 1, 2, 3}, {4, 5, 6, 7}, {4, 5, 6, 3}, {4, 7, 6, 3} };
  242.               for(unsigned i = 0; i < 4; i++)
  243.                   bankw[i] = bankr[i] = RAM_BASE_M + PAGE * RamDecoder[RamPage][i];
  244.               bank0 = bankr[0];
  245.               bank3 = bankr[3];
  246.           }
  247.           break;
  248.       }
  249.  
  250.       case MM_QUORUM:
  251.       {
  252.           if(!(comp.p00 & Q_TR_DOS))
  253.               comp.flags |= CF_DOSPORTS;
  254.  
  255.           if(comp.p00 & Q_B_ROM)
  256.           {
  257.               if (comp.flags & CF_TRDOS)
  258.                   bank0 = base_dos_rom;
  259.               else
  260.                   bank0 = (comp.p7FFD & 0x10) ? base_sos_rom : base_128_rom;
  261.           }
  262.           else
  263.           {
  264.               bank0 = base_sys_rom;
  265.           }
  266.  
  267.           if(comp.p00 & Q_F_RAM)
  268.           {
  269.               unsigned bnk0 = (comp.p00 & Q_RAM_8) ? 8 : 0;
  270.               bank0 = RAM_BASE_M + (bnk0 & temp.ram_mask) * PAGE;
  271.           }
  272.  
  273.           bank |= ((comp.p7FFD & 0xC0) >> 3) | (comp.p7FFD & 0x20);
  274.           bank3 = RAM_BASE_M + (bank & temp.ram_mask) * PAGE;
  275.           break;
  276.       }
  277.  
  278.       default: bank3 = RAM_BASE_M + 0*PAGE;
  279.    }
  280.  
  281.    bankw[0] = bankr[0] = bank0;
  282.    bankw[3] = bankr[3] = bank3;
  283.  
  284.    if (bankr[0] >= ROM_BASE_M) bankw[0] = TRASH_M;
  285.    if (bankr[1] >= ROM_BASE_M) bankw[1] = TRASH_M;
  286.    if (bankr[2] >= ROM_BASE_M) bankw[2] = TRASH_M;
  287.    if (bankr[3] >= ROM_BASE_M) bankw[3] = TRASH_M;
  288.  
  289.  
  290.    unsigned char dosflags = CF_LEAVEDOSRAM;
  291.    if (conf.mem_model == MM_PENTAGON || conf.mem_model == MM_PROFI)
  292.        dosflags = CF_LEAVEDOSADR;
  293.  
  294.    if (comp.flags & CF_TRDOS)
  295.    {
  296.        comp.flags |= dosflags | CF_DOSPORTS;
  297.    }
  298.    else if ((comp.p7FFD & 0x10) && conf.trdos_present)
  299.    { // B-48, inactive DOS, DOS present
  300.       // for Scorp, ATM-1/2 and KAY, TR-DOS not started on executing RAM 3Dxx
  301.       if (!((dosflags & CF_LEAVEDOSRAM) && bankr[0] < RAM_BASE_M+PAGE*MAX_RAM_PAGES))
  302.          comp.flags |= CF_SETDOSROM;
  303.    }
  304.  
  305.    if (comp.flags & CF_CACHEON)
  306.    {
  307.       unsigned char *cpage = CACHE_M;
  308.       if (conf.cache == 32 && !(comp.p7FFD & 0x10)) cpage += PAGE;
  309.       bankr[0] = bankw[0] = cpage;
  310.       // if (comp.pEFF7 & EFF7_ROCACHE) bankw[0] = TRASH_M; //Alone Coder 0.36.4
  311.    }
  312.  
  313.    if ((comp.flags & CF_DOSPORTS)? conf.floatdos : conf.floatbus)
  314.        comp.flags |= CF_Z80FBUS;
  315.  
  316.    if (temp.led.osw && (trace_rom | trace_ram))
  317.    {
  318.       for (unsigned i = 0; i < 4; i++) {
  319.          unsigned bank = unsigned((bankr[i] - RAM_BASE_M) / PAGE);
  320.          if (bank < MAX_PAGES) used_banks[bank] = 1;
  321.       }
  322.    }
  323. /*
  324.     if ((unsigned)(bankr[0] - ROM_BASE_M) < PAGE*MAX_ROM_PAGES)
  325.     {
  326.         printf("ROM%2X\n", (bankr[0] - ROM_BASE_M)/PAGE);
  327.         printf("DOS=%p\n",  base_dos_rom);
  328.         printf("SVM=%p\n",  base_sys_rom);
  329.         printf("SOS=%p\n",  base_sos_rom);
  330.         printf("128=%p\n",  base_128_rom);
  331.     }
  332. */
  333. }
  334.  
  335. void set_scorp_profrom(unsigned read_address)
  336. {
  337.    static unsigned char switch_table[] =
  338.    {
  339.       0,1,2,3,
  340.       3,3,3,2,
  341.       2,2,0,1,
  342.       1,0,1,0
  343.    };
  344.    comp.profrom_bank = switch_table[read_address*4 + comp.profrom_bank] & temp.profrom_mask;
  345.    unsigned char *base = ROM_BASE_M + (comp.profrom_bank * 64*1024);
  346.    base_128_rom = base + 0*PAGE;
  347.    base_sos_rom = base + 1*PAGE;
  348.    base_sys_rom = base + 2*PAGE;
  349.    base_dos_rom = base + 3*PAGE;
  350.    set_banks();
  351. }
  352.  
  353. /*
  354. u8 *__fastcall MemDbg(u32 addr)
  355. {
  356.     return am_r(addr);
  357. }
  358.  
  359. void __fastcall wmdbg(u32 addr, u8 val)
  360. {
  361.    *am_r(addr) = val;
  362. }
  363.  
  364. u8 __fastcall rmdbg(u32 addr)
  365. {
  366.    return *am_r(addr);
  367. }
  368. */
  369.  
  370. void set_mode(ROM_MODE mode)
  371. {
  372.    if (mode == RM_NOCHANGE)
  373.        return;
  374.  
  375.    if (mode == RM_CACHE)
  376.    {
  377.        comp.flags |= CF_CACHEON;
  378.        set_banks();
  379.        return;
  380.    }
  381.  
  382.    // no RAM/cache/SERVICE
  383.    comp.p1FFD &= ~7;
  384.    comp.pDFFD &= ~0x10;
  385.    comp.flags &= ~CF_CACHEON;
  386.  
  387.    // comp.aFF77 |= 0x100; // enable ATM memory
  388.  
  389.    switch (mode)
  390.    {
  391.       case RM_128:
  392.          comp.flags &= ~CF_TRDOS;
  393.          comp.p7FFD &= ~0x10;
  394.          break;
  395.       case RM_SOS:
  396.          comp.flags &= ~CF_TRDOS;
  397.          comp.p7FFD |= 0x10;
  398.  
  399.          if(conf.mem_model == MM_PLUS3) // disable paging
  400.             comp.p7FFD |= 0x20;
  401.          break;
  402.       case RM_SYS:
  403.          comp.flags |= CF_TRDOS;
  404.          comp.p7FFD &= ~0x10;
  405.          break;
  406.       case RM_DOS:
  407.          comp.flags |= CF_TRDOS;
  408.                  if(conf.mem_model != MM_ATM710){
  409.                         comp.p7FFD |=  0x10;
  410.                  }
  411.          //if(conf.mem_model == MM_ATM710 || conf.mem_model == MM_ATM3)
  412.          //    comp.p7FFD &=  ~0x10;
  413.          break;
  414.    }
  415.    set_banks();
  416. }
  417.  
  418. static unsigned char cmosBCD(unsigned char binary)
  419. {
  420.    if (!(cmos[11] & 4)) binary = (binary % 10) + 0x10*((binary/10)%10);
  421.    return binary;
  422. }
  423.  
  424. unsigned char cmos_read()
  425. {
  426.    static SYSTEMTIME st;
  427.    static bool UF = false;
  428.    static unsigned Seconds = 0;
  429.    static unsigned long long last_tsc = 0ULL;
  430.    unsigned char reg = comp.cmos_addr;
  431.    unsigned char rv;
  432.    if (conf.cmos == 2)
  433.        reg &= 0x3F;
  434.  
  435.    if ((1 << reg) & ((1<<0)|(1<<2)|(1<<4)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<12)))
  436.    {
  437.       unsigned long long tsc = rdtsc();
  438.       // [vv] ╫рё√ ўшЄр■Єё  эх ўр∙х фтєї Ёрч т ёхъєэфє
  439.       if ((tsc-last_tsc) >= 25 * temp.ticks_frame)
  440.       {
  441.           GetLocalTime(&st);
  442.           if(st.wSecond != Seconds)
  443.           {
  444.               UF = true;
  445.               Seconds = st.wSecond;
  446.           }
  447.       }
  448.    }
  449.  
  450.    if (input.buffer_enabled && reg >= 0xF0)    //thims zxevo_ps2
  451.    {
  452.        return input.buffer.Pop();
  453.    }
  454.    switch (reg)
  455.    {
  456.       case 0:     return cmosBCD((BYTE)st.wSecond);
  457.       case 2:     return cmosBCD((BYTE)st.wMinute);
  458.       case 4:     return cmosBCD((BYTE)st.wHour);
  459.       case 6:     return 1+(((BYTE)st.wDayOfWeek+8-conf.cmos) % 7);
  460.       case 7:     return cmosBCD((BYTE)st.wDay);
  461.       case 8:     return cmosBCD((BYTE)st.wMonth);
  462.       case 9:     return cmosBCD(st.wYear % 100);
  463.       case 10:    return 0x20 | (cmos [10] & 0xF); // molodcov_alex
  464.       case 11:    return (cmos[11] & 4) | 2;
  465.       case 12:  // [vv] UF
  466.           rv = UF ? 0x10 : 0;
  467.           UF = false;
  468.           return rv;
  469.       case 13:    return 0x80;
  470.    }
  471.    return cmos[reg];
  472. }
  473.  
  474. void cmos_write(unsigned char val)
  475. {
  476.    if (conf.cmos == 2) comp.cmos_addr &= 0x3F;
  477.         if (conf.mem_model == MM_ATM3 && comp.cmos_addr == 0x0C)
  478.         {
  479.                 if (val & 0x01)
  480.                    input.buffer.Empty();
  481.                 return;
  482.         }
  483.    cmos[comp.cmos_addr] = val;
  484. }
  485.  
  486. void NVRAM::write(unsigned char val)
  487. {
  488.    const int SCL = 0x40, SDA = 0x10, //WP = 0x20,
  489.              SDA_1 = 0xFF, SDA_0 = 0xBF,
  490.              SDA_SHIFT_IN = 4;
  491.  
  492.    if ((val ^ prev) & SCL) // clock edge, data in/out
  493.    {
  494.       if (val & SCL) // nvram reads SDA
  495.       {
  496.          if (state == RD_ACK)
  497.          {
  498.             if (val & SDA) goto idle; // no ACK, stop
  499.             // move next byte to host
  500.             state = SEND_DATA;
  501.             dataout = nvram[address];
  502.             address = (address+1) & 0x7FF;
  503.             bitsout = 0; goto exit; // out_z==1;
  504.          }
  505.  
  506.          if ((1<<state) & ((1<<RCV_ADDR)|(1<<RCV_CMD)|(1<<RCV_DATA))) {
  507.              if(out_z) // skip nvram ACK before reading
  508.              {
  509.                  datain = 2 * datain + ((val >> SDA_SHIFT_IN) & 1);
  510.                  bitsin++;
  511.              }
  512.          }
  513.  
  514.       } else { // nvram sets SDA
  515.  
  516.          if (bitsin == 8) // byte received
  517.          {
  518.             bitsin = 0;
  519.             if (state == RCV_CMD) {
  520.                if ((datain & 0xF0) != 0xA0) goto idle;
  521.                address = (address & 0xFF) + ((datain << 7) & 0x700);
  522.                if (datain & 1) { // read from current address
  523.                   dataout = nvram[address];
  524.                   address = (address+1) & 0x7FF;
  525.                   bitsout = 0;
  526.                   state = SEND_DATA;
  527.                } else
  528.                   state = RCV_ADDR;
  529.             } else if (state == RCV_ADDR) {
  530.                address = (address & 0x700) + datain;
  531.                state = RCV_DATA; bitsin = 0;
  532.             } else if (state == RCV_DATA) {
  533.                nvram[address] = datain;
  534.                address = (address & 0x7F0) + ((address+1) & 0x0F);
  535.                // state unchanged
  536.             }
  537.  
  538.             // EEPROM always acknowledges
  539.             out = SDA_0; out_z = 0; goto exit;
  540.          }
  541.  
  542.          if (state == SEND_DATA) {
  543.             if (bitsout == 8) { state = RD_ACK; out_z = 1; goto exit; }
  544.             out = (dataout & 0x80)? SDA_1 : SDA_0; dataout *= 2;
  545.             bitsout++; out_z = 0; goto exit;
  546.          }
  547.  
  548.          out_z = 1; // no ACK, reading
  549.       }
  550.       goto exit;
  551.    }
  552.  
  553.    if ((val & SCL) && ((val ^ prev) & SDA)) // start/stop
  554.    {
  555.       if (val & SDA) { idle: state = IDLE; } // stop
  556.       else // start
  557.       {
  558.           state = RCV_CMD;
  559.           bitsin = 0;
  560.       }
  561.       out_z = 1;
  562.    }
  563.  
  564.    // else SDA changed on low SCL
  565.  
  566.  
  567.  exit:
  568.    if (out_z) out = (val & SDA)? SDA_1 : SDA_0;
  569.    prev = val;
  570. }
  571.