Вот так правильней ;)
Вид для печати
А теперь классика:
Код:;+
;
; CVBTOD
; Converts the binary value passed in R0 to a string of
; ascii characters which is the decimal equivalent and
; places them in the buffer pointed to by R1
;
; CALL:
; R0 = 16-bit number
; R1 -> conversion buffer
;
; RETURNS:
; R0 = 0
; R1 -> byte following last digit in converted number
;
;-
CVBTOD: MOV R0,-(SP) ;SAVE THE NUMBER PASSED TO US
CLR R0 ;SET FOR CRUDE DIVIDE BY 10.
10$: INC R0 ;BUMP QUOTIENT
SUB #10.,(SP) ;REDUCE NUMBER BY 10.
BHIS 10$ ;IF SIGN DIDN'T CHANGE...
ADD #10.+60,(SP) ;MAKE REMAINDER PRINTABLE
DEC R0 ;REDUCE QUOTIENT
BEQ 20$ ;IF ZERO, TIME TO PRINT
CALL CVBTOD ;OTHERWISE, RECURSE !
20$: MOVB (SP)+,(R1)+ ;STORE A CONVERTED DIGIT
RETURN ;UNWIND THE RECURSION
Со счётом 40:34 победил автор из DEC (и это я ещё не засчитал буфер и не возможность разместить в ПЗУ)Код:
TEST MACRO V05.06R Tuesday 04-Jun-19 Page 1
11
12 000000 .PSECT A1
13 ; Decimal by Manwe
14 ; input: R0 - number to print
15 ; output: R1 - pointer to text string
16
17 000000 012701 000046' DECIM: MOV #NUMBER,R1 ; pointer to output text string
18 000004 105041 CLRB -(R1) ; end of text marker
19 000006 012704 000012 MOV #10.,R4
20 000012 012705 177777 10$: MOV #-1.,R5
21 000016 005205 20$: INC R5 ; counter of 10s
22 000020 160400 SUB R4,R0
23 000022 103375 BHIS 20$ ; branch if higher or same
24 000024 062700 000072 ADD #72,R0 ; #10. + '0' ASCII code
25 000030 110041 MOVB R0,-(R1) ; store R0 to text string
26 000032 010500 MOV R5,R0 ; let's count next how many 10s in number of 10s
27 000034 001366 BNE 10$
28 000036 000207 RETURN ; returns text string pointer in R1
29
30 000040 .BLKB 6
31 000046 NUMBER:
32
33 000000 .PSECT A2
34 000000 010046 CVBTOD: MOV R0,-(SP) ;SAVE THE NUMBER PASSED TO US
35 000002 005000 CLR R0 ;SET FOR CRUDE DIVIDE BY 10.
36 000004 005200 10$: INC R0 ;BUMP QUOTIENT
37 000006 162716 000012 SUB #10.,(SP) ;REDUCE NUMBER BY 10.
38 000012 103374 BHIS 10$ ;IF SIGN DIDN'T CHANGE...
39 000014 062716 000072 ADD #10.+60,(SP) ;MAKE REMAINDER PRINTABLE
40 000020 005300 DEC R0 ;REDUCE QUOTIENT
41 000022 001402 BEQ 20$ ;IF ZERO, TIME TO PRINT
42 000024 004767 177750 CALL CVBTOD ;OTHERWISE, RECURSE !
43 000030 112621 20$: MOVB (SP)+,(R1)+ ;STORE A CONVERTED DIGIT
44 000032 000207 RETURN
- - - Добавлено - - -
Как видно, в DEC знали про этот подход или у них был свой Дженсен ;)
Для комплекта ещё - вариант из Stop the Express для MS-0515.
Но на самом деле тут в конце приписан ещё лишний нолик, потому что выводятся заработанные очки.
Точку входа Z34420 можно использовать для печати 3-значного числа.
Код:; Подпрограмма: Печать 5-значного десятичного числа; R3=число
Z34400: MOV #023420, R2 ; 10000.
Z34404: CALL Z34454 ;
Z34410: MOV #001750, R2 ; 1000.
Z34414: CALL Z34454 ;
Z34420: MOV #000144, R2 ; 100.
Z34424: CALL Z34454 ;
Z34430: MOV #000012, R2 ; 10.
Z34434: CALL Z34454 ;
Z34440: ADD #000060, R3 ; '0'
Z34444: MOVB R3, (R1)+ ;
Z34446: MOVB #000060, (R1)+ ;
Z34452: RETURN ;
Z34454: MOV #000060, R0 ; '0'
Z34460: SUB R2, R3 ;
Z34462: BLO Z34470 ;
Z34464: INC R0 ;
Z34466: BR Z34460 ;
Z34470: ADD R2, R3 ;
Z34472: MOVB R0, (R1)+ ; копируем в экран план
Z34474: RETURN
Кто запустил УКНЦшников в тему БК-0010?!!
:)
А в чём "невозможность" размещения в ПЗУ? Буфер текстовой строки - это любое место в ОЗУ.
И зачем было считать за часть программы занесение адреса текстового буфера в R1, если в другой программе он не считается?
Ещё они не заносят в текстовый буфер символ конца строки (0). Если из моей программы убрать и это, она станет на одно слово короче DECовской. Тогда получится 13:14 в мою пользу!
:)
Так-то идея с рекурсией прикольная, респект. Но с практической точки зрения там много операций со стеком, что сказывается на производительности. Этот алгоритм и без того тормозной, так ещё и усугублять постоянными обращениями к (SP)... Наверное, целью было сэкономить регистры любой ценой.Код:; Decimal by Manwe
; input: R0 - number to print
; R1 - pointer to text buffer + 6
; output: R1 - pointer to the text to print
DECIM: CLRB -(R1) ; end of text marker
MOV #10.,R4
1: MOV #-1.,R5
2: INC R5 ; counter of 10s
SUB R4,R0
BHIS 2 ; branch if higher or same
ADD #72,R0 ; #10. + '0' ASCII code
MOVB R0,-(R1) ; store R0 to text string
MOV R5,R0 ; let's count next how many 10s in number of 10s
BNE 1
RET ; returns text string pointer in R1
Естественно, "в DEC был свой Дженсен" - несколько хакеров из MIT перешли на работу в DEC. Собственно, они повлияли на само становление архитектуры PDP-1.
Вариант из Stop the Express занимает 31 слово (в десятичной системе счисления).
Я делал быстрый (без CALLов) вариант со степенями 10. Из полезного: не печатает лидирующие нули, добавляет в конец символ конца строки.
Размер 25 слов:
Код:; Fast DECIMAL by Manwe
; input: R0 - number
; R1 - pointer to output text string
DECIM: MOV #TEN,R5 ; table address
1: CMP (R5)+,R0 ; skip leading zeros
BHI 1 ; branch if higher, for 16-bit not signed
MOV -(R5),R3
BEQ 4 ; if less then 10
2: MOV #57,R4 ; 0 symbol in ASCII codepage - 1
3: INC R4 ; count digits
SUB R3,R0
BHIS 3 ; branch if higher or same, for 16-bit not signed
MOVB R4,(R1)+ ; print R4
ADD (R5)+,R0
MOV (R5),R3
BNE 2
4: ADD #60,R0 ; 0 symbol in ASCII codepage
MOVB R0,(R1)+ ; print R0
CLRB (R1) ; write end marker of the text string
RET
TEN: .WORD 10000.,1000.,100.,10.,0
Не нашёл более подходящей темы, спрошу здесь.
При обращении к адресу @#167776 БК-0011М вылетает на середине команды. По адресам 160000-177777 находится область регистров внешних устройств и конкретно по адресу 167776 в данный момент ничего не подключено (обычно бывает подключён контроллер СМК и в этой ячейке памяти записана версия контроллера).
Действительно ли БК должна прерываться по 4-ому вектору при обращении к адресу 167776?
Касается ли это только БК-0011М, или также БК-0010?
Известны ли какие-то ещё устройства, использующие порт 167776?
Заранее спасибо.
Адрес существует всегда! но по нему могут не отвечать. Или никто не живет или разговаривать не хотят. А могут только читать а писать нет!
Для БК страница ввода-вывода определена в документации 177600-177776 и называется областью системных регистров. В этом одно из несоответствий архитектуре PDP-11
Код:1. Конфигурация без расширенной памяти.
0 ------------------------------
! Область стека и системных !
! переменных !
1000 ------------------------------
! ОЗУ пользователя !
40000 ------------------------------
! ОЗУ экрана !
100000 ------------------------------
! Системное ПЗУ !
120000 ------------------------------
! Сменное (съемное) !
! ПЗУ (Фокал) !
140000 ------------------------------
! Сменное ПЗУ !
160000 ------------------------------
! Сменное системное ПЗУ !
177600 ------------------------------
! Область системных !
! регистров !
177777 ------------------------------
2. Конфигурация с расширенной памятью.
0 ------------------------------
! Область стека и системных !
! переменных !
1000 ------------------------------
! ОЗУ пользователя !
40000 ------------------------------
! ОЗУ пользователя или !
! экрана !
70000 ------------------------------
! ОЗУ экрана !
100000 ------------------------------
! Системное ПЗУ (монитор и !
! драйверы) !
120000 ------------------------------
! ПЗУ-интерпретатор Фокала !
140000 ------------------------------
! ПЗУ резервное !
160000 ------------------------------
! ПЗУ. тесты !
177600 ------------------------------
! Область системных !
! регистров !
177777 ------------------------------
Адрес, при обращении по которому в течении 15 мкс не прилетел BRPLY L
Ну, строго говоря, в архитектуре PDP-11 нигде не постулируется, что в старших 8 кб адресного пространства располагается страница в/в или что там обязательно только регистры внешних устройств. Более точный вариант для PDP - сигнал BBS7 L, хотя и это - не постулат. Но если требуется работа ОС от DEC без необходимости модификации - это до некоторой степени предполагается. Хотя более точный вариант (но тоже не постулат) - по адресам 177560-177566 - регистры адаптера подключения консольного терминала плюс по некоторым адреса (не обязательно на странице в/в) ПЗУ с по крайне мере начальным загрузчиком (или ввод его тем или иным способом) плюс по некоторым адресам (не обязательно на странице в/в) регистров устройства, откуда пойдёт начальная загрузка некоей системы. Но это не обязательно, особенно в варианте с прошитым в ПЗУ софтом.
Постулируется
177560-177566 ОБЯЗАТЕЛЬНО
Карта распределения памяти и диспетчер памяти определяются стандартом
Кстати DECPro Digital не обзывал PDP-11 совместимым компьютером
Так что наша википедия врет на странице pdp-11 про
Электроника 85
Электроника БК-0010 и БК-0011М
Электроника МК-85
Электроника МК-90
Союз-Неон ПК-11/16 не совместимый но программно-аппаратно эмулирует pdp-11 с 16-ти разрядным адресом
про немигу и мс0515 не знаю
PDP-11 Architecture Handbook
http://home.kpn.nl/a.dikker1/museum/rspdparch.html
Спасибо за ответы!
Я смотрел схему адресного пространства из книги Зальцмана, и по ней у меня сложилось впечатление, что с адреса 160000 может быть и ПЗУ, и регистры внешних устройств: http://gid.pdp-11.ru/books/00015-01....html#_ref_p111
За попытку отмазки - прокатит, за ссылку на документ - нет
Из PDP-11 Architecture Handbook, страница 17
The professional 300 series are full-fledged of the PDP-11 family. The microprocessor chip used in the Professional 325 and 350 is the F-11, the same chip used in the LSI-11/23 and the PDP-11/23 PLUS. ... As a PDP-11 family member, ...
страница 257
However, certain applications place memory, or devices that act like memory, on the UNIBUS. Examples ... :
- Shared (multi-ported) UNIBUS memory
- Certain graphics devices (bit-mapped graphics ...)
- Bus windows (DA11-F)
In these cases, address presented on the UNIBUS may actually be intended for the memory on the UNIBUS. It would be undesirable for the UNIBUS Map to pick up such an address and translate it to a main memory address...
страница E-7
Devices in the I/O page ignore the nine high order address bits BDAL <21:13> and instead decode BBS7 L along with the thirteen low-order address bits
И наконец (я, конечно, мог пропустить - и тогда - страницу в студию, но) - ни слова про 177560-177566
Может и то и другое. Например, по адресам 173000-173776 и 165000-165776 часто можно найти ПЗУ тестирования и загрузчиков
Проба пера для PDP-11 - распаковщик LZSA1. Наверняка можно сократить, но, надеюсь, и этот вариант приемлемый.
ivagor, спасибо!
А есть у вас запаковщик на C/C++ для этого алгоритма? // а, сорри, увидел - https://github.com/emmanuel-marty/lzsa
Тут в параллельной ветке по УКНЦ иногда поднимается вопрос упаковки/распаковки.
На данный момент мы имеем три алгоритма - RLE, LZSS, LZ4 - все три с упаковщиком на C/C++ и распаковщиком на PDP-11.
См. тут - https://github.com/nzeemin/ukncbtl-u.../Sav2Cartridge
По вашему коду могу только сказать что вот такую конструкцию
можно сократить доКод:mov src, dst
bic #177400, dst
Код:clr dst
bisb src, dst
По поводу сравнения с sav2cartridge. RLE и LZ4 точно уступают LZSA1 по степени сжатия, LZ4 потенциально еще чуть уступает и по скорости распаковки, но насчет своего конкретного распаковщика по этому вопросу пока не уверен. LZSS скорее всего сжимает сильнее, но тут надо проверять, насколько именно.
За подсказку спасибо, еще подумаю и заменю на доработанный вариант.
- - - Добавлено - - -
Еще раз взглянул и понял, что bic #177400 в данном случае совсем не нужен, но на будущее вариант clr\ bisb пригодится.
Возможно ошибся с выходом из RIDLNG... Но пока на одно слово меньше :)Код:.NLIST
.INCLUDE /DSMAC.MAC/
.INCLUDE /MYMAC.MAC/
.LIST
MODULE NAME=<TEST>, REL=<SH>, VER=<01>, LIBR=<LZSA1UnPack>, COMM=<LZSA1 UnPacker>
EXPORT QUALIFIED ULZSA1
PROCEDURE ULZSA1
BEGIN
LET Counter+1 :B= #0
LOOP
LET R0 := #0
LET R0 :B= R0 SET.BY (R1)+
LET R5 := R0
LET R0 := R0 OFF.BY #^C<160>
IF RESULT IS NE THEN ; if literal
LET R0 := R0 R.SHIFT 4
IF R0 EQ #7 THEN
CALL RIDLNG
ON.ERROR LEAVE LOOP
END
LET Counter+0 :B= R0
THRU R3 := Counter
LET (R2)+ :B= (R1)+
END
END
LET Offset+0 :B= (R1)+
LET Offset+1 :B= #377
LET R0 :B= R5
IF RESULT IS MI THEN ; LongOffset
LET Offset+1 :B= (R1)+
END
LET R0 := R0 OFF.BY #^C<17> + #3
IF R0 EQ #18. THEN
CALL RIDLNG
ON.ERROR LEAVE LOOP
END
LET Counter+0 :B= R0
LET R4 := R1
LET R1 := Offset + R2
THRU R3 := Counter
LET (R2)+ :B= (R1)+
END
LET R1 := R4
END
RETURN
END ULZSA1
PROCEDURE RIDLNG
BEGIN
CLR R4
LET R4 :B= R4 SET.BY (R1)+
LET R0 := R0 + R4
IF RESULT IS CS THEN
LET Counter+1 :B= R0
LET R0 :B= (R1)+
IFB Counter+1 EQ #0 THEN
LET Counter+0 :B= R0
LET Counter+1 :B= (R1)+
LET CARRY := OFF
IFB Counter+1 EQ #0 THEN
LET CARRY := ON
END
END
END
RETURN
END RIDLNG
Counter: .BLKW 0
Offset: .BLKW 0
END TEST
.END
- - - Добавлено - - -
Пардон, забыл одну команду, что бы сделать полноценный библиотечный модуль :)
Вот когда сумеете сократить размер менее 14-ти слов, тогда и поговорим :)
ivagor, можете взглянуть что может быть не так?
Пробую применить ваш распаковщик LZSA1 для картриджа УКНЦ.
В некоторый момент распаковщик вычисляет не ту длину для копирования.
Исходные данные до запаковки - HWYENC.SAV начиная с адреса 512. = 0x200;
запакованный поток (проверен штатным LZSA1-распаковщиком на валидность) - HWYENC.BIN, тоже начиная с адреса 512. = 0x200;
проблема возникает со значением по адресу 30157(octal) = 0x306F, туда должно попасть значение 0x8A, а получается 0xFD, ну и дальше конечно уже все данные распакованы неверно.
Во вложении архив с этими файлами, плюс стейт-файл к эмулятору UKNCBTL, отладчик стоит перед вычислением длины и копированием как раз этого фрагмента.
Там же LST-файл от компилятора чтобы понимать что где.
Может это конечно я где-то налажал с ручным переносом кода, но вроде бы всё проверил несколько раз.
nzeemin, спасибо за багрепорт! Ошибку нашел, исправил, но не проверил на Вашем файле, извините, может уже завтра, но надеюсь будет работать правильно.
Выложил в репозиторий исправленные распаковщики LZSA1 и LZSA2.
Потестировал LZSA2 на своей программе ST0play. Размеры:
Было: 11244
Стало: 5746
Для сравнения BKpack: 6006
LZSA1 тоже работает.
Для распаковки предлагаю дописывать в начало:
Здесь 1000 - куда распаковывать программу, 32000 - адрес упакованной программы. Понятно, что распакованный файл не должен выходить за адрес 32000.Код:.LINK 32000
BEGIN: MOV #32000+(packed-BEGIN),r1
MOV #1000,r2
MOV r2,-(SP)
Сразу после такого начала идёт процедура распаковки. По RET она переходит на адрес 1000, потому что он был заранее положен в стек.
Если суммировать по алгоритмам сжатия для БК/УКНЦ, то у нас сейчас есть:
1. LZSS: запаковщик в Sav2Cart, распаковщик там же (из LZSAV.MAC by Ostapenko Alexey) в 66. байт.
2. LZ4: запаковщик в Sav2Cart (подглючивает иногда, надо исправлять), распаковщик там же, by Alexander Troosh, в 76. байт.
3. LZSA1: запаковщик https://github.com/emmanuel-marty/lzsa, распаковщик тут https://gitlab.com/ivagor/lzsa8080/ by Ivan Gorodetsky, 156. байт.
4. LZSA2: запаковщик https://github.com/emmanuel-marty/lzsa, распаковщик тут https://gitlab.com/ivagor/lzsa8080/ by Ivan Gorodetsky, 296. байт.
5. bkpack - исходники кажется были у @gid? распаковщик сколько занимает?
6. P16UNP.MAC в 364. байта и PL.PAS из кода для ПК 11/16 - см. https://github.com/troosh/pk11-16/tree/master/Soft/BIOS
На БК 0011м под CSI-DOS есть ещё неплохой Crunch. Он иногда плотней bkpack'а, иногда нет.
Размер распаковщика bkpack: короткий - 128 байт, длинный - 146. байт, но ему ещё нужно около килобайта временного места для распаковки таблиц, которые используются для распаковки массива данных,.
Посмотрел на размеры распаковщиков, устыдился и немного оптимизировал LZSA1 (теперь 144 байта).
6 байт можно очевидно отыграть внеся Counter, Offset и SavedOffset в тело программы. Скорее всего фикс бага со счетчиком можно сделать поприличнее. А дальше надо смотреть, вспоминать алгоритмы распаковки. Наверняка LZSA2 для PDP-11 можно еще заметно сократить, а может и LZSA1 тоже.
Я проверяю в emu в конфиге BK-0010 на паре файлов. Пропуск ошибки со счетчиком вызван тем, что файлы сравнительно небольшие (до 15 Кб) и там такой проблемы не возникло, что, конечно, моя недоработка.
Последние оптимизации LZSA1 не только позволили уменьшить размер, но и совершенно точно немного ускорили распаковщик. В emu эмуляция скорости BK не очень точная (а в каком эмуляторе она точная?), поэтому конкретные цифры не буду приводить.
Перечисленные оптимизации LZSA2 тоже приведут к некоторому ускорению при уменьшении размера.
Сократил распаковщик LZSA2 до 266 байт и ускорил. Перешел на "тестовую платформу" DVK и добавил третий тестовый файл, побольше размером.