Subversion Repositories pentevo

Rev

Rev 716 | Blame | Last modification | View Log | Download | RSS feed

  1. #include "std.h"
  2.  
  3. #include "emul.h"
  4. #include "vars.h"
  5. #include "font.h"
  6. #include "font16.h"
  7. #include "gs.h"
  8. #include "tape.h"
  9. #include "draw.h"
  10. #include "debug.h"
  11. #include "dbgbpx.h"
  12. #include "memory.h"
  13.  
  14. #include "util.h"
  15.  
  16. unsigned pitch;
  17.  
  18. void text_i(unsigned char *dst, const char *text, unsigned char ink, unsigned off = 0)
  19. {
  20.    unsigned char mask = 0xF0; ink &= 0x0F;
  21.    for (unsigned char *x = (unsigned char*)text; *x; x++) {
  22.       unsigned char *d0 = dst;
  23.       for (unsigned y = 0; y < 8; y++) {
  24.          unsigned char byte = font[(*x)*8+y];
  25.          d0[0] = (byte >> off) + (d0[0] & ~(0xFC >> off));
  26.          d0[1] = (d0[1] & 0xF0) + ink;
  27.          if (off > 2) {
  28.             d0[2] = (byte << (8-off)) + (d0[2] & ~(0xFC << (8-off)));
  29.             d0[3] = (d0[3] & 0xF0) + ink;
  30.          }
  31.          d0 += pitch;
  32.       }
  33.       off += 6; if (off & 8) off -= 8, dst += 2;
  34.    }
  35. }
  36.  
  37. static void text_16(unsigned char *dst, const char *text, unsigned char attr)
  38. {
  39.    for (; *text; text++, dst += 2)
  40.       for (unsigned y = 0; y < 16; y++)
  41.          dst[y*pitch] = font16[16 * *(unsigned char*)text + y],
  42.          dst[y*pitch+1] = attr;
  43. }
  44.  
  45. unsigned char *aypos;
  46. void paint_led(unsigned level, unsigned char at)
  47. {
  48.    if (level) {
  49.       if (level > 15) level = 15, at = 0x0E;
  50.       unsigned mask = (0xFFFF0000 >> level) & 0xFFFF;
  51.       aypos[0] = mask >> 8;
  52.       aypos[2] = (unsigned char)mask;
  53.       aypos[1] = (aypos[1] & 0xF0) + at, aypos[3] = (aypos[3] & 0xF0) + at;
  54.    }
  55.    aypos += pitch;
  56. }
  57.  
  58. void ay_led()
  59. {
  60.    aypos = temp.led.ay;
  61.    unsigned char sum=0;
  62.  
  63.    int max_ay = (conf.sound.ay_scheme > AY_SCHEME_PSEUDO)? 2 : 1;
  64.    for (int n_ay = 0; n_ay < max_ay; n_ay++) {
  65.       for (int i = 0; i < 3; i++) {
  66.          unsigned char r_mix = ay[n_ay].get_reg(7);
  67.          unsigned char tone = (r_mix >> i) & 1,
  68.                        noise = (r_mix >> (i+3)) & 1;
  69.          unsigned char c1 = 0, c2 = 0;
  70.          unsigned char v = ay[n_ay].get_reg(i+8);
  71.          if (!tone) c1 = c2 = 0x0F;
  72.          if (!noise) c2 = 0x0E;
  73.          if (v & 0x10) {
  74.             unsigned r_envT = ay[n_ay].get_reg(11) + 0x100*ay[n_ay].get_reg(12);
  75.             if (r_envT < 0x400) {
  76.                v = (3-(r_envT>>3)) & 0x0F;
  77.                if (!v) v = 6;
  78.             } else v = ay[n_ay].get_env()/2;
  79.             c1 = 0x0C;
  80.          } else v &= 0x0F;
  81.          if (!c1) c1 = c2;
  82.          if (!c2) c2 = c1;
  83.          if (!c1) v = 0;
  84.          sum |= v;
  85.          paint_led(v, c1);
  86.          paint_led(v, c2);
  87.          paint_led(0, 0);
  88.       }
  89.    }
  90.  
  91.    const unsigned FMvols[]={4,9,15,23,35,48,70,105,140,195,243,335,452,608,761,1023};
  92.    #define _cBlue 0x09
  93.    #define _cRed 0x0a
  94.    #define _cPurp 0x0b
  95.    #define _cGreen 0x0c
  96.    #define _cCyan 0x0d
  97.    #define _cYell 0x0e
  98.    #define _cWhite 0x0f
  99.  
  100.    const int FMalg1[]={
  101.    _cBlue , _cPurp , _cGreen, _cWhite,
  102.    _cPurp , _cPurp , _cGreen, _cWhite,
  103.    _cGreen, _cPurp , _cGreen, _cWhite,
  104.    _cPurp , _cGreen, _cGreen, _cWhite,
  105.  
  106.    _cGreen, _cWhite, _cGreen, _cWhite,
  107.    _cPurp , _cWhite, _cWhite, _cWhite,
  108.    _cGreen, _cWhite, _cWhite, _cWhite,
  109.    _cWhite, _cWhite, _cWhite, _cWhite
  110.    };
  111.  
  112.    const int FMalg2[]={
  113.    _cBlue , _cPurp , _cGreen, _cYell ,
  114.    _cPurp , _cPurp , _cGreen, _cYell ,
  115.    _cGreen, _cPurp , _cGreen, _cYell ,
  116.    _cPurp , _cGreen, _cGreen, _cYell ,
  117.  
  118.    _cGreen, _cYell , _cGreen, _cYell ,
  119.    _cPurp , _cYell , _cYell , _cYell ,
  120.    _cGreen, _cYell , _cYell , _cYell ,
  121.    _cYell , _cYell , _cYell , _cYell
  122.    };
  123.  
  124.    const int FMslots[]={0,2,1,3};
  125. /*
  126.    const int FMalg1[]={
  127.    _cPurp , _cGreen, _cCyan , _cWhite,
  128.    _cPurp , _cPurp , _cGreen, _cWhite,
  129.    _cGreen, _cPurp , _cCyan , _cWhite,
  130.    _cPurp , _cCyan , _cGreen, _cWhite,
  131.  
  132.    _cPurp , _cWhite, _cGreen, _cWhite,
  133.    _cPurp , _cWhite, _cWhite, _cWhite,
  134.    _cGreen, _cWhite, _cWhite, _cWhite,
  135.    _cWhite, _cWhite, _cWhite, _cWhite
  136.    };
  137.  
  138.    const int FMalg2[]={
  139.    _cPurp , _cGreen, _cCyan , _cYell ,
  140.    _cPurp , _cPurp , _cGreen, _cYell ,
  141.    _cGreen, _cPurp , _cCyan , _cYell ,
  142.    _cPurp , _cCyan , _cGreen, _cYell ,
  143.  
  144.    _cPurp , _cYell , _cGreen, _cYell ,
  145.    _cPurp , _cYell , _cYell , _cYell ,
  146.    _cGreen, _cYell , _cYell , _cYell ,
  147.    _cYell , _cYell , _cYell , _cYell
  148.    };
  149. */
  150.    if ( conf.sound.ay_chip == SNDCHIP::CHIP_YM2203 ) {
  151.       for (int ayN = 0; ayN < max_ay; ayN++) {
  152.          for (int i = 0; i < 3; i++) {
  153.             for (int j = 0; j < 4; j++) {
  154.                unsigned v=ay[ayN].Chip2203->CH[i].SLOT[j].vol_out;
  155.                if (v>1023) v=1023;
  156.                int c; //Alone Coder 0.36.7
  157.                for (/*int*/ c=0;c<16;c++)
  158.                   if (FMvols[c]>=v) break;
  159.                if ( (i == 2) && (((ay[ayN].Chip2203->OPN.ST.mode) & 0xc0) == 0x40) )
  160.                   paint_led(15-c, FMalg2[ay[ayN].Chip2203->CH[i].ALGO * 4 + FMslots[j]]);
  161.                else
  162.                   paint_led(15-c, FMalg1[ay[ayN].Chip2203->CH[i].ALGO * 4 + FMslots[j]]);
  163.             }
  164.          paint_led(0, 0);
  165.          }
  166.       }
  167.    } //Dexus
  168.  
  169.    #ifdef MOD_GS
  170.    if (sum || !conf.gs_type) return; // else show GS indicators
  171.    aypos = temp.led.ay; // reset y-pos, if nothing above
  172.    for (unsigned ch = 0; ch < 8; ch++) {
  173.       unsigned v = gsleds[ch].level, a = gsleds[ch].attrib;
  174.       paint_led(v, a);
  175.       paint_led(v, a);
  176.       paint_led(0, 0);
  177.    }
  178.  
  179.    #endif
  180. }
  181.  
  182. void load_led()
  183. {
  184.    char ln[20]; unsigned char diskcolor = 0;
  185.  
  186. #ifdef GS_BASS
  187.    if (gs.loadmod) {
  188.       text_i(temp.led.load, "", 0x0D);
  189.       gs.loadmod = 0;
  190.    } else if (gs.loadfx) {
  191.       sprintf(ln, "\x0D%d", gs.loadfx);
  192.       text_i(temp.led.load, ln, 0x0D);
  193.       gs.loadfx = 0;
  194.    } else
  195. #endif
  196.    if (trdos_format) {
  197.       diskcolor = (trdos_format < ROMLED_TIME*3/4) ? 0x06 : 0x0E;
  198.       trdos_format--;
  199.    } else if (trdos_save) {
  200.       diskcolor = (trdos_save < ROMLED_TIME*3/4) ? 0x02 : 0x0A;
  201.       trdos_save--;
  202.    } else if (trdos_load) {
  203.       diskcolor = (trdos_load < ROMLED_TIME*3/4) ? 0x01 : 0x09;
  204.       trdos_load--;
  205.    } else if (trdos_seek) {
  206.       trdos_seek--;
  207.    } else if (comp.tape.play_pointer) {
  208.       static unsigned char tapeled[11*2] = {
  209.          0x7F, 0xFE, 0x80, 0x01, 0x80, 0x01, 0x93, 0xC9, 0xAA, 0x55, 0x93, 0xC9,
  210.          0x80, 0x01, 0x8F, 0xF1, 0x80, 0x01, 0xB5, 0xA9, 0xFF, 0xFF };
  211.       const int tapecolor = 0x51;
  212.       for (int i = 0; i < 11; i++)
  213.          temp.led.load[pitch*i+0] = tapeled[2*i],
  214.          temp.led.load[pitch*i+1] = tapecolor,
  215.          temp.led.load[pitch*i+2] = tapeled[2*i+1],
  216.          temp.led.load[pitch*i+3] = tapecolor;
  217.       int time = (int)(temp.led.tape_started + tapeinfo[comp.tape.index].t_size - comp.t_states);
  218.       if (time < 0) {
  219.          find_tape_index(); time = 0;
  220.          temp.led.tape_started = comp.t_states;
  221.          unsigned char *ptr = tape_image + tapeinfo[comp.tape.index].pos;
  222.          if (ptr == comp.tape.play_pointer && comp.tape.index)
  223.             comp.tape.index--, ptr = tape_image + tapeinfo[comp.tape.index].pos;
  224.          for (; ptr < comp.tape.play_pointer; ptr++)
  225.             temp.led.tape_started -= tape_pulse[*ptr];
  226.       }
  227.       time /= (conf.frame * conf.intfq);
  228.       sprintf(ln, "%X:%02d", time/60, time % 60);
  229.       text_i(temp.led.load + pitch*12 - 2, ln, 0x0D);
  230.    }
  231.    if (diskcolor | trdos_seek) {
  232.       if (diskcolor) {
  233.          unsigned *ptr = (unsigned*)temp.led.load;
  234.          int i; //Alone Coder 0.36.7
  235.          for (/*int*/ i = 0; i < 7; i++, ptr = (unsigned*)((char*)ptr+pitch))
  236.             *ptr = (*ptr & WORD4(0,0xF0,0,0xF0)) | WORD4(0x3F,diskcolor,0xFC,diskcolor);
  237.          static unsigned char disk[] = { 0x38, 0x1C, 0x3B, 0x9C, 0x3B, 0x9C, 0x3B, 0x9C, 0x38,0x1C };
  238.          for (i = 0; i < 5; i++, ptr = (unsigned*)((char*)ptr+pitch))
  239.             *ptr = (*ptr & WORD4(0,0xF0,0,0xF0)) | WORD4(disk[2*i],diskcolor,disk[2*i+1],diskcolor);
  240.       }
  241.       if (comp.wd.seldrive->track != 0xFF) {
  242.          sprintf(ln, "%02X", comp.wd.seldrive->track*2 + comp.wd.side);
  243.          text_i(temp.led.load + pitch - 4, ln, 0x05 + (diskcolor & 8));
  244.       }
  245.    }
  246. }
  247.  
  248. static unsigned p_frames = 1;
  249. static u64 led_updtime, p_time;
  250. double p_fps;
  251. __inline void update_perf_led()
  252. {
  253.    u64 now = led_updtime - p_time;
  254.    if (now >= temp.cpufq) // єёЁхфэхэшх чр ёхъєэфє
  255.    {
  256.       p_fps = (p_frames * temp.cpufq) / double(now) + 0.005;
  257.       p_frames = 0;
  258.       p_time = led_updtime;
  259.    }
  260.    p_frames++;
  261. }
  262.  
  263. void perf_led()
  264. {
  265.    char bf[0x20]; unsigned PSZ;
  266.    if (conf.led.perf_t)
  267.       sprintf(bf, "%6d*%2.2f", cpu.haltpos ? cpu.haltpos : cpu.t, p_fps), PSZ = 7;
  268.    else
  269.       sprintf(bf, "%2.2f fps", p_fps), PSZ = 5;
  270.    text_i(temp.led.perf, bf, 0x0E);
  271.    if (cpu.haltpos) {
  272.       unsigned char *ptr = temp.led.perf + pitch*8;
  273.       unsigned xx; //Alone Coder 0.36.7
  274.       for (/*unsigned*/ xx = 0; xx < PSZ; xx++) *(unsigned short*)(ptr+xx*2) = 0x9A00;
  275.       unsigned mx = cpu.haltpos*PSZ*8/conf.frame;
  276.       for (xx = 1; xx < mx; xx++) ptr[(xx>>2)&0xFE] |= (0x80 >> (xx & 7));
  277.    }
  278. }
  279.  
  280. void input_led()
  281. {
  282.    if (input.kbdled != 0xFF) {
  283.       unsigned char k0 = 0x99, k1 = 0x9F, k2 = 0x90;
  284.       if (input.keymode == K_INPUT::KM_PASTE_HOLD) k0 = 0xAA, k1 = 0xAF, k2 = 0xA0;
  285.       if (input.keymode == K_INPUT::KM_PASTE_RELEASE) k0 = 0x22, k1 = 0x2F, k2 = 0x20;
  286.  
  287.       int i; //Alone Coder 0.36.7
  288.       for (/*int*/ i = 0; i < 5; i++)
  289.          temp.led.input[1+i*2*pitch] = temp.led.input[3+i*2*pitch] = k0;
  290.       for (i = 0; i < 4; i++)
  291.          temp.led.input[pitch*(2*i+1)] = 0x7F,
  292.          temp.led.input[pitch*(2*i+1)+2] = 0xFE;
  293.       temp.led.input[pitch*1+1] = (input.kbdled & 0x08)? k2 : k1;
  294.       temp.led.input[pitch*3+1] = (input.kbdled & 0x04)? k2 : k1;
  295.       temp.led.input[pitch*5+1] = (input.kbdled & 0x02)? k2 : k1;
  296.       temp.led.input[pitch*7+1] = (input.kbdled & 0x01)? k2 : k1;
  297.       temp.led.input[pitch*1+3] = (input.kbdled & 0x10)? k2 : k1;
  298.       temp.led.input[pitch*3+3] = (input.kbdled & 0x20)? k2 : k1;
  299.       temp.led.input[pitch*5+3] = (input.kbdled & 0x40)? k2 : k1;
  300.       temp.led.input[pitch*7+3] = (input.kbdled & 0x80)? k2 : k1;
  301.    }
  302.    static unsigned char joy[] =   { 0x10, 0x38, 0x1C, 0x1C, 0x1C, 0x1C, 0x08, 0x00, 0x7E, 0xFF, 0x00, 0xE7 };
  303.    static unsigned char mouse[] = { 0x0C, 0x12, 0x01, 0x79, 0xB5, 0xB5, 0xB5, 0xFC, 0xFC, 0xFC, 0xFC, 0x78 };
  304.    if (input.mouse_joy_led & 2)
  305.       for (int i = 0; i < sizeof joy; i++)
  306.          temp.led.input[4 + pitch*i] = joy[i],
  307.          temp.led.input[4 + pitch*i+1] = (temp.led.input[4 + pitch*i+1] & 0xF0) + 0x0F;
  308.    if (input.mouse_joy_led & 1)
  309.       for (int i = 0; i < sizeof mouse; i++)
  310.          temp.led.input[6 + pitch*i] = mouse[i],
  311.          temp.led.input[6 + pitch*i+1] = (temp.led.input[6 + pitch*i+1] & 0xF0) + 0x0F;
  312.    input.mouse_joy_led = 0; input.kbdled = 0xFF;
  313. }
  314.  
  315. #ifdef MOD_MONITOR
  316. void debug_led()
  317. {
  318.    unsigned char *ptr = temp.led.osw;
  319.    if (trace_rom | trace_ram) {
  320.       set_banks();
  321.       if (trace_rom) {
  322.          const unsigned char off = 0x01, on = 0x0C;
  323.          text_i(ptr + 2,           "B48", used_banks[(base_sos_rom - memory) / PAGE] ? on : off);
  324.          text_i(ptr + 8,           "DOS", used_banks[(base_dos_rom - memory) / PAGE] ? on : off);
  325.          text_i(ptr + pitch*8 + 2, "128", used_banks[(base_128_rom - memory) / PAGE] ? on : off);
  326.          text_i(ptr + pitch*8 + 8, "SYS", used_banks[(base_sys_rom - memory) / PAGE] ? on : off);
  327.          ptr += pitch*16;
  328.       }
  329.       if (trace_ram) {
  330.          unsigned num_rows = conf.ramsize/128;
  331.          unsigned j; //Alone Coder 0.36.7
  332.          for (unsigned  i = 0; i < num_rows; i++) {
  333.             char ln[9];
  334.             for (/*unsigned*/ j = 0; j < 8; j++)
  335.                ln[j] = used_banks[i*8+j]? '*' : '-';
  336.             ln[j] = 0;
  337.             text_i(ptr, ln, 0x0D);
  338.             ptr += pitch*8;
  339.          }
  340.       }
  341.       for (unsigned j = 0; j < MAX_PAGES; j++) used_banks[j] = 0;
  342.    }
  343.    for (unsigned w = 0; w < 4; w++) if (watch_enabled[w])
  344.    {
  345.       char bf[12]; sprintf(bf, "%8X", calc(&cpu, watch_script[w]));
  346.       text_i(ptr,bf,0x0F); ptr += pitch*8;
  347.    }
  348. }
  349. #endif
  350.  
  351. #ifdef MOD_MEMBAND_LED
  352. void show_mband(unsigned char *dst, unsigned start)
  353. {
  354.    char xx[8]; sprintf(xx, "%02X", start >> 8);
  355.    text_i(dst, xx, 0x0B); dst += 4;
  356.  
  357.    Z80 &cpu = CpuMgr.Cpu();
  358.    unsigned char band[128];
  359.    unsigned i; //Alone Coder 0.36.7
  360.    for (/*unsigned*/ i = 0; i < 128; i++) {
  361.       unsigned char res = 0;
  362.       for (unsigned q = 0; q < conf.led.bandBpp; q++)
  363.          res |= cpu.membits[start++];
  364.       band[i] = res;
  365.    }
  366.  
  367.    for (unsigned p = 0; p < 16; p++, dst+=2) {
  368.       unsigned char r=0, w=0, x=0;
  369.       for (unsigned b = 0; b < 8; b++) {
  370.          r *= 2, w *= 2, x *= 2;
  371.          if (band[p*8+b] & MEMBITS_R) r |= 1;
  372.          if (band[p*8+b] & MEMBITS_W) w |= 1;
  373.          if (band[p*8+b] & MEMBITS_X) x |= 1;
  374.       }
  375.  
  376.       unsigned char t = (p && !(p & 3))? 0x7F : 0xFF;
  377.  
  378.       dst[0*pitch] = t; dst[0*pitch+1] = 0x9B;
  379.  
  380.       dst[1*pitch] = r; dst[1*pitch+1] = 0x1C;
  381.       dst[2*pitch] = r; dst[2*pitch+1] = 0x1C;
  382.       dst[3*pitch] = w; dst[3*pitch+1] = 0x1A;
  383.       dst[4*pitch] = w; dst[4*pitch+1] = 0x1A;
  384.       dst[5*pitch] = x; dst[5*pitch+1] = 0x1F;
  385.       dst[6*pitch] = x; dst[6*pitch+1] = 0x1F;
  386.  
  387.       dst[7*pitch] = t; dst[7*pitch+1] = 0x9B;
  388.    }
  389.  
  390.    sprintf(xx, "%02X", (start-1) >> 8);
  391.    text_i(dst, xx, 0x0B, 2);
  392.  
  393.    for (i = 0; i < 8; i++)
  394.       dst[i*pitch] |= 0x80, dst[i*pitch - 17*2] |= 0x01;
  395. }
  396.  
  397. void memband_led()
  398. {
  399.    unsigned char *dst = temp.led.memband;
  400.    for (unsigned start = 0x0000; start < 0x10000;) {
  401.       show_mband(dst, start);
  402.       start += conf.led.bandBpp * 128;
  403.       dst += 10*pitch;
  404.    }
  405.  
  406.    Z80 &cpu = CpuMgr.Cpu();
  407.    for (unsigned i = 0; i < 0x10000; i++)
  408.       cpu.membits[i] &= ripper | ~(MEMBITS_R | MEMBITS_W | MEMBITS_X);
  409. }
  410. #endif
  411.  
  412.  
  413. HANDLE hndKbdDev;
  414.  
  415. void init_leds()
  416. {
  417.    DefineDosDevice(DDD_RAW_TARGET_PATH, "Kbd_unreal_spec", "\\Device\\KeyboardClass0");
  418.    hndKbdDev = CreateFile("\\\\.\\Kbd_unreal_spec", GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
  419.    if (hndKbdDev == INVALID_HANDLE_VALUE) hndKbdDev = 0, conf.led.flash_ay_kbd = 0;
  420. }
  421.  
  422. void done_leds()
  423. {
  424.    if (hndKbdDev) {
  425.       DefineDosDevice(DDD_REMOVE_DEFINITION, "Kbd_unreal_spec", 0);
  426.       CloseHandle(hndKbdDev); hndKbdDev = 0;
  427.    }
  428. }
  429.  
  430. void ay_kbd()
  431. {
  432.    static unsigned char pA, pB, pC;
  433.    static unsigned prev_keyled = -1;
  434.  
  435.    KEYBOARD_INDICATOR_PARAMETERS InputBuffer;
  436.    InputBuffer.LedFlags = InputBuffer.UnitId = 0;
  437.  
  438.    if (ay[0].get_reg( 8) > pA) InputBuffer.LedFlags |= KEYBOARD_NUM_LOCK_ON;
  439.    if (ay[0].get_reg( 9) > pB) InputBuffer.LedFlags |= KEYBOARD_CAPS_LOCK_ON;
  440.    if (ay[0].get_reg(10) > pC) InputBuffer.LedFlags |= KEYBOARD_SCROLL_LOCK_ON;
  441.  
  442.    pA = ay[0].get_reg(8), pB = ay[0].get_reg(9), pC = ay[0].get_reg(10);
  443.  
  444.    DWORD xx;
  445.    if (prev_keyled != InputBuffer.LedFlags)
  446.       prev_keyled = InputBuffer.LedFlags,
  447.       DeviceIoControl(hndKbdDev, IOCTL_KEYBOARD_SET_INDICATORS,
  448.                &InputBuffer, sizeof(KEYBOARD_INDICATOR_PARAMETERS), 0, 0, &xx, 0);
  449. }
  450.  
  451. void key_led()
  452. {
  453.    #define key_x 1
  454.    #define key_y 1
  455.    int i; //Alone Coder 0.36.7
  456.    for (/*int*/ i = 0; i < 9; i++) text_16(rbuf+(key_y+i)*pitch*16+key_x*2, "                                 ", 0x40);
  457.    static char ks[] = "cZXCVASDFGQWERT1234509876POIUYeLKJHssMNB";
  458.    for (i = 0; i < 8; i++) {
  459.       for (int j = 0; j < 5; j++) {
  460.          unsigned x, y, at;
  461.          if (i < 4) y = 7-2*i+key_y, x = 3*j+2+key_x;
  462.          else y = 2*(i-4)+1+key_y, x = 29-3*j+key_x;
  463.          unsigned a = ks[i*5+j]*0x100+' ';
  464.          at = (input.kbd[i] & (1<<j))? 0x07 : ((input.rkbd[i] & (1<<j)) ? 0xA0:0xD0);
  465.          text_16(rbuf+2*x+y*pitch*16,(char*)&a,at);
  466.       }
  467.    }
  468. }
  469.  
  470. void time_led()
  471. {
  472.    static u64 prev_time;
  473.    static char bf[8];
  474.    if (led_updtime - prev_time > 5000) {
  475.       prev_time = led_updtime;
  476.       SYSTEMTIME st; GetLocalTime(&st);
  477.       sprintf(bf, "%2d:%02d", st.wHour, st.wMinute);
  478.    }
  479.    text_i(temp.led.time, bf, 0x0D);
  480. }
  481.  
  482. // ┬√ч√трхЄё  Ёрч т ърфЁ
  483. void showleds()
  484. {
  485.    led_updtime = rdtsc();
  486.    update_perf_led();
  487.  
  488.    if (temp.vidblock) return;
  489.  
  490.    pitch = temp.scx/4;
  491.  
  492.    if (statcnt) { statcnt--; text_i(rbuf + ((pitch/2-strlen(statusline)*6/8) & 0xFE) + (temp.scy-10)*pitch, statusline, 0x09); }
  493.  
  494.    if (!conf.led.enabled) return;
  495.  
  496.    if (temp.led.ay) ay_led();
  497.    if (temp.led.perf) perf_led();
  498.    if (temp.led.load) load_led();
  499.    if (temp.led.input) input_led();
  500.    if (temp.led.time) time_led();
  501. #ifdef MOD_MONITOR
  502.    if (temp.led.osw) debug_led();
  503. #endif
  504. #ifdef MOD_MEMBAND_LED
  505.    if (temp.led.memband) memband_led();
  506. #endif
  507.    if (conf.led.flash_ay_kbd && hndKbdDev) ay_kbd();
  508.    if (input.keymode == K_INPUT::KM_KEYSTICK) key_led();
  509. }
  510.