Подобного - это какого?
Чтобы два слоя были статическими, а третий менялся? Конечно. Что этому мешает?
Вид для печати
Просто это уберет кучу проблем с сохранением-восстановлением фона.
А так "стильно-модно-молодежно". :)
- - - Добавлено - - -
Еще бы приемлемый горизонтальный однобитный скролл придумать.
Хотя если объектов немного проще спрайты двигать (тут как раз пригодится процедурка вывода части спрайта).
Задумал было отказаться полность от ОС и работать с дисководом напрямую.
Но возник вопрос - как правильно это делать?
В какой то теме натыкался на то что form писал о реализации минимального драйвера MZ (который работает только с диками на 800КБ). Помню что судя по контексту должны были присутствовать ссылки на драйвер, но их не было.
В общем разыскиваю примеры как строится передача данных с дискет.
Немного о затруднениях:
В массиве параметров который передается ПП для того чтобы он выполнил чтение, задается количество слов для чтения.
Здесь я наткнулся на несколько неожиданное поведение:
допустим запросил я считать 512 слов, начиная с сектора 10(последнего на дорожке), головки 0 и дорожки 0
соответственно ПП нужно прочитать два сектора, и второй сектор будет прочитан со следующей дорожки(1), хотя я ожидал что будет произведено чтение с другой стороны диска.
Ну да ладно, чтобы особо не заморачиватся я могу раскидать данные внутри образа так что каждая непрерывная последовательность будет находится на одной стороне диска.
Но наткнулся на другое, когда запрашиваю чтение более 2000 слов(не пытался установить точное значение), что то переклинивает, сначала считывается примерно 2000 слов, а потом головка дисковода начинает метаться, и через какое то время все прекращается.
Lethargeek, в стандарте можно много чего написать, а как это поддерживается в железе?! Если память мне не врёт, то турбопаскаль поддерживал доступ ко всем внешним контекстам для вложенных процедур. Уж не знаю это часть стандарта или исключительно его особенность, но мне что-то не попадались железяки с каким-то аппаратными регистрами для ускорения этого дела. Везде стандартные SP/BP и копирование этой кучки указателей через стек.
Я передавал неправильный тип устройства в массиве параметров - 01(односторонний диск). После этого просил прочитать со второй стороны, когда сектор заканчивает, должен осущестится переход на другую дорожку, но тут что то переклинивало и головка дисковода начинала метаться между текущей и следующей дорожкой. :v2_dizzy_facepalm:
Там не только с рекурсией проблемы, допустим у нас есть процедура D внутри которой описаны процедуры A,B,C, причём процедура A вызывается из B и C, в этом случае процедуре A должны передать указатель на локальные переменные процедуры D, иначе доступа к ним она не получит. Ну и такая же фигня может случиться на любом уровне, где есть несколько вложенных процедур и в итоге копировать придётся несколько указателей.
Это всё прекрасно, только этим языкам уже лет 20 и не удивительно что на тот момент они как-то соответствовали возможностям железа. С другой стороны, если взять язык релейных диаграмм, то реально никаких реле внутри нет, кроме возможно силовых на выходе и изолирующих на входах. Так что тезис о том, что алгоритмические языки сильно отстали от железа промышленная автоматика никак не опровергает.
Hunta, это нельзя вычислить на этапе компиляции, если процедурам B и C требуется разное количество памяти для локальных переменных.
ребят вы тему по УК-НЦ засорили уже реально! Создаёте в разном новую и обсуждайте свои "реле" там!
Если на входе процедура D выделила место для своих переменных и скопировала SP в BP, далее процедура B или C сохранила в стеке BP от процедуры D, и точно так же выделила место для своих переменных, то если теперь вызать процедуру A, она не будет знать из B или C её вызвали, и где искать BP от процедуры D, чтобы добраться до её локальных переменных. Каким образом это можно подсчитать во время компиляции?!
Это не обязательно какой-то выделенный регистр, но в Си имеется функция выделения памяти в стеке, и когда размер выделяемой памяти приходит в виде параметра, без BP или его аналога этого не сделать. Ну а в паскале, если разрешать доступ к локальным переменным внешних процедур, то значение SP при входе тоже придётся где-то запоминать, а во внутренней процедуре откуда-то извлечь.
Ещё раз - в Паскале всё просчитывается в момент компиляции - потому что понятно - кто в кого вложен и как был вызов
Если Вам это не понятно - это не мои проблемы
Вообще доступ к локальным переменным из вложенных процедур организован несколько менее эффективно. Это действительно так. Но ведь можно такие процедуры и не юзать. Вот в Си их вообще нет, и не парятся.
Есть попытки выпустить реализацию Оберона-07 без вложенных процедур. Но это только эксперименты.
Еще раз обращаю внимание A,B и C это процедуры напрямую вложенные в процедуру D, но процедура A вызывается через B или C, хотя можно еще и напрямую из D вызвать. Возможные состояния стека:
Avars Bvars Dvars
Avars Cvars Dvars
Avars Dvars
Как образом при компиляции здесь можно подсчитать где окажутся переменные процедуры D в тот момент когда вызвана процедура A?
Доступ к таким локальным переменным идёт по смещению, передаваемому извне при вызове вложенной процедуры. О чём спор вообще?
Немного инфы перед анонсом большего для pdp-11:
Код:C:\ming-w64\bin> pdp11-aout-gcc -v
Using built-in specs.
COLLECT_GCC=pdp11-aout-gcc
COLLECT_LTO_WRAPPER=c:/ming-w64/bin/../libexec/gcc/pdp11-aout/10.0.1/lto-wrapper.exe
Target: pdp11-aout
Configured with: ../configure --prefix=/opt/pdp11/ming-w64 --target=pdp11-aout --host=i686-w64-mingw32 --disable-shared --enable-static --disable-threads --disable-multilib --enable-languages=c,c++ --disable-libstdcxx --disable-libsanitizer --disable-gold --disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libssp --disable-nls --disable-plugin --disable-silent-rules --disable-sjlj-exceptions --without-headers --without-isl --without-cloog --enable-stage1-checking --disable-libgcc --with-gmp=/opt/pdp11/ming-w64 --with-mpfr=/opt/pdp11/ming-w64 --with-mpc=/opt/pdp11/ming-w64 --without-iconv
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 10.0.1 20200318 (experimental) (GCC)
Код:D:\workspace\pdp11-toolchain\hello-gcc> make
pdp11-aout-as -o crt0rt.o crt0rt.s
pdp11-aout-gcc -O1 -m10 -c -o hello.o hello.c
pdp11-aout-as -o puts.o puts.s
pdp11-aout-ld -T pdp11-aout.ld -o hello.out hello.o puts.o -Map=hello.out.map
bin2load -a -f hello.out -o hello.lda
lda2sav -o hello.sav hello.lda
Правильно понимаю что из нового тут только lda2sav, чтобы использовать этот тулчейн для RT-11 ?
https://github.com/yshestakov/pdp11-...-gcc/lda2sav.c
Да, правильно.
И свежий GCC (master, 10.0.1) + binutils 2.34, собранный с помощью MinGW в 32-bit Windows executables.
Я чуть позже перенесу (добавлю) в pdp11 бакэнд GCC описание процессоров ВМ1 и ВМ2, чтоб генерился код под них.
Прямо сейчас сборка в виже ZIP лежит у Vslav на сайте:
https://www.1801bm1.com/files/pdp11/cross-compilers/
Тут пока чистый GCC. Как сделаю поддержку ВМ1/ВМ2 - попробую закинуть
Поднимем тему немного.
Решил скинуть сюда отдельные примеры работы с библиотекой ULBLIB (входит в состав RT-11 Source Kit). Вдруг кому пригодится.
Сам многократно писал с нуля функционал который уже есть в этой библиотеке.
Для начала пример обработки ошибок в программе.В принципе тут все должно быть понятно.Код:.MCALL .MODULE
.MODULE ULB,RELEASE=V01,VERSION=00,COMMENT=<ERROR HANDLING>,AUDIT=YES
.MCALL .EXIT ;SYSTEM MACROS
.INCLUD /SY:ULBMAC/ ;ULBLIB MACROS
ERAREA: .BLKB ;ERROR CODE
.BLKB ;ERROR LEVEL/RETURN FLAG
.WORD ERRPRE ;ERROR MESSAGE PREFIX
.WORD ERRLEV ;ERROR LEVEL BYTE
.WORD ERRTAB ;ERROR MESSAGE OFFSET TABLE
.BLKW ;FILE NAME BLOCK/ADDRESS OF STRING
.WORD $ABORT ;ABORT ENTRY
ERRPRE: .NLCSI TYPE=I,PART=PREFIX
ERRLEV: .ASCII /X-/<200>
.EVEN
MSGLST ERRTAB
ERRMSG ERR,<Just an error>
ERRMSG WAR,<Warning and nothing more>
ERRMSG FIL,<File error >
ERRMSG STR,<Error with string >
ERRMSG FAT,<Fatal error>
MSGEND
DBLK: .RAD50 /SY FILNAMTYP/
TEXT: .ASCII /"Hi there"/<200>
.EVEN
$START::
.ERR #ERAREA,#ERR,LEVEL=FATAL,RETURN=YES
.ERR #ERAREA,#WAR,LEVEL=WARNING,RETURN=YES
.ERR #ERAREA,#FIL,LEVEL=FATAL,FILE=#DBLK,RETURN=YES
.ERR #ERAREA,#STR,LEVEL=PADLA,ASCII=#TEXT,RETURN=YES
.ERR #ERAREA,#FAT,LEVEL=U
BR $START
$ABORT::
.EXIT
.END $START
Определяется таблица ERRTAB.
В этой таблице определяются сообщения с уникальным кодом.
Код занимает один байт со знаком.
Положительные значения назначаются автоматически макрокомандой ERRMSG.
Отрицательные значения зарезервированы для файловых и прочих системных ошибок (об этом в другой раз).
Таблиц может быть несколько, хотя скорее всего одной хватит.
Макрокоманда .ERR вызывает печать сообщения с заданным уровнем (используется первая буква).
Если указан адрес стандартного блока имени файла - к сообщению добавляется имя файла.
Если указан адрес дополнительной строки - к сообщению добавляется строка.
Одновременно указать блок имени файла и дополнительную строку нельзя.
Для стандартных уровней (W,E,F,U) устанавливаются правильные биты в байте ошибки программы (@#53).
Если не указан RETURN=YES, возврата не происходит, управление передается на заданную в блоке описания точку входа.
Как-то так :)
- - - Добавлено - - -Код:.EX UL/LINK:SY:ULBLIB
?ULB-F-Just an error
?ULB-W-Warning and nothing more
?ULB-F-File error SY:FILNAM.TYP
?ULB-P-Error with string "Hi there"
?ULB-U-Fatal error
.
Здесь без примеров.
Просто описание вызовов.
Вызов $INIDM можно так же вызвать повторно чтобы освободить всю выделенную ранее память (предварительно нужно обнулить второе слово $FRHD).Код:;CALL $INIDM -- Инициализация динамической памяти.
;
;На входе:
; R0 - Адрес двухсловного массива $FRHD (нужно определить в программе)
; +00 - начальный адрес используемой памяти (обычно содержимое @#50 плюс 2)
; +02 - 0
;
;На выходе:
; C - 0=успех, 1=ошибка
; R0 - Размер свободной памяти в байтах
; @#50 - Максимальный доступный программе адрес
;CALL $RQCB -- Запрос блока динамической памяти
;
;На входе:
; R0 - адрес $FRHD
; R1 - размер блока в байтах
;
;На выходе:
; C - 0=успех, 1=ошибка
; R0 - адрес выделенного блока памяти
; R1 - реальный размер выделенного блока памяти
;CALL $RLCB - Освобождение блока памяти
;
;На входе:
; R0 - Адрес $FRHD
; R1 - Размер блока памяти
; R2 - Адрес блока памяти
Память выделяется сверху вниз. Если планируется вызывать подпрограммы работы с файлами из ULBLIB, сразу после инициализации динамической памяти стоит выделить "в пустоту" блок памяти под USR (не требуется в XB/XM/ZB/ZM или если выгрузка USR запрещена). Размер USR в байтах можно получить по смещению 374 от начала RMON.
Так же не требуется выделять блок памяти под USR если все нужные драйвера гарантированно загружены.
Для вывода сообщения об ошибке выделения памяти можно воспользоваться макрокомандой .ERR как показано выше со стандартным кодом FE.NOM.
- - - Добавлено - - -
Здесь кратко о макросах/подпрограммах ULBLIB для работы с файлами.
Начало программы может выглядеть примерно так:Для работы с файлами средствами ULBLIB используются дескрипторы фалов (FDB).Код:$FRHD:: .BLKW 2 ;ЗАГОЛОВОК СПИСКА СВОБОДНОЙ ПАМЯТИ
OUTSPC: .BLKW 3*5 ;БЛОКИ ВЫХОДНЫХ ФАЙЛОВ
INPSPC: .BLKW 6*4 ;БЛОКИ ВХОДНЫХ ФАЙЛОВ
DEFEXT: .RAD50 /INPOUTOUTOUT/ ;РАСШИРЕНИЯ ФАЙЛОВ ПО УМОЛЧАНИЮ
;+
;ТОЧКА ЗАПУСКА.
;-
$START::
MOV @#50,R0 ;ПОЛУЧАЕМ ВЕРХНИЙ АДРЕС
TST (R0)+ ;СЛЕДУЮЩИЙ АДРЕС - НАЧАЛО СВОБОДНОЙ
;ПАМЯТИ
MOV R0,$FRHD ;СОХРАНЯЕМ ЕГО
;+
;ТОЧКА ПОВТОРНОГО ВХОДА.
;-
$RETRY:
MOV #$FRHD+4,R5 ;АДРЕС ЗАГОЛОВКА (+4)
CLR -(R5) ;ИНИЦИАЛИЗИРУЕМ ЗАГОЛОВОК
MOV -(R5),R4 ;ПОЛУЧАЕМ АДРЕС НАЧАЛА СВОБОДНОЙ
;ПАМЯТИ
MOV R4,R0 ;КОПИРУЕМ ДЛЯ ИСПОЛЬЗОВАНИЯ
TST -(R0) ;ПРЕДЫДУЩИЙ АДРЕС - ВЕРХ ПРОГРАММЫ
.SETTOP ;ВОССТАНАВЛИВАЕМ ВЕРХНИЙ АДРЕС
;
;ВЕРХНИЙ АДРЕС ВОССТАНАВЛИВАЕТСЯ ЧТОБЫ ИЗБЕЖАТЬ ЛИШНЕЙ АКТИВНОСТИ С ФАЙЛОМ
;SWAP.SYS ПРИ ВЫХОДЕ ИЗ ПРОГРАММЫ.
;
.SRESET ;ЗАКРЫВАЕМ ОТКРЫТЫЕ КАНАЛЫ,
;ВЫГРУЖАЕМ ЗАГРУЖЕННЫЕ ДРАЙВЕРЫ
;
;В ЭТОМ МЕСТЕ:
; R5 = АДРЕС ЗАГОЛОВКА СПИСКА СВОБОДНОЙ ПАМЯТИ
; R4 = НАЧАЛЬНЫЙ АДРЕС СВОБОДНОЙ ПАМЯТИ
;
;МЫ ИСПОЛЬЗУЕМ .CSISPC, ВСЕ ОСТАЛЬНЫЕ ОПЕРАЦИИ ВЫПОЛНЯЮТСЯ СРЕДСТВАМИ
;БИБЛИОТЕКИ ULBLIB.
;
10$: MOV @#42,SP ;ВОССТАНАВЛИВАЕМ УКАЗАТЕЛЬ СТЕКА
.CSISPC #OUTSPC,#DEFEXT,#0,R4 ;РАЗБИРАЕМ КОМАНДНУЮ СТРОКУ
;
;КОМАНДНАЯ СТРОКА ЧИТАЕТСЯ С ТЕРМИНАЛА ИЛИ ИЗ КОМАНДНОГО ФАЙЛА,
;ПРОВЕРЯЕТСЯ НА СООТВЕТСТВИЕ CSI, ОБРАБОТКА ОШИБОК ПРОИСХОДИТ
;ПРИ ЭТОМ БЕЗ НАШЕГО УЧАСТИЯ.
;
;R4 ССЫЛАЕТСЯ НА КОПИЮ КОМАНДНОЙ СТРОКИ ДЛЯ ДОПОЛНИТЕЛЬНОЙ ПРОВЕРКИ.
;
...........................................................................
;
;ЗДЕСЬ И ДАЛЕЕ СЧИТАЕМ ЧТО СОДЕРЖИМОЕ РЕГИСТРОВ R4 И R5 ОСТАЛОСЬ ТЕМ ЖЕ,
;ЧТО БЫЛО ВЫШЕ.
;
;ИНИЦИАЛИЗИРУЕМ ДИНАМИЧЕСКУЮ ПАМЯТЬ.
;
.GVAL R4,#300 ;ЧИТАЕМ КОНФИГУРАЦИЮ СИСТЕМЫ
MOV R0,-(SP) ;СОХРАНЯЕМ НА ПОТОМ
.GVAL R4,#374 ;ЧИТАЕМ РАЗМЕР USR
MOV R0,-(SP) ;СОХРАНЯЕМ НА ПОТОМ
MOV R5,R0 ;ЗАГОЛОВОК
CALL $INIDM ;ИНИЦИАЛИЗИРУЕМ ПАМЯТЬ
BCC 30$ ;CC - OK
20$: .ERR #ERAREA,#FE.NOM,LEVEL=F ;МАЛО ПАМЯТИ
30$: MOV (SP)+,R1 ;ВОССТАНАВЛИВАЕМ РАЗМЕР USR
BIT #1000,(SP)+ ;USR ВСЕГДА В ПАМЯТИ?
BNE 40$ ;ДА
MOV R5,R0 ;ЗАГОЛОВОК
CALL $RQCB ;РЕЗЕРВИРУЕМ ПАМЯТЬ ПОД USR
;(ТРЕБУЕТСЯ ДЛЯ .FETCH)
BCS 20$ ;CS - МАЛО ПАМЯТИ
40$:
Для открытия файлов по дескриптору используется макрокоманда .OPEN.Код:;+
;ДЕСКРИПТОРЫ ФАЙЛОВ.
;ИСХОДЯЩЕМУ ПРИВЯЗЫВАЕМ КАНАЛ 0, ВХОДЯЩЕМУ КАНАЛ 1.
;МАКСИМАЛЬНАЯ ДЛИНА СТРОКИ - 132. БАЙТА,
;РАЗМЕР РАБОЧЕГО БУФЕРА - 512. БАЙТ.
;
;ЕСЛИ НЕ ПЛАНИУРЕТСЯ РАБОТА СО СТРОКАМИ (БУДУТ ИСПОЛЬЗОВАНЫ ВЫЗОВЫ
;.READ/.WRITE), RECSIZ И BUFSIZ ДОЛЖНЫ БЫТЬ РАВНЫ 0.
;-
OUTFDB: .FILE <OUT>,0,OUTSPC,RECSIZ=132.,BUFSIZ=512.
INPFDB: .FILE <IN>,1,INPSPC,RECSIZ=132.,BUFSIZ=512.
При этом выделяется память под драйвер (если нужно), загружается драйвер (если нужно), выделяется память под рабочий буфер (если указано).
Входящие файлы открываются с помощью .LOOKUP, исходящие - с помощью .ENTER.Последовательное чтение строк из файла выполняется макрокомандой GET$S.Код:MOV #OUTFDB,R2 ;ДЕСКРИПТОР ФАЙЛА
.OPEN R2,R5 ;ОТКРЫВАЕМ ФАЙЛ
BCC 60$ ;CC - OK
;
;ОБРАБОТКА ОШИБОК РАБОТЫ С ФАЙЛОМ.
;R2 У НАС СОДЛЕРЖИТ АДРЕС FDB.
;
50$: .ERR #ERAREA,F.ERR(R2),LEVEL=F,FILE=F.OPNM(R2) ;ОБРАБОТКА ОШИБОК
60$:
В случае ошибки будет установлен бит C.
R0 после вызова GET$S ссылается на FDB.
Код ошибки можно получить по смещению F.ERR дескриптора файла.
Код FE.EOF означает, что во входящем файле больше нечего читать.
Последовательная запись строк в файл выполняется макрокомандой PUT$S.Код:;+
;СЧИТАЕМ ЧТО В R2 У НАС АДРЕС FDB ВХОДЯЩЕГО ФАЙЛА
;-
GET$S R2 ;ЧИТАЕМ СТРОКУ
BCC 70$ ;CC - OK
CMPB #FE.EOF,F.ERR(R0) ;КОНЕЦ ФАЙЛА?
BNE 50$ ;НЕТ, ОШИБКА
;
;ЗДЕСЬ МОЖНО ЗАВЕРШИТЬ РАБОТУ С ФАЙЛАМИ И ПЕРЕЙТИ К ОБРАБОТКЕ СЛЕДУЮЩЕЙ
;КОМАНДЫ.
;
...........................................................................
70$: MOV F.NRBD+2(R0),R1 ;ПОЛУЧАЕМ АДРЕС СТРОКИ
MOV F.NRBD(R0),R2 ;ПОЛУЧАЕМ ДЛИНУ СТРОКИ
В случае ошибки будет установлен бит C.
R0 после вызова PUT$S ссылается на FDB.Если для чтения/записи файла используются макрокоманды .READ/.WRITE, для обработки ошибок нужно сконвертировать код RT-11 в код ошибки для .ERR.Код:;+
;СЧИТАЕМ ЧТО В R2 У НАС АДРЕС FDB ИСХОДЯЩЕГО ФАЙЛА,
;В R1 - АДРЕС СТРОКИ, В R3 - ДЛИНА.
;-
PUT$S R2,R1,R3 ;ЗАПИСЫВАЕМ СТРОКУ
BCS 50$ ;CS - ОШИБКА
Для этого есть подпрограммы $IERR (для .READ/.READC/.READW) и $OERR (для .WRITE/.WRITC/.WRITW).
Обе подпрограммы на входе требуют адрес FDB в R1, на выходе C устанавливается, F.ERR(R1) содержит код ошибки, пригодный для .ERR.Для закрытия файла используется подпрограмма $CLOSE.Код:.READW #AREA,#1,#BUFF,#WCNT,#BLKN ;ВЫПОЛНЯЕМ ЧТЕНИЕ
BCC OK ;CC - OK
MOV R2,R1 ;FDB
CALL $IERR ;КОНВЕРТИРУЕМ КОД ОШИБКИ
BR 50$ ;ОБРАБАТЫВАЕМ ОШИБКУ
На входе R0 должен содержать адрес FDB.
Подпрограмма $CLOSE записывает остатки рабочего буфера в исходящий файл и закрывает его.
Входящий файл можно так же закрыть просто макрокомандой .PURGE или .CLOSE на соответствующем канале.Примерно так :)Код:MOV R2,R0 ;FDB
CALL $CLOSE ;ЗАКРЫВАЕМ ФАЙЛ
BCS 50$ ;CS - ОШИБКА
Некоторые подпрограммы в ULBLIB пересекаются с теми, что я портировал из RSX в RSXLIB.
Для них описание уже есть.
ULBLIB содержит следующие подпрограммы, присутствующие в RSXLIB:
- подпрограммы сохранения регистров $SAVAL, $SAVRG, $SAVVR
- подпрограммы преобразования $CBDSG, $CBDMG, $CBOSG, $CBOMG
- подпрограммы арифметики $DIV, $MUL
- - - Добавлено - - -
Другие подпрограммы преобразования (этих в RSXLIB нет).
Код:;CALL $R50AS - ПРЕОБРАЗОВАНИЯ RADIX-50 В ASCII
; КОД 034 (".") ПРЕОБРАЗУЕТСЯ В "%"
; КОД 035 ПРЕОБРАЗУЕТСЯ В "*"
;
;НА ВХОДЕ:
; R0 - СЛОВО ДЛЯ ПРЕОБРАЗОВАНИЯ
; R1 - АДРЕС БУФЕРА
;
;НА ВЫХОДЕ:
; R1 - УКАЗЫВАЕТ НА СЛЕДУЮЩИЙ БАЙТ ЗА ПОЛУЧЕННОЙ СТРОКОЙ
;CALL $ASCR5 - ПРЕОБРАЗОВАНИЕ ASCII В RADIX-50
; ПРОВЕРОК НЕ ПРОИСХОДИТ, ЕСЛИ СТРОКА СОДЕРЖИТ
; СИМВОЛЫ, НЕ ВХОДЯЩИЕ В RADIX-50 - ПОЛУЧИТСЯ КАША
; "%" ПРЕОБРАЗУЕТСЯ В КОД 034 (".")
; "*" ПРЕОБРАЗУЕТСЯ В КОД 035
;
;НА ВХОДЕ:
; R1 - АДРЕС СТРОКИ
;
;НА ВЫХОДЕ:
; R0 - РЕЗУЛЬТАТ В RADIX-50
; R1 - НАЧАЛЬНЫЙ АДРЕС + 3
;CALL $FNASC - ПРЕОБРАЗОВАНИЯ ИМЕНИ ФАЙЛА В ASCII
;
;НА ВХОДЕ:
; R0 - АДРЕС БЛОКА ИМЕНИ ФАЙЛА RT-11
; R1 - АДРЕС БУФЕРА
;
;НА ВЫХОДЕ:
; R1 - СДРЕС СЛЕДУЮЩЕГО БАЙТА ЗА ПОЛУЧЕННОЙ СТРОКОЙ
form, позвольте вопрос к Вам, как к гуру RT-11.
Я правильно распознал способ выделения памяти под переменные в программе для RT-11? Вот здесь описал: https://zx-pk.ru/threads/11381-napis...=1#post1064763
.SETTOP
- - - Добавлено - - -
https://zx-pk.ru/threads/15587-progr...l=1#post923105
В RT-11 используется .SETTOP для запроса верхнего адреса который нужен программе.
Результатом выполнения будет установка максимально возможного для использования адреса (не выше запрошенного).
После вызова R0 будет содержать самый верхний адрес, доступный программе.Код:.SETTOP #20000 ;ЗАПРАШИВАЕМ ВЕРХНИЙ АДРЕС 20000
.SETTOP #-2 ;ЗАПРАШИВАЕМ МАКСИМАЛЬНЫЙ ВОЗМОЖНЫЙ ВЕРХНИЙ АДРЕС
А вот нижний доступный свободный адрес (сразу после кода программы) как раз стоит брать из @#50 (прибавив к нему 2) или с помощью директивы .LIMIT (так же прибавив 2).
Очень частая ошибка:Это неправильный способ определения конца программы (если программа состоит из нескольких модулей или использует библиотеки, в этом мести может оказаться код следующего модуля).Код:...
END: ;КОНЕЦ ПРОГРАММЫ
.END START
Если хочется динамически выделять блоки памати из свободного места после программы, лучше всего использовать готовые вызовы ULBLIB (выше есть описание подпрограмм).
Есть там так же вариант с виртуальной памятью на диске, но я его еще не смотрел.
Ну и перед выходом из программы стоит возвращать старый верхзний адрес макрокомандой .SETTOP (или вовсе сделать .SETTOP #0). Это поможет избежать лишней дисковой активности.
Да, это расширит файл.
Если через .ASECT прописать - файл не расширится, но при загрузке верхний адрес будет проверяться на доступность для программы. Это этакий заранее сделанный .SETTOP получается. Но вот как оно будет работать в mapped системах, TSX и RSTS - черт его знает :)
Вот я и хочу с помощью 50-ой ячейки в заголовке sav-файла добавить к фактическому концу программы ещё немножко под переменные, чтобы это стало «нижним доступным свободным адресом». Можно, конечно, нулей записать в конец с помощью .BLKW, но это расточительно в смысле места на диске.
Не-не, только статически один раз при загрузке программы.Цитата:
Если хочется динамически выделять блоки памати из свободного места после программы
Исхожу из описания процесса загрузки sav-файла в докумендации DEC: «KMON sets $USRTO (location 50) to the top of the user program». То есть что я прописал в 50-ю ячейку sav-файла, то и будет. Если умещается в память, то начинается загрузка блоков из тела программы согласно битовой карте («The monitor uses this information when it loads the program»).
Во, это круто. То, что надо :) Спасибо.
Не проверял, но пошёл по пути, который точно работает, позволяет выделять место в конце программы для рабочих данных, не увеличивая размер .sav файла и при этом адреса определяются статически - то есть можно не заморачиваться на динамическое выделение памяти и хранение адреса блока где-либо.