Важная информация

User Tag List

Страница 1 из 3 123 ПоследняяПоследняя
Показано с 1 по 10 из 27

Тема: Печать двухбайтового числа без знака и со знаком в машкоде

  1. #1
    Veteran Аватар для Oleg N. Cher
    Регистрация
    24.08.2007
    Адрес
    Днепропетровская обл.
    Сообщений
    1,596
    Спасибо Благодарностей отдано 
    2,180
    Спасибо Благодарностей получено 
    137
    Поблагодарили
    103 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию Печать двухбайтового числа без знака и со знаком в машкоде

    Господа, знаю, что тема замусоленная и многократно поднималась много где, в т.ч. и в прессе. Это "по мотивам" процедуры Сержа Колотова, претендует на высокую эффективность. Но, видя чудеса кодинга, вполне верю в конструктивную критику. :-) Критикуем, господа. Вывод делается средствами ПЗУ.

    Код:
    /*--------------------------------- Cut here ---------------------------------*/
    void Basic_PRCHAR_ROM (unsigned char ch) __z88dk_fastcall {
    __asm
              LD   IY,#0x5C3A
              LD   A,L
              EX   AF,AF
              LD   A,#2
              CALL 0x1601
              EX   AF,AF
              RST  0x10
    __endasm;
    } //Basic_PRCHAR_ROM
    
    /*--------------------------------- Cut here ---------------------------------*/
    void Basic_PRWORD_ROM (unsigned int n) __naked __z88dk_fastcall {
    __asm
              LD    IY,#0x5C3A
    /* Из журнала Deja Vu #04, Кемерово, 01.04.98
        (c) Колотов Сеpгей, г.Шадpинск, SerzhSoft
    Доработано для печати только значащих цифр */
    ;----------------------------------------;
    ;Печать десятичного числа в HL (0..65535)
    ;----------------------------------------;
              PUSH  HL            ;закинули печатаемое число на стек
              LD    A,#2          ;открываем канал 2
              CALL  #0x1601       ;(печать в области основного экрана)
              LD    HL,#DECTB_W$  ;адрес таблицы степеней десятки
              LD    BC,#0x505     ;макс. возможное количество цифр: 5
              ;установим также рег. C - кол-во незначащих нулей + 1
    LP_PDW1$: XOR   A             ;обнулили счётчик и флаг C для SBC
              LD    E,(HL)        ;взяли текущую степень
              INC   HL            ; десятки из таблицы
              LD    D,(HL)        ; и поместили в DE
              INC   HL            ;перешли к след. элементу таблицы
              EX    (SP),HL       ;адрес эл-та <-> печатаемое число
    LP_PDW2$: INC   A             ;увеличиваем счётчик
              SBC   HL,DE         ;вычитаем текущую степень десятки
              JR    NC,LP_PDW2$   ;повторяем пока HL>=0
              ADD   HL,DE         ;HL=HL mod DE; A=HL div DE
              DEC   C             ;проверяем: может это незначащий нуль?
              JR    Z,LP_PRNT$    ; если уже были другие цифры, печатаем
              DEC   A             ;если это нуль, то он незначащий
              JR    Z,LP_NOPR$    ; ничего не печатаем
              INC   A             ;это не нуль, увеличим на 1 для печати
    LP_PRNT$: ADD   A,#"0"-1      ;перевод A в ASCII-код ("0".."9")
              RST   0x10          ;печать десятичной цифры
              LD    C,#1          ;уже была печать, дальше все значащие
    LP_NOPR$: EX    (SP),HL       ;HL=адрес эл-та, число -> на стек
              DJNZ  LP_PDW1$      ;цикл по цифрам
              POP   HL            ;убрали оставшийся ноль со стека
              RET                 ;выход из процедуры
    ;----------------------------------------;
    DECTB_W$: .DW   10000,1000,100,10,1  ;Таблица степеней десятки;
    ;----------------------------------------;
    __endasm;
    } //Basic_PRWORD_ROM
    
    /*--------------------------------- Cut here ---------------------------------*/
    void Basic_PRINT_ROM (int n) __naked __z88dk_fastcall {
    __asm
              BIT   7,H
              JP    Z,_Basic_PRWORD_ROM
              EX    DE,HL
              XOR   A
              LD    L,A
              LD    H,A
              SBC   HL,DE
              PUSH  HL
              LD    L,#0x2D
              CALL  _Basic_PRCHAR_ROM
              JP    _Basic_PRWORD_ROM+10
    __endasm;
    } //Basic_PRINT_ROM
    P.S. Зависимость Basic_PRINT_ROM от Basic_PRCHAR_ROM не критикуем, прямой вставкой не заменяем. Так задумано ;-)

  2. #1
    С любовью к вам, Yandex.Direct
    Размещение рекламы на форуме способствует его дальнейшему развитию

  3. #2
    Veteran Аватар для Oleg N. Cher
    Регистрация
    24.08.2007
    Адрес
    Днепропетровская обл.
    Сообщений
    1,596
    Спасибо Благодарностей отдано 
    2,180
    Спасибо Благодарностей получено 
    137
    Поблагодарили
    103 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Переписал с применением подпрограммы ПЗУ PRINT-FP. Скорость будет ниже, зато код компактнее. Всё равно печать с помощью RST 16 сама по себе довольно медленная.

    Код:
    /*--------------------------------- Cut here ---------------------------------*/
    void Basic_PRCHAR_ROM (unsigned char ch) __z88dk_fastcall {
    __asm
      LD   A,L
      LD   IY,#0x5C3A
      EX   AF,AF
      LD   A,#2
      CALL 0x1601
      EX   AF,AF
      RST  16
    __endasm;
    } //Basic_PRCHAR_ROM
    
    /*--------------------------------- Cut here ---------------------------------*/
    void Basic_PRWORD_ROM (unsigned int n) __naked __z88dk_fastcall {
    __asm
      LD   C,L
      LD   B,H
      CALL 0x2D2B // BC-TO-FP
      LD   A,#2
      CALL 0x1601
      JP   0x2DE3 // PRINT-FP
    __endasm;
    } //Basic_PRWORD_ROM
    
    /*--------------------------------- Cut here ---------------------------------*/
    void Basic_PRINT_ROM (int n) __naked __z88dk_fastcall {
    __asm
        BIT   7,H
        JP    Z,_Basic_PRWORD_ROM
        
        ; HL := -HL
        EX    DE,HL ;  4
        XOR   A     ;  4
        LD    L,A   ;  4
        LD    H,A   ;  4
        SBC   HL,DE ; 15 => 31t
    
        PUSH  HL
        LD    A,#0x2D
        CALL  _Basic_PRCHAR_ROM+1
        POP   BC
        JP    _Basic_PRWORD_ROM+2
    __endasm;
    } //Basic_PRINT_ROM
    Приветствуются любые замечания по сокращению кода.

    P.S. Можно ускорить смену знака на один такт. Вместо:
    Код:
    ;      HL := -HL
        EX    DE,HL ;  4
        XOR   A     ;  4
        LD    L,A   ;  4
        LD    H,A   ;  4
        SBC   HL,DE ; 15 => 31t
    использовать:
    Код:
        LD    A,L   ;  4
        CPL         ;  4
        LD    L,A   ;  4
        LD    A,H   ;  4
        CPL         ;  4
        LD    H,A   ;  4
        INC   HL    ;  6 => 30t
    Но это не даст никакого ощутимого выигрыша, всё равно PRINT-FP использует медленный калькулятор. Но менее компактно (7 байт против 6).

  4. #3
    Super Moderator Аватар для Alex Rider
    Регистрация
    07.02.2008
    Адрес
    г. Рязань
    Сообщений
    2,908
    Спасибо Благодарностей отдано 
    29
    Спасибо Благодарностей получено 
    89
    Поблагодарили
    31 сообщений
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Oleg N. Cher Посмотреть сообщение
    LD A,#2
    CALL 0x1601
    А зачем при печати каждого символа звать CHAN-OPEN? Там же хренотуча кода, который выполняется не шустро ни разу. Я бы в либах вообще отказался от работы с другими каналами, кроме S (экран). Для этого надо:
    1. Открывать канал S при нинциализации приложения;
    2. Переписать CLS (штатная беузмно тормозная) чтобы канал не сбрасывался в K;
    3. Переписать AT чтобы можно было указывать 23 и 24 строки.
    4. Убрать CHAN-OPEN из печати символа. Если в либах поддерживается вызов INPUT (нужен пример реализации?), то открывать S после этого INPUT.

    Самописные CLS и AT получатся весьма компактными, а выгода по скорости будет весьма неплохая.

    - - - Добавлено - - -

    UPD: Если не поддерживать пользовательские каналы, то вместо RST 16 можно звать 09F4 - сэкономится куча тактов и не попортится DE'
    ZX Evolution Rev C + ZXM-SoundCard Extreme + NeoGS.

  5. #4
    Veteran Аватар для Oleg N. Cher
    Регистрация
    24.08.2007
    Адрес
    Днепропетровская обл.
    Сообщений
    1,596
    Спасибо Благодарностей отдано 
    2,180
    Спасибо Благодарностей получено 
    137
    Поблагодарили
    103 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    CHAN-OPEN звать при печати каждого символа чтобы не пихать код открытия канала в общий инициализатор библиотеки. Отдельный инициализатор печати, нужный только для печати кодом из ПЗУ, видится лишним нагромождением, особенно когда печать из ПЗУ вообще не юзается. И не такая уж CHAN-OPEN и тормозная.

    Печать кодом из ПЗУ - это только одна из опций. Если бы ты знал архитектуру библиотеки Basic, то знал бы, что там есть ещё один способ печати - включается убиранием #define ROM_OUTPUT в файле конфигурации BasicCfg.h, который может присутствовать в собственном проекте или же отсутствовать (в этом случае используется стандартная конфигурация по умолчанию - ZXDev/Lib/BasicCfg.h).

    Опция ROM_OUTPUT поддерживается ТОЛЬКО для тех случаев, когда нужна компактность, а скорости хватает. Если её закомментировать, то подключаются самописные быстрые AT, CLS и вывод работает во всём экране, включая нижние строки.

    Библиотека Console предоставляет ещё один дополнительный способ печати из трёх:

    Код:
    /* Use ROM output (RST 10H, slow, 32x22) or COMPACT/FAST (fast, 32x24) */
    
    //#define Console_OUTPUT_COMPACT
    //#define Console_OUTPUT_FAST
    #define Console_OUTPUT_ROM
    #09F4 - печатает всегда в канал 2 ?
    Последний раз редактировалось Oleg N. Cher; 04.01.2017 в 03:13.

  6. #5
    Super Moderator Аватар для Alex Rider
    Регистрация
    07.02.2008
    Адрес
    г. Рязань
    Сообщений
    2,908
    Спасибо Благодарностей отдано 
    29
    Спасибо Благодарностей получено 
    89
    Поблагодарили
    31 сообщений
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Oleg N. Cher Посмотреть сообщение
    И не такая уж CHAN-OPEN и тормозная.
    CHAN-OPEN: 524 такта для канала 2
    RST 16: 1961 такт.
    CHAN-OPEN жрет 1/5 общего времени вызова.
    Цитата Сообщение от Oleg N. Cher Посмотреть сообщение
    Отдельный инициализатор печати, нужный только для печати кодом из ПЗУ, видится лишним нагромождением, особенно когда печать из ПЗУ вообще не юзается.
    Не очень я это понимаю. Потратить 524 такта в инициализации - лишнее нагроможение, а при печати каждого символа - норм.

    Цитата Сообщение от Oleg N. Cher Посмотреть сообщение
    #09F4 - печатает всегда в канал 2 ?
    Нет, она является процедурой вывода для каналов K, S, P. Экономия по сравнению с RST 16 в том, оно не шарится по таблицам каналов чтобы сделать в конце концов переход на 09F4.
    Если использовать 09F4, то открывать S можно вызовом 1642 (аргументы ей не нужны, будет работать чуть шустрее):
    1642: 207 тактов, не надо инициализировать A, использует только A, H, L - символ для печати можно сохранить в регистре просто.
    09F4: 1857 тактов

    Код:
    void Basic_PRCHAR_ROM (unsigned char ch) __z88dk_fastcall {
    __asm
      LD   E,L
      LD   IY,#0x5C3A
      CALL 0x1642
      LD   A,E
      CALL 0x09F4
    __endasm;
    } //Basic_PRCHAR_ROM
    Но лучше все же CALL 0x1642 с его 207 тактами убрать в инициализатор и в CLS.

    PS INPUT у вас реализован? Надо пример?
    Последний раз редактировалось Alex Rider; 04.01.2017 в 11:07.
    ZX Evolution Rev C + ZXM-SoundCard Extreme + NeoGS.

  7. #6
    Veteran Аватар для Oleg N. Cher
    Регистрация
    24.08.2007
    Адрес
    Днепропетровская обл.
    Сообщений
    1,596
    Спасибо Благодарностей отдано 
    2,180
    Спасибо Благодарностей получено 
    137
    Поблагодарили
    103 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Alex Rider Посмотреть сообщение
    Не очень я это понимаю. Потратить 524 такта в инициализации - лишнее нагроможение, а при печати каждого символа - норм.
    Ну можно конечно сделать в Basic.Init отдельную секцию, открывающую канал 2 при включенной опции ROM_OUTPUT. Сделаю.

    Кстати, а как можно реализовать CLS? Есть варианты, превосходящие LDIR по скорости? (10 кб кода на очистку экрана во фрейм не рассматриваем, код нужен по возможности компактный).

    Цитата Сообщение от Alex Rider Посмотреть сообщение
    PS INPUT у вас реализован? Надо пример?
    Пример не помешает.

    У нас есть Console.ReadInt и ReadIntRange(min, max) для всего экрана (а не для канала 0), но он простенький.

  8. #7
    Master Аватар для SaNchez
    Регистрация
    22.12.2007
    Адрес
    г. Владивосток
    Сообщений
    915
    Спасибо Благодарностей отдано 
    0
    Спасибо Благодарностей получено 
    12
    Поблагодарили
    6 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Oleg N. Cher Посмотреть сообщение
    Кстати, а как можно реализовать CLS? Есть варианты, превосходящие LDIR по скорости? (10 кб кода на очистку экрана во фрейм не рассматриваем, код нужен по возможности компактный).
    Вариант средний по скорости и длине:
    Код:
          ld hl,#4000
          ld de,#4001
          ld bc,#1800
          ld (hl),0
    loop1 dup 32
          ldi
          edup
          jp pe,loop1
          ld bc,#300
          ld (hl),7; байт атрибута
    loop2 dup 32
          ldi
          edup
          jp pe,loop2
          ret
    Последний раз редактировалось SaNchez; 04.01.2017 в 17:06. Причина: исправил косяк в выводе атрибутов

  9. #8
    Member
    Регистрация
    25.11.2015
    Адрес
    г. Москва
    Сообщений
    192
    Спасибо Благодарностей отдано 
    12
    Спасибо Благодарностей получено 
    16
    Поблагодарили
    14 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Oleg N. Cher Посмотреть сообщение
    LP_PDW2$: INC A ;увеличиваем счётчик SBC HL,DE ;вычитаем текущую степень десятки JR NC,LP_PDW2$ ;повторяем пока HL>=0 ADD HL,DE ;HL=HL mod DE; A=HL div DE
    Если оптимизировать это по скорости, то нужно поменять SBC на ADD и знак у чисел в таблице, кроме этого JR стоит заменить на JP. Или вообще взять и развернуть цикл:
    Код:
    ADD HL,DE
    JR NC,DIV_2
    INC A
    ADD HL,DE
    JR NC,DIV_2
    INC A
    ADD HL,DE
    JR NC,DIV_2
    INC A
    ADD HL,DE
    JR NC,DIV_2
    INC A
    ADD HL,DE
    DIV_2:
    ADD HL,HL
    ADD A,A
    SBC HL,DE
    JR C,DIV_1
    INC A
    SBC HL,DE
    DIV_1:
    Только для такого развёрнутого цикла таблица констант требуется другая: -20000, -4000, -800, -160, -32, хотя конечно последний элемент таблицы не нужен, поскольку последняя цифра в том или ином виде в HL уже есть.
    Последний раз редактировалось blackmirror; 04.01.2017 в 15:24.

  10. #9
    Veteran
    Регистрация
    08.01.2007
    Адрес
    г. Красноярск
    Сообщений
    1,262
    Спасибо Благодарностей отдано 
    264
    Спасибо Благодарностей получено 
    1,404
    Поблагодарили
    277 сообщений
    Mentioned
    7 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Цитата Сообщение от Oleg N. Cher Посмотреть сообщение
    Кстати, а как можно реализовать CLS? Есть варианты, превосходящие LDIR по скорости? (10 кб кода на очистку экрана во фрейм не рассматриваем, код нужен по возможности компактный).
    Компактно и быстро:

    LD D,7;цвет атрибутов
    LD B,6
    LD HL,0
    ADD HL,SP
    LD SP,#5b00
    cls LD E,D
    PUSH DE;повторить 64 раза
    DJNZ $-64
    LD A,D
    OR A
    LD D,B
    LD B,48
    JR NZ,cls
    LD SP,HL
    RET

  11. #10
    Master Аватар для SaNchez
    Регистрация
    22.12.2007
    Адрес
    г. Владивосток
    Сообщений
    915
    Спасибо Благодарностей отдано 
    0
    Спасибо Благодарностей получено 
    12
    Поблагодарили
    6 сообщений
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Ну это до тех пор, пока вдруг стек не укажет на ROM

Страница 1 из 3 123 ПоследняяПоследняя

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Похожие темы

  1. Вычисление числа Пи на ассемблере
    от perestoronin в разделе Разное
    Ответов: 311
    Последнее: 12.02.2024, 17:12
  2. ABS и SGN в машкоде
    от Oleg N. Cher в разделе Программирование
    Ответов: 19
    Последнее: 10.01.2017, 04:14
  3. Мнемокоманды и числа.
    от ALKO в разделе Программирование
    Ответов: 0
    Последнее: 15.02.2014, 03:49
  4. Определение числа сторон
    от mungo в разделе Внешние накопители
    Ответов: 1
    Последнее: 16.03.2012, 18:06
  5. Дисковод Sankyo - кому знаком?
    от nikor4 в разделе Внешние накопители
    Ответов: 3
    Последнее: 07.10.2011, 06:19

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •