Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ; ***********************************************************
- ; ** NyaOS Sample **
- ; ***********************************************************
- ; http://teplofizik.diary.ru/p179655647.htm
- AREA RAM, DATA, NOINIT, READWRITE, ALIGN=3
- ; Указатель стека главного процесса
- SPMain DCD 0
- AREA |.text|, CODE, READONLY
- EXPORT nyaos_Stub
- EXPORT nyaos_Start
- ; Прерывания
- EXPORT SysTick_Handler
- EXPORT SVC_Handler
- IMPORT ProcessTable
- IMPORT ContextTable
- IMPORT CurrentProcess
- IMPORT ProcessMaxCount
- IMPORT SWI_Table ; swi_table.s
- IMPORT SWI_Count ; swi_table.s
- IMPORT SWI_ChCount ; swi_table.s
- GET nyaos.inc
- GET system.inc
- ; Получить номер текущего процесса
- ; Аргументы: нет
- ; Результаты: номер слота
- ; Используемые регистры: LR, R0
- disp_GetSlotIndex PROC
- ; Загрузим номер текущего процесса (по таблице)
- MOV32 R0, CurrentProcess
- LDR R0, [R0] ; Прочитаем номер процесса
- BX LR
- ENDP
- ; Установить номер текущего процесса
- ; Аргументы: 1
- ; R0: номер слота
- ; Результаты: нет
- ; Используемые регистры: LR, R1
- disp_SetSlotIndex PROC
- MOV32 R1, CurrentProcess
- STR R0, [R1] ; Запишем номер процесса
- BX LR
- ENDP
- ; Сохранение состояния текущей задачи
- ; Аргументы: 1
- ; R0: номер текущего слота
- ; Результаты: нет
- ; Используемые регистры: LR, R0, R1, R2, R3
- disp_SaveContext PROC
- ; Загрузим адрес таблицы контекстов
- MOV32 R1, ContextTable
- ; Выберем нужную запись
- MOV R2, #CONTEXT_SIZE
- MUL R0, R0, R2
- ADD R1, R1, R0
- ; Сохраним состояние старших регистров
- STR SP, [R1, #CONT_SP]
- STR R4, [R1, #CONT_R4]
- STR R5, [R1, #CONT_R5]
- STR R6, [R1, #CONT_R6]
- STR R7, [R1, #CONT_R7]
- STR R8, [R1, #CONT_R8]
- STR R9, [R1, #CONT_R9]
- STR R10, [R1, #CONT_R10]
- STR R11, [R1, #CONT_R11]
- BX LR
- ENDP
- ; Чтение состояния текущей задачи
- ; Аргументы: 1
- ; R0: номер текущего слота
- ; Результаты: нет
- ; Используемые регистры: LR, R0, R1, R2
- disp_LoadContext PROC
- ; Выбираем контекст
- MOV32 R1, ContextTable
- MOV R2, #CONTEXT_SIZE
- MUL R2, R0, R2
- ADD R1, R2
- ; Загружаем регистры и указатель стека
- LDR SP, [R1, #CONT_SP]
- LDR R4, [R1, #CONT_R4]
- LDR R5, [R1, #CONT_R5]
- LDR R6, [R1, #CONT_R6]
- LDR R7, [R1, #CONT_R7]
- LDR R8, [R1, #CONT_R8]
- LDR R9, [R1, #CONT_R9]
- LDR R10, [R1, #CONT_R10]
- LDR R11, [R1, #CONT_R11]
- BX LR
- ENDP
- ; Расчёт задержек
- ; Аргументы: 0
- ; Результат: нет
- ; Используемые регистры: LR, R0
- disp_CalcDelay PROC
- ; Пробежимся по таблице, посмотрим, есть ли задержки
- MOV R0, #0
- ; Загрузим таблицу процессов
- MOV32 R2, ProcessTable
- ; Загрузим ограничение на количество
- MOV32 R4, ProcessMaxCount
- LDR R4, [R4]
- __next_proc
- ; Допустимый номер процесса?
- CMP R0, R4
- BPL __del_exit
- LDR R1, [R2, #PROC_FLAGS] ; Process->Flags
- ; Проверяем программную задержку (выставлена -> обработаем)
- TST R1, #DELAY_MASK
- BEQ __continue
- ; Вычтем из поля Event единицу
- LDR R1, [R2, #PROC_EVENT] ; Process->Event
- SUBS R1, #1
- STR R1, [R2, #PROC_EVENT] ; Process->Event
- ; Если всё ещё больше или равно 0, идём дальше
- BPL __continue
- ; Минус. Задержка кончилась.
- ; Снимаем флаг задержки
- LDR R1, [R2, #PROC_FLAGS] ; Process->Flags
- BIC R1, #DELAY_MASK
- STR R1, [R2, #PROC_FLAGS] ; Process->Flags
- __continue
- ; Следующий процесс
- MOV R1, #PROCESS_SIZE
- ADD R2, R1
- ADD R0, #1
- B __next_proc
- __del_exit
- BX LR
- ENDP
- ; Поиск следующей задачи
- ; Аргументы: 1
- ; R0: номер текущего слота
- ; Результат: номер следующего слота
- ; Используемые регистры: LR, R0, R1, R2, R3, R4, R5, R6, R7
- disp_FindNext PROC
- ; Запомним номер процесса
- MOV R3, R0
- ; Загрузим таблицу процессов
- MOV32 R2, ProcessTable
- ; И размер одной записи...
- MOV R5, #PROCESS_SIZE
- ; Загрузим ограничение на количество
- MOV32 R4, ProcessMaxCount
- LDR R4, [R4]
- ; Ищем свободный PID
- _proc_next
- ADD R0, #1
- ; Проверим на границу диапазона
- CMP R0, R4
- ; Загрузим 0, если вылезли (0 для Idle)
- IT EQ
- MOVEQ R0, #0
- ; Сравним с номером, с которого начинали
- CMP R0, R3
- ; Если он - загрузим процесс Idle (0).
- ITT EQ
- MOVEQ R0, #0
- BEQ _proc_found
- ; Если это процесс Idle, пропускаем.
- CMP R0, #0
- BEQ _proc_next
- ; Нет, не он. Проверим PID
- ; Считаем смещение до элемента
- MOV R6, R0
- MUL R6, R6, R5
- ADD R6, R2
- ; Грузим PID
- LDR R7, [R6, #PROC_PID]
- ; Если ноль, ищем дальше.
- CMP R7, #0
- BEQ _proc_next
- ; Проверим регистр флагов:
- LDR R7, [R6, #PROC_FLAGS] ; Process->Flags
- ; Проверяем программную задержку (выставлена -> мимо)
- TST R7, #DELAY_MASK
- BNE _proc_next
- ; Проверяем ожидание события
- TST R7, #EVENT_MASK
- BNE _proc_next
- _proc_found ; Процесс выбран
- BX LR
- ENDP
- ; Диспетчер
- ; Переключение задач
- SysTick_Handler PROC
- ; Запомним код выхода в обычный режим
- MOV R12, LR
- ; Номер текущего слота
- BL disp_GetSlotIndex
- ; Если не надо сохранять, не сохраняем...
- CMP R0, #0xFF000000
- BEQ _sysh_start
- ; Сохранить контекст
- BL disp_SaveContext
- ; Посчитаем программные задержки для всех процессов
- BL disp_CalcDelay
- ; Номер текущего слота
- BL disp_GetSlotIndex
- ; Запомним номер
- MOV R3, R0
- B _sysh_loadptable
- _sysh_start
- ; Cохраним указатель стека
- MOV32 R0, SPMain
- STR SP, [R0]
- ; Текущий Process: 0
- MOV R3, #0
- _sysh_loadptable
- ; получить номер следующей задачи
- MOV R0, R3
- BL disp_FindNext
- ; Сохраним номер выбранного процесса
- BL disp_SetSlotIndex
- ; Загрузим контекст
- BL disp_LoadContext
- ; Выход из прерывания уже по новому PC
- BX R12
- ENDP
- ; Обработчик программного прерывания
- SVC_Handler PROC
- PUSH {R8-R11}
- MOV R12, LR
- ; Получение номера прерывания
- LDR R11, [SP, #0x28] ; PC
- LDRB R11, [R11, #-2] ; Младший байт инструкции (номер)
- ; Проверим номер на допустимость (а то улетим куда)
- MOV32 R8, SWI_Count
- LDR R8, [R8]
- ; Если много - выходим.
- CMP R11, R8
- ITT GE
- POPGE {R8-R11}
- BXGE R12
- ; Сохраним номер для проверки дальнейшей
- PUSH {R11}
- ; Умножим номер на 4, получим смещение.
- LSL R11, #2
- ; И прибавим к началу таблицы
- MOV32 R8, SWI_Table
- ; Загрузим адрес функции
- LDR R11, [R8, R11]
- ; Сохраним R12 (код возврата)
- PUSH {R12}
- ; Вызов функции
- BLX R11
- ; Вернём R12 (код возврата)
- POP {R12}
- ; Вытащим номер обратно в R1
- POP {R1}
- ; Скопипастим R0 обратно в стек
- STR R0, [SP, #0x10]
- POP {R8-R11}
- ; Проверим, надо ли менять процесс или пусть остаётся
- ; Задано количество элементов, после выполнения которых требуется смена
- ; процесса. Проверим, не один из них ли?
- MOV32 R2, SWI_ChCount
- LDR R2, [R2]
- ; Если номер больше порогового, то выходим из прерывания, не меняя процесс.
- CMP R1, R2
- IT GE
- BXGE R12
- ; Смена процесса.
- ; Номер текущего слота
- BL disp_GetSlotIndex
- ; Если не надо сохранять, не сохраняем...
- CMP R0, #0xFF000000
- BEQ _svch_start
- ; Запомним номер
- MOV R3, R0
- ; Сохранить контекст
- BL disp_SaveContext
- B _svch_loadptable
- _svch_start
- ; Cохраним указатель стека
- MOV32 R0, SPMain
- STR SP, [R0]
- ; Текущий Process: 0
- MOV R3, #0
- _svch_loadptable
- ; получить номер следующей задачи
- MOV R0, R3
- BL disp_FindNext
- ; Сохраним номер выбранного процесса
- BL disp_SetSlotIndex
- ; Загрузим контекст
- BL disp_LoadContext
- ; Выход из прерывания
- BX R12
- ENDP
- ; Завершение процесса с помощью функции ОС
- ; Аргументы: нет
- ; Результаты: нет
- nyaos_Stub PROC
- ; ExitProcess(R0);
- SVC SWI_EXITPROCESS_NUMBER
- B .
- ENDP
- ; Запуск ОС
- ; Аргументы: нет
- ; Результаты: нет
- nyaos_Start PROC
- ; Разрешить прерывания от таймера
- MOV R0, #1
- BL SysTickInterruptEnable
- ; По прерыванию выполнение перейдёт к процессу
- __mainloop
- ; На очередной круг
- B __mainloop
- ENDP
- END
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement