Pull to refresh

Comments 41

Спасибо вам за прекрасную статью! Я прочитал её с громадным удовольствием.

Спасибо за ассемблер и разбор полётов. Сама программа гениальная и ваш разбор очень полезен.

Что-то меня так зацепил этот проект и то что вы написали, что можно уместить эту кривую на одном экране, что я чутка заморочился и модифицировал код (да, не 16 байт, но всё же). Теперь режим экрана 1024х768

    mov ax, 4F02h    ; VESA функция установки режима
    mov bx, 105h     ; 1024x768, 256 цветов
    int 10h          ; вызов VESA BIOS

    ; Инициализация регистров
    mov al, 1        ; цвет
    mov ah, 0Ch      ; функция вывода пикселя
    xor cx, cx
    xor dx, dx
    xor bx, bx       

S: 
    adc al,0x10
    sbb dx,cx       
    sar dx,0x01 
    adc dh,bl
    add cx,dx
    push dx
    push cx
    add dx, 375      ; смещение вниз
    add cx, 250      ; смещение вправо
    int 0x10
    pop cx
    pop dx
    mov ah,0x0C
    jmp short S

В результате получается такая красота:

Но по-русски правильно именно «16 байтов» (потому что «16 килограммов помидоров», а не «16 килограмм помидор»).

Нашёл тут:

Подскажите, пожалуйста, правильный вариант: количество байтов в секторе или количество байт в секторе? С уважением, anjolie.

ответ

Верен первый вариант.

как раз тот случай, когда "гляжу в книгу, вижу фигу"

Вот именно, поэтому ваше замечание было некорректно.

Вас не затруднит привести авторитетный источник на тему этой вашей «счётной формы»?

Ответам на грамоте.ру мы все, конечно же, доверяем, но всё же хотелось бы ссылку на академическую работу по языкознанию. И желательно из прошлого века.

16 байт - довольно таки условно, ибо за int 10 скрывается еще не один десяток, а может и сотен.

Не. Это просто запись в VRAM. А установка видео-режима - пара команд IO. Так что без BIOS'a добавится с дюжину инструкций.

Ещё можно микрокод вспомнить и количество транзисторов в процессоре. Это все таки именно 16 байт. Демки и на JS бывают, от этого они не перестают быть искусством.

Вы озадачили проверить, можно ли убрать int 10h. В результате набросал следующую функцию:

paint_f:
    push ax          
    push bx
    push cx
    push dx
    push si         
    
    ; Проверка границ экрана
    cmp cx, 320
    jae skip_paint
    cmp dx, 200
    jae skip_paint
    
    mov si, ax      ; Сохраним AX
    
    mov ax, dx       ; Y координата
    mov bx, 320      ; Ширина экрана
    mul bx           ; AX = Y * 320
    add ax, cx       ; AX = Y * 320 + X
    mov di, ax       ; DI = смещение
    
    mov ax, si       ; Восстановим AX
    mov es:[di], al  ; Записываем цвет

skip_paint:
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    ret

А в основной программе вызов её осуществляется следующим образом:

    pushf
    call paint_f
    popf

Возможно код немного избыточен и не идеален, но результат работы вот:

Полученный размер, с учётом добавлений: 82 байта. Что, на мой взгляд, очень мало. Более того, это я быстренько набросал, думаю можно всё ужать.

Так просто будет только в 256-цветных режимах. В 16-цветных каждый из 4 битов цвета придётся по отдельности записывать по разным адресам, комбинируя со значениями 8 соседних пикселей в строке. Если поискать по старым фидошным эхам, то наверняка и FAQ и примеры найдутся.

Флаги редко когда сохраняют, разве что при входе в обработчик прерывания. Здесь, думаю, тоже можно их не сохранять/не восстанавливать. Цвета пикселей чуть поменяются да и только.

И у вас не показана инициализация регистра es, туда нужно 0a000h положить, иначе мы свой код перепишем.

Вы же вроде автор статьи.

Флаги редко когда сохраняют, разве что при входе в обработчик прерывания. Здесь, думаю, тоже можно их не сохранять/не восстанавливать. Цвета пикселей чуть поменяются да и только.

Цитирую вас же:

Самая загадочная здесь, пожалуй, переменная flag: её значение получается как побочный эффект других вычислений и при этом она играет неясную, но очень важную роль.

Проще говоря, вы можете попробовать перестать сохранять флаги и магия перестанет работать.

И у вас не показана инициализация регистра es, туда нужно 0a000h положить, иначе мы свой код перепишем.

Согласен.

Признаюсь, при написании комментария поленился проверить и понадеялся, что уровень случайности значения CF пострадает не сильно.

Сейчас всё же проверил и да, тут без pushf / popf не обойтись. Но можно их занести внутрь функции, call / ret флаги не меняют. А пачку push / pop заменить на пару pusha / popa, у нас же size coding? )

Тут можно ещё поколдовать с оптимизацией :).

По ИМХО главная ценность статьи - краткое но ёмкое введение в ассемблер.
+/+

PS Если кто знает хорошие материалы с краткими начальными курсами ассемблера подсыпьте ссылочек плzzz.

PS Если кто знает хорошие материалы с краткими начальными курсами ассемблера подсыпьте ссылочек плzzz.

Вопрос в том, подо что писать. И вообще зачем изучать сейчас ассемблер? Вопрос с подвохом, если вам нужно писать драйвера устройств под Linux, то достаточно общих сведений, потому что идёт потом всё в си. Если DOS (зачем...), то другое. ИМХО, если у вас нет чёткой задачи, то он вам не нужен.

Мне он нужен в учебных целях. Учить началам программирования детей. Книгу Дракона они, увы, сразу не тянут (проверено).

...Да и может ли Software Engineer считаться таковым не зная устройства процессора? (вопрос без подвоха)

Она. Алиса Селезнёва. :)

Только, как и всякий Талмуд, его полностью читать не надо. Нужно выбирать только те куски, которые нужно. :)

Я запутался.
Если мы хотим научить ассемблеру, то книга по построению компиляторов нам ничем не поможет. Там ассемблер если и упоминается, то в главе про генерацию кода и без привязки к конкретной платформе.

Если мы хотим научить писать компиляторы, то ученик уже должен владеть каким-нибудь ЯП.

К слову, вспомнил одну современную книгу про компиляторы в которой ассемблер всё же присутствует, но там ARM. Есть онлайн-версия, можете полистать.

https://keleshev.com/compiling-to-assembly-from-scratch/

Всегда удивляло желание учить детей не нужным наукам. Ассемблер вреден и не нужен в данный момент.

Пожалуйста, не издевайтесь над детьми. Если уж так хочется показать как работает процессор, то покажите ассемблер для AVR.

Так я ж своих, а не Ваших и не "абстрактных детей" учу. Предвзято и для себя любимого. :)

PS Что до тех ассемблеров, так там в базе 4 арифметических операции, 6 побитовых, ~4 для записи в память/регистры, ~4 - на ветвления и подпроцедуры. Что там учить?! :)

Не бывает ваших и наших детей. Бывают просто дети.

В любом случае, чтобы советовать хорошую книгу по ассемблеру, надо понимать конечную задачу.

Не бывает ваших и наших детей. Бывают просто дети.

Это Вы хорошо сказали. Как раз в тему, на глаза попалось:

*

Правда всегда немногословна. Ложь - да.
Нужно жалеть или не нужно жалеть — так ставят вопрос фальшивые люди.
Восславим тех, кто перестал врать.
Если тебе удалось обмануть человека, то это не значит, что он дурак. Это лишь значит, что тебе доверяли больше, чем ты того заслуживаешь.
Не старость сама по себе уважается, а прожитая жизнь. Если она была.

Василий Шукшин

Я имел в виду, что большинство педагогов на бюджете учат "абстрактных детей" и "абстрактных студентов" - им то самим ни те и ни эти не нужны. Отсидел своё ученик - иди на улицу, заходи следующий. В общем, готовят специалистов не для себя, а для улицы. А у меня же - другое.

Цель - проста и пряма как дорога в рай: писать свои языки в итоге. Промежуточным уровнем при этом сидит интерпретатор байткода или vm-ка. Вот и хотелось бы научить ученика в 4-5 занятий писать процессор с системой команд. Просто и ясно, без раздутых книг.

Достойная задача. Но вряд ли помогу.

Возможно всё же стоит взять более простой процессор. Потому что x86 даже для меня зубодробительный. Если выйти за 16-битный режим реального времени, то там даже не каждый студент технического ВУЗа сдюжит архитектуру, а если сюда прикрутить всякие микрокоды то вообще. А если вспомнить что есть ещё 64-х битный режим, ууу. А недокументированные режимы, уууу.

Напомню и про чудесный godbolt / Compiler Explorer. Слева можно вводить код на разных языках, а справа изучать скомпилированный результат на разных asm.

Прочитал про эту статью в телеграм канале @dlinyj и по его совету публикую мою реализацию для БК0010:

.org 1000
start:
clr r0
clr r1
clr r2
clr r3
0loop:
add r0, 0x10
tst r3
beq 1
inc r0
1:
clr r3
cmp #377, r0
ble 2
inc r3
2:
bic #177400, r0
sub r1, r2
tst r3
beq 3
inc r2
3:
clr r3
bit #1, r2
beq 4
inc r3
4:
asr r2
tst r3
beq 5
add #400, r2
5:
clr r3
add r2, r1
bcc 6
inc r3
6:
push r1
push r2
asr r1
asr r1
asr r2
asr r2
add #100, r1
add #200, r2
call draw_point
pop r2
pop r1
br 0loop

draw_point:
push r0
push r1
push r2
push r3
push r4
mov #177400, r3
bic r3, r1
bic r3, r2
movb #0b11111100, r3
bicb r3, r0
asl r0
asl r0
mov r1, r4
bicb r3, r4
add r4, r0
movb dp_color(r0), r0
movb dp_mask(r4), r4
asr r1
asr r1
swab r2
ror r2
ror r2
add #40000, r1
add r2, r1
movb (r1), r3
bicb r4, r3
bisb r0, r3
movb r3, (r1)
pop r4
pop r3
pop r2
pop r1
pop r0
ret
dp_color:
.byte 0b00000000
.byte 0b00000000
.byte 0b00000000
.byte 0b00000000
.byte 0b00000001
.byte 0b00000100
.byte 0b00010000
.byte 0b01000000
.byte 0b00000010
.byte 0b00001000
.byte 0b00100000
.byte 0b10000000
dp_mask:
.byte 0b00000011
.byte 0b00001100
.byte 0b00110000
.byte 0b11000000
.end

P.S. Никак не мог отформатировать, пытался несколько раз, превью не работало, показывало всплывашку "Запрос уже был обработан", и кнопки Отправить и Предпросмотр не работали.

@admin есть ли возможность поправить?

Нужна инструкция, как ассемблировать исходник и получить заветный dragon.bin.

Для этого использовал кросс-ассемблер который есть в поставке эмулятора https://gid.pdp-11.ru/bkemu.html.

  1. Качаем, распаковываем (например, в папку D:\BK_v3_13).

  2. Сохраняем код в "dragon.asm".

  3. Из командной строки из папки где лежит файл "dragon.asm" вызываем "D:\BK_v3_13\BKTurbo8\BKTurbo8_x64.exe -l CO dragon.asm". Будет создан "dragon.bin".

  4. Запускаем эмулятор и выбираем в меню "Конфигурация" пункт "Старт БК 0010-01" (если не выбран).

  5. Выходим из Бейсика в Монитор, для этого набираем английскими буквами без кавычек: "MO" [ENTER], после знака вопроса набираем "M" [ENTER], появится запрос имени, тут просто [ENTER], появится диалоговое окно с выбором файла, находим "dragon.bin", нажимаем "Open", файл загрузится в память и появится знак вопроса, и наконец запускаем: "S" [ENTER].

Скорость можно повысить в меню "Управление".

Sign up to leave a comment.

Articles