Немного подшаманил дизассемблер. Следующая итерация бейсика 5.29: см. дальше.
Вид для печати
Немного подшаманил дизассемблер. Следующая итерация бейсика 5.29: см. дальше.
В 2.97 закралась ошибка в поиск строк, пофиксил. Очень специфическая, в готовых программах она не проявляется, поэтому не находил тестами. На нее можно наткнуться набирая программу в самом бейсике при хитром порядке номеров. Есть и хорошая новость - после исправления и доработки скорость не ухудшилась, а даже микроскопически улучшились (обновлять результаты тестов не стал, принципиальной разницы нет).
Больше тестов хороших и разных. Решето Эратосфена.
Скрытый текст
Код:10 DIM BS(500)
20 N=500
30 FOR I=2 TO N
40 IF BS(I)=0 THEN PRINT I;
50 J=1
60 IF I*J<=N THEN BS(I*J)=1:J=J+1:GOTO 60
70 NEXT
80 STOP
[свернуть]
Пробелы между операторами для совместимости с 5.29. 4.51 и 5.29 тестировал в Т-34.
4.51 (одинарн) - 49.96 секунды
4.51 (целые) - 41 секунда
5.29 (одинарн) - 46.58 секунды
5.29 (целые) - 36.58 секунды
2.5 - 46.55 секунды
2.891 - 39.38 секунды
2.995 - 20.2 секунды
2.996 - 19.47 секунды
Вклад вывода чисел на экран можно оценить сравнив с результатами без PRINT I (4.51 не позволил оставить просто THEN, поэтому тут его результатов нет)
5.29 (одинарн) - 45.24 секунды
5.29 (целые) - 35.7 секунды
2.5 - 44.61 секунды
2.97fix - 29.86 секунды
2.98 - 18.71 секунды
Полез смотреть целочисленную арифметику в 5.29 и понял, что с целыми придется частично перетестировать. В продвинутых микрософтовских бейсиках есть отдельное целочисленное деление \. Т.е. когда есть деление для перехода на полноцелочисленность не хватает DEFINT, надо менять / на \. И я ведь когда-то читал про это, но не придал особого значения, а разница весьма заметная. Деление используется в RFBM3-7 (в решете деления нет). RFBM3 выдает переполнение с \, там остается /. Результаты RFBM4-7 с \ добавил в таблицу. Но 2.97 не сдается даже когда в 4.51/5.29 используется \, в 2 тестах из 4 он впереди. Целочисленную арифметику в 5.29 по скорости особо не оптимизировали и в 4.51 явно не лучше, там большие резервы.
Подчистил "фантомные" метки в командах LXI (т.е. где должна быть константа). Наверное, больше уже ничего делать не буду.
Финальный дизасм бейсика 5.29: Вложение 78970
Арифметика с одинарной точностью в 5.29 оказалась несколько интереснее, чем ожидал.
Отличия от альтаирского 3.2 (и векторовского 2.5):
1. В цикл умножения добавили sticky bit, вероятно под влиянием IEEE, это немного замедляет умножение по сравнению с 3.2 и 2.5.
2.1. В деление добавили проверки при начальном увеличении экспоненты. Хорошая вещь, 3.2 и 2.5 могут пропустить переполнение при делении.
2.2. В окончании деления громоздко и коряво формируют троицу: guard bit, round bit, sticky bit, но дальше переходят на округление, где, как и в ранних версиях, учитывают только guard bit. Это или забывчивость или даже не знаю, как назвать.
3. Добавили оптимизацию частных случаев (когда есть нули) в сдвигах мантиссы вправо и влево. Тут я оказывается попал в тренд, в своих модификациях оптимизировал сдвиги вправо (и на мой субъективный взгляд сделал это лучше). Сдвиги влево пробовал менять, но в итоге в релиз не включил (не хватало места). Наверно зря, особенно если сравнить с тем, как в 5.29, надо было изыскать резервы. Кстати, в отличие от умножения и деления, в сдвиги вправо sticky bit не добавили.
4. У меня сложилось впечатление, что модификаторы бейсика совсем не напрягались. Для примера вместо того, чтобы убрать в нормализации лишнюю команду, которая ошибочно там оставалась с 3.2 (просто занимала 1 байт места и время на выполнение) они "исправили" ее на 3х байтовую, молодцы. Ну и они оставили некоторые старые неоптимальные решения, на мой взгляд бросающиеся в глаза, и добавили своих еще менее впечатляющих.
По пробелам чемпион 4.51, там можно пробелы и в именах переменных, как в 3.2 (и 2.5+) и во всяких GO*UB, как в 5.29. А в 5.29 ужесточили с именами переменных. Думаю это один из источников ускорения 5.29, пробовал так делать в своей модификации - становится немного быстрее.
Извращенцы:
L0FBE сравнивает строки, только вот L1305 пропускает одну букву. При таком раскладе должно было работать GO ATO, но вместо этого получается GOSUB (JZ L0FB8 явно переходит на пару байт раньше). Победить не смогли, поэтому просто добавили GO TO в таблицу операторов:Код:PUSH H
LXI D,L0FCC
CALL L0FBE
JNZ L0FD6
CALL L1305
LXI D,L0FD0
CALL L0FBE
MVI A,89h
JZ L0FB8
LXI D,L0FD3
CALL L0FBE
JNZ L0FD6
L0FB8:
MVI A,8Dh
POP B
JMP L1048
L0FBE:
LDAX D
ORA A
RZ
MOV C,A
CALL L1C5A
CMP C
RNZ
INX H
INX D
JMP L0FBE
L0FCC:
DB 'GO ',0
L0FD0:
DB 'TO',0
L0FD3:
DB 'UB',0
Микрософт :)Код:OPS_G:
DB 'OT','O'+80h
DB 89h
DB 'O T','O'+80h
DB 89h
DB 'OSU','B'+80h
DB 8Dh
DB 'E','T'+80h
DB 0C1h,0
Понятно, что хотели как лучше - помочь неопытной части англоязычных пользователей, которые могут написать go to или go sub с пробелом, но реализация позорная. У меня получилось нормализовать приведенный фрагмент тремя исправлениями, многовато для простой задачи.
Не проще было добавить в таблицу операторов ещё и GO SUB? Тогда и лишнего кода не надо было бы. Единственный недостаток, пробел мог бы быть только один. Однако, и сейчас GO TO с несколькими пробелами не прокатит. GOSUB получается :) Если, конечно, переход оставить как есть.
- - - Добавлено - - -
Надо для прикола Altair Basic 8K дизассемблировать. Скорее всего там такая-же шняга :)
- - - Добавлено - - -
Дизассм Altair Basic 4K уже есть, с комментариями altairbasic.org. Я знал, что у MBASIC оттуда ноги растут, сейчас хоть сравнить можно. Много похожего. Шняги с GOTO/GOSUB нет, но в 4Кб сложно что-то вменяемое вместить.
Предлагаю такие 3 исправления (только приведенный фрагмент, там где L0FD6 я не смотрел):
1. CALL L1305 меняем на CALL L1306
2. JZ L0FB8 на JZ L0FBA
3. L0FD3: DB 'UB',0 меняем на L0FD3: DB 'SUB',0
Нет, там нельзя пробелы внутри токенов. И писали его умные люди. Ошибаются все, но явной тупизны там нет.
Как пишется программа для Бейсика сейчас:
набираю код в текстовом редакторе -->> конвертор file.txt to file.cas -->> загрузка в Бейсике CLOAD"" и RUN (предварительно загрузка Бейсика в Эмулятор)
Можно ли сделать следующее:
Создать .bat файл, который взял бы .txt файл кода и преобразовал его через конвертор в .cas (или .bas) файл
Далее запустил эмулятор Вектора
Далее загрузил Бейсик (последнюю версию от ivagor)
Далее загрузил файл .cas (или .bas) и запустил бы его
В итоге мы можем писать код в удобном нам редакторе, а потом запускаем .bat файл, который делает все монотонные движения вместо нас.
Возможно ли такое ?
Ну, ёлы-палы..
https://youtu.be/MmzbMz-DAGw
Файл должен иметь расширение ASC и, если там русский, он должен быть в UTF-8.
svofski, еще бы ты подсказал, как заменить используемый в таком автозапуске бейсик.
Или дело в непоследнем v06x у меня или в r0m вместо rom, попозже попробую.
Я проверил на BASIC 2.97fix и v06x-8b8-win64, это работает.
Он проверяет байтики в памяти, чтобы поверить в то, что это бейсик. Если не находит, жмет сам себе F11. Может быть изменились байтики?
global signature_2b05 = [0xc5, 0xd5, 0x0e, 0x00, 0x57, 0xdb, 0x01]
В последней версии v06x все заработало, круто, спасибо!
svofski, а есть ли возможность ещё и команду RUN сделать автоматической (чтобы ближе к идеалу - меньше лишних движений) ?
Все скрипты могут быть пользовательскими, теоретически. Но прикручивать интерфейс, который это позволит удобно делать, пока руки не дошли. Набрать RUN все-таки не такая уж большая мука =)
Кстати, F9 должно ускорять 4x.
Не, я не про интерфейс. Например команда CLOAD"" она же как-то сама набирается (без всякого интерфейса). Поэтому я подумал что и RUN можно также сделать как CLOAD"". Т.е. если есть уже готовое решение по команде CLOAD"", значит (подумал я) можно и RUN на этой заготовке сделать. :)
Но похоже там не всё так просто.
Всё же было бы здорово если RUN на автомате работал, поскольку когда запускаешь программу только один раз, то да это совсем не напрягает. Но когда делаешь новую программу и запускаешь её раз 100, то это уже другое ощущение процесса :)
А, кажется я понял насчёт интерфейса - это в смысле чтобы автоматический RUN сделать отключаемым - если это так, то тогда да.
Хотя можно сделать спец. версию с автоматическим RUN (если конечно это не много заморочек с заготовкой по CLOAD"").
Я об этом конечно же. Сейчас интерфейс процесса загрузки очень простой -- его нет. Это мой любимый вариант.
Если тебе не чужд Godot 3.5, ты можешь локально у себя поправить что хочешь. По-простому, чтобы без усложнений интерфейса, можно было бы решить все загрузкой скриптов из файлов вместо ресурсов. Но это пока не сделано.
- - - Добавлено - - -
metamorpho, возьми эту версию, специально по заказу https://www.sensi.org/~svo/v06x/v06x-cload-run.zip
Наверное ему недостаточно времени на то, чтобы переварить. Попробуй по той же ссылке еще раз. Добавил задержку. Теперь он должен подождать пару секунд перед тем, как набирать RUN.
Заработало !! Спасибо !!
По поводу конвертирования файла .asc обнаружил небольшой моментик - если в файле .asc где-то встретится например
PLOT 50,120,2:LINE 2,2,BS:PRINT "Бейсик" - маленькими буквами
То на экране вместо маленьких букв будут другие символы. Конечно пользователю самому нужно следить за регистром букв, либо как вариант при конвертировании все мелкие буквы преобразовать в заглавные символы.
Да, любые ошибки будут плохо восприняты. Наверное можно сделать какой-то синтакс хайлайтер на основе конвертера, который бы подсвечивал заранее известные ошибки. Наверняка можно для vs.code и neovim это сделать. Но у меня нет такого опыта, так что на коленке быстро не сбацать.
Среди тестов не хватало сравнения с компилятором более содержательного, чем пустой цикл, пусть будет Мандельброт.
Исходный текст
Код:10 CLS
20 ROWS=21
30 COLUMNS=30
40 MAXITER=8
50 SCALE=4
60 SQ=2
70 SQ2=SQ*SQ
80 VR=-2.3*SCALE
90 VI=-1.0*SCALE
100 ZOOM=0.1*SCALE
110 FOR Y=0 TO ROWS-1
120 CI=VI+Y*ZOOM
130 FOR X=0 TO COLUMNS-1
140 CR=VR+X*ZOOM
150 ZR=CR
160 ZI=CI
170 FOR N=0 TO MAXITER-1
180 R2=ZR*ZR/SQ2
190 I2=ZI*ZI/SQ2
200 IF (R2+I2)>4*SCALE THEN 240
210 ZI=2*ZR*ZI/SQ2+CI
220 ZR=R2-I2+CR
230 NEXT
240 PRINT CHR$(40-INT(N));
250 XX=XX+1
260 NEXT X
270 PRINT
280 XX=0:YY=YY-1
290 NEXT
300 STOP
[свернуть]
BASCOM - 79 секунд по секундомеру (mdos34)
2.5 - 191.6 секунды
2.97fix - 128.4 секунды
И это еще не финал соревнований.
Для скорости лучше не указывать переменные в NEXT, но именно здесь X правда требуется, т.к. в строке 200 есть выход из цикла и без явного указания переменной бейсик путается, что ему NEXTить.
- - - Добавлено - - -
Добавил скриншот
Понятно. И замена внутреннего цикла на бейсиковский эквивалент while скорости уж точно не принесет? N=0 ... N=N+1:IF N < MAXITER GOTO ...
Проблема с N=N+1: IF ... в том, что это два отдельных выражения, которые бейсик должен тяжело и мучительно парсить в цикле. NEXT парсить проще и он один делает и N+1 и GOTO.
Для сравнения оптимизированный вариант Мандельброта. Меньше букв и операций, меньше наглядности и понятности.
Исходный текст
Код:1 CLS
2 RW=21
3 CM=30
4 MI=8
5 SC=4
6 S4=4*SC
7 SQ=2
8 SQ=1/(SQ*SQ)
9 S2=2*SQ
10 VR=-2.3*SC
11 VI=-1.0*SC
12 ZM=0.1*SC
13 FOR Y=0 TO RW-1
14 CI=VI+Y*ZM
15 FOR X=0 TO CM-1
16 CR=VR+X*ZM:ZR=CR:ZI=CI
17 FOR N=0 TO MI-1
18 R2=SQ*ZR*ZR:I2=SQ*ZI*ZI
19 IF (R2+I2)>S4 THEN 22
20 ZI=S2*ZR*ZI+CI:ZR=R2-I2+CR
21 NEXT
22 PRINT CHR$(40-INT(N));
23 XX=XX+1
24 NEXT X
25 PRINT
26 XX=0:YY=YY-1
27 NEXT
28 STOP
[свернуть]
Картинка не изменилась, просто быстрее работает.
BASCOM - 59 секунд по секундомеру (mdos34)
2.5 - 160.1 секунды
2.891 - 127.1 секунды
2.995 - 70.36 секунды
2.996 - 63.53 секунды
Видно, что компилятор дубовый и похоже сам не оптимизирует даже элементарные вещи. Зато он есть и работает, причем на самом 8080.
И все же он существует - исходник бейсика 5.2 с комментариями
Кроме того оказалось, что на известном сайте, где разобран 3.2 4k есть и фрагменты 4.1 Disk Extended
Очередная недокументированная фича - если в GOTO/GOSUB не указать номер строки, то он будет принят равным 0. Например
0 PRINT"HELLO WORLD!":GOTO
даст бесконечный цикл