Войти
ФлеймФорумЖелезо

Блеск и нищета 8/16-битных консолей и ПК (55 стр)

Страницы: 154 55 56 5759 Следующая »
#810
(Правка: 7:32) 7:31, 23 янв. 2020


=A=L=X=
> Вот недавно где то на форуме видел что кто то писал как под win95 асмовсавками
> в защищенном же приложении писал в порты ввода-вывода то ли com то ли lpt.
> Сейчас это невозможно в принципе, а тогда работало.

Под семёрку тоже работает! :) PortIO :) Нужна inpout32.dll . 

PortIO.h:

+ Показать

PortIO.c:

+ Показать

main.c:

+ Показать

Type.h:

+ Показать

make:

+ Показать

:)


#811
7:42, 23 янв. 2020

Gradius
> Нужна inpout32.dll

InpOut32 is an open source windows DLL and Driver to give direct access to hardware ports
...
The driver (.sys file) is included, as a resource in the DLL.
...
NOTE: When the DLL loads for the first time, the appropriate driver is installed and used.
NOTE: Elevated permissions are required in Vista and later to install the driver.

Ну это другое конечно. :)
#812
7:44, 23 янв. 2020


=A=L=X=
> Читая обсуждение еще на пред-предыдущей странице загорелся тем чтобы
> реализовать на спектруме настоящую вытесняющую многозадачность.

Алёнка и Макс уже давно реализовали.  Говнофорум (хз-пк-ру) в помощь. Искать - "тазис" и всё что с ним связано

#813
(Правка: 7:46) 7:46, 23 янв. 2020

Gradius
> Алёнка и Макс уже давно реализовали.

Не сомневаюсь, идея лежит на поверхности, интересно именно самому. Я и прерывания перехватил первый раз в жизни сегодня с утреца. :)

#814
9:36, 23 янв. 2020

=A=L=X=
> А правда, что пилишь?

Если получится - то очередную звуковую (в основном) демку. И в этот раз для чистоты эксперимента - под DOS, а то вон в прошлый раз gamedevfor не поверил, что все синтезируется чисто собственным кодом, и сказал, что раз демки под Win32, то там внутри я мог вызвать всякие API, которые и сделали большую часть работы. Похоже что так же подумали и большинство остальных, видевших эти демки, хотя на самом деле там из API только самый минимум, необходимый для waveOut (но может быть просто всем пофиг, а интересны только демки на спектрумах).

Впрочем, пока стопроцентной уверенности нет. Не уверен, смогу ли уложиться по быстродействию (т.к. все-таки приходится запускать в эмуляторе типа DosBox), да и в 16-битном режиме я теряю SSE-инструкции, за счет которых обсчитывалось сразу по 4 голоса одновременно. Не уверен, смогу ли уложиться по памяти, т.к. предыдущие демки, несмотря на свой 16-килобайтный размер, жрали памяти больше мегабайта для различных буферов (все эти эффекты Delay, Chorus, несколько буферов ревербератора, и все это в стерео и во float32-представлении и на частоте 44100, буферы для распакованных данных). Ну а главное, я не уверен, что у меня не опустятся руки...

Правда если переключиться в защищенный режим, вопрос с доступностью памяти отпадет, да и SSE станут доступны, но поскольку я все же хочу уложиться в 16к (и это вместе с данными), то использовать готовые DOS-экстендеры я не могу, надо будет своим кодом подготавливать все эти структуры защищенного режима - я пока даже не представляю, сложно это или нет, много ли кода потребуется.

#815
10:13, 23 янв. 2020

Dmitry_Milk

Ясно, прикольно!

> готовые DOS-экстендеры я не могу, надо будет своим кодом подготавливать все эти структуры защищенного режима - я пока даже не представляю, сложно это или нет, много ли кода потребуется.

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

#816
(Правка: 10:52) 10:29, 23 янв. 2020

Гы, реально реализовал вытесняющую мультизадачность на спектруме. :D
Сделал как можно проще - контекст процесса (задачи) это одна страница памяти (256 байт выровненные на 256 байт) где хранится стек.
Стек процесса не должен выходить за пределы этой страницы и поэтому чтобы сохранить вершину стека в первом байте страницы при засыпании откладывается нижний байт SP и этого достаточно.
Регистры процесса сохраняются до того в сам стек.
Вторым байтом в контексте процесса хранится адрес следующего в односвязном циклическом списке контекста. Достаточно лишь байта опять таки потому что контексты это страницы и достаточно хранить только верхний байт их адреса.
Код переключения контекстов по прерыванию 50 раз в секунду таким образом получился безобразно коротким (intr_handler).
Чтобы основной поток выполнения встроился в эту схему ему достаточно вправить стек в конец какого-нибудь контекста - остальное происходит само-собой.
А вот прочие потоки надо инициализировать в такое состояние как будто они уже выполнялись и содержат в конце стека и все регистры и адрес продолжения работы потока и главное что в первом байте контекста содержится нижний байт вершины стека - для этого уже приходится делать процедуру task_init с параметрами.
Все три процесса в примере выполняют один и тот же код, но т.к. на входе у них разные значения регистра DE, то они вечно инкрементируют разные 3 байта в экранной области - и это реально видно. Всё происходит параллельно с квантом времени 1/50 секунды. :D
Прикольно, прикольно, еще одна мечта детства реализована. :D

    device ZXSPECTRUM48

    org $8000
intr_table
    block 257, $EE  ; таблица векторов прерываний (все вектора - адрес $EEEE)
entry  jp start    ; переходим на начало программы

    ;include "screen.inc"
    ;include "math.inc"
    ;include "zstr.inc"
    ;include "keys.inc"

; task_init - инициализировать задачу
; in: h - старший байт адреса контекста задачи
;  bc - стартовый адрес кода задачи
;   остальные регистры сохранят свои значения
;  и могут служить входными параметрами в задачу.
task_init
    ld (.prev_sp), sp  ; sp нужен для манипуляций - запоминаем его
    ld l, $FF    ; hl = конец стека задачи
    ld sp, hl
    push bc      ; адрес возобновления задачи
    push af
    push bc
    push de
    push hl
    push ix
    push iy      ; зафиксировали в контексте все регистры

    ld b, h
    ld c, 0      ; bc = taskCtx
    ld hl, 0
    add hl, sp    ; hl = вершина стека
    ld a, l
    ld (bc), a    ; сохранили low sp в контекст

    ld sp, (.prev_sp)  ; восстанавливаем sp и выходим
    ret
.prev_sp  dw 0

    ; НАЧАЛО ПРОГРАММЫ
start
    ; устанавливаем обработчик прерываний
    di
    ld a, $80    ; таблица векторов лежит по $8000
    ld i, a
    im 2

    ; инициализируем Задачу 2
    ld de, $4000    ; входной параметр - байт который будем менять
    ld h, high task2ctx  ; старший байт адреса задачи
    ld bc, tasks_start  ; начало кода задачи
    call task_init

    ; инициализируем Задачу 3
    ld de, $5804    ; входной параметр - байт который будем менять
    ld h, high task3ctx  ; старший байт адреса задачи
    ld bc, tasks_start  ; начало кода задачи
    call task_init

    ; первую задачу просто делаем текущим контекстом установив стек
    ld de, $4001    ; входной параметр новой задачи
    ld sp, task1ctx + $FF  ; адрес стека создаст правильный контекст
    ei          ; разрешаем прерывания чтобы менеджер задач заработал
    jp tasks_start

    ; цикл (общий) выполнения для разных задач
tasks_start
    ld hl, de      ; hl = переданный в задачу параметр 
tasks_loop
    inc (hl)      ; вечно прокручиваем байт по переданному адресу
    jp tasks_loop    

body_end

    ; Контекст задачи 1
    org $9000      ; указываем что контекст лежит по адресу $9000
task1ctx
    db 0        ; нижний байт стека
    db high task2ctx  ; связь со следующей задачей

    ; Контекст задачи 2
    org $9100
task2ctx  
    db 0        ; нижний байт стека
    db high task3ctx  ; связь со следующей задачей

    ; Контекст задачи 3
    org $9200
task3ctx  
    db 0        ; нижний байт стека
    db high task1ctx  ; связь со следующей задачей

    org $EEEE
intr_handler
    di
    ; сохраним все регистры
    push af
    push bc
    push de
    push hl
    push ix
    push iy
    ; сохраним в текущем контексте задачи нижний байт sp
    xor a
    ld h, a
    ld l, a
    add hl, sp    ; hl = sp
    ld c, l         ; c = low sp
    ld l, a      ; hl = taskCtx
    ld (hl), c    ; taskCtx.lowSp = c
    inc l
    ; переключимся указатель в hl на следующий контекст
    ld c, (hl)    ; c = taskCtx.highNext
    ld h, c      ; h = taskCtx.highNext
    ld l, a      ; hl = taskCtx.next
    ; восстановим sp из следующего контекста
    ld l, (hl)    ; hl = taskCtx.sp
    ld sp, hl    ; sp = taskCtx.sp
    ; восстанавливаем регистры контекста
    pop iy
    pop ix
    pop hl
    pop de
    pop bc
    pop af
    ; и возобновляем выполнение задачи
    ei
    ret
    
pend

    savesna "test48.sna", entry
    savebin "test48.bin", entry, pend - entry

#817
(Правка: 11:00) 10:59, 23 янв. 2020

Кстати, забавно, додумался сейчас еще, что из-за того как работают прерывания в спектруме (по сути просто выполняя CALL, использовать инструкцию reti для возврата необязательно, достаточно просто ret) текущая задача может легко отдать свой квант времени следующей задаче в списке просто сделав CALL intr_handler. :) Никакого дополнительного кода для этого писать не надо.
И если далее задумываться о межпроцессном взаимодействии, то т.к. всё крутится вокруг прерываний, то:
- любые записи/чтения данных одной инструкцией в спектруме в принципе атомарны (на уровне прерываний)
- критические секции это просто пары команд di ... ei - код между командами запрета и разрешением прерываний гарантированно будет атомарен
Т.е. можно даже легко наворотить всякие семафоры :))

#818
11:26, 23 янв. 2020

=A=L=X=
> Прикольно, прикольно, еще одна мечта детства реализована. :D

нужно было делать это в детстве

#819
11:28, 23 янв. 2020

innuendo
> нужно было делать это в детстве

Так вот и осталась неудовлетворённая детская мечта. :D
Удовлетворил полностью за час - теперь я богоподобный созидатель вытесняющей многопоточности двигающий облака! :D

#820
(Правка: 15:45) 15:45, 23 янв. 2020

gamedevfor

> рисует в свою часть экрана

Оно сейчас это и делает в сущности - 3 разных полоски рисуются, можно с  разной скоростью даже, если отдавать квант времени от одного потока другим.

> Давай демо

Не особо этим интересуюсь, да и такая техника для демок не особо интересна по крайней мере в плане равноправных потоков. Демкам важнее одно хороводящее прерывание таймера, а остальное сидит просто на таймингах обычно.

#821
15:52, 23 янв. 2020

gamedevfor
> каждая из которых рисует в свою часть экрана и запусти их одновременно.

Хорошо затроллил Алекса :)
А вообще мне кажется нет смысла вырывать управление у программ 50 раз в секунду. Какой многозадачности действительно не хватало на тех 8-битных компах - это возможности переключаться между задачами по желанию пользователя, без необходимости, чтоб программа работала в фоне - достаточно было, чтоб она в том фоне "спала". Кстати, если к спектруму умудриться пришпандорить относительно быстрый внешний накопитель, то вот по такому "межзадачному прерыванию" можно было бы делать своп "образов памяти" на такой накопитель, благо в Z80 есть какие-то "строковые" инструкции (или в спектруме есть DMA?), которые могли бы ускорить обмен 48к с таким внешним накопителем до считанных секунд.

#822
(Правка: 16:24) 16:24, 23 янв. 2020

Dmitry_Milk
> Кстати, если к спектруму умудриться пришпандорить относительно быстрый внешний
> накопитель

DivMMC называется . И даже уже встроена возможность сохранять снапшоты через Magic Button на флешку и подгружать их обратно, как в эмуляторе.

#823
16:36, 23 янв. 2020

gamedevfor
> На ZX48 это просто не эффективно потому что на 90% там будет работа по
> сохранению/восстановлению регистров и только 10% на выполнение задач - слишком
> тормозный проц у ZX48 для этого.
> Корутины действительно более предпочтительны для ZX48.

не пиши если не знаешь тему

#824
16:37, 23 янв. 2020

0iStalker
> Magic Button

о ... даст ист фантастиш - я от этой штуки писал кипятком

Страницы: 154 55 56 5759 Следующая »
ФлеймФорумЖелезо