; --------------------------------------------

; Title: cli

; Version:

; --------------------------------------------

; CLI

; the command line interface is the default method for user to interact with OS

; etc stuff blahblahblah

#segment text

:cli_name

dat "Command Prompt", 0

#segment data

:cmd_start

dat 0x0

:cmd_buffer

dat 0x0

#segment code

; prints the prompt

:cli_prompt

set push, a

set a, cliprompt_data

jsr print

set a, pop

set pc, pop

:cli

; set up command buffer

set a, 128 ; 64 word buffer

jsr malloc

set [cmd_buffer], c ; store that

jsr clearscreen

;set a, clistart

;jsr print

;jsr newline

jsr cli_prompt ; print prompt

set [cmd_start], [vram_pointer]

:cli_input_loop

set j, [vram_pointer]

jsr getc

ife c, 0

set pc, cli_input_loop

ifl c, 0x20

set pc, cli_handle_lowspec ; handle low special character

ifg c, 0x7f

set pc, cli_handle_hispec ; handle high special character

:standard_char

bor c, [defaultcolor]

set [j], c

add j, 1

set [vram_pointer], j

set pc, cli_input_loop

; handle 0x10-0x19

:cli_handle_lowspec

ife c, 0x10 ; backspace

jsr backspace

ife c, 0x11 ; return

jsr cli_handle_input ; deal with the input

ife c, 0x12 ; insert

add pc, 0 ; placeholder

ife c, 0x13 ; delete

add pc, 0 ; placeholder

set pc, cli_input_loop

; handle 0x80+

:cli_handle_hispec

set pc, cli_input_loop

; handle an inputted command

:cli_handle_input

jsr newline ; go to a new line

set push, a

set push, b

set push, c

set push, z

set push, i

set push, j

set y, 0

set i, 0 ; argc

set z, 0 ; *argv

set a, 32 ; stores the arguments

jsr malloc

set z, c

set [argv_buffer_pointer], z

set a, [cmd_start] ; start of command

set b, [cmd_buffer] ; copy into buffer

set c, [vram_pointer]

sub c, [cmd_start] ; length of command

jsr memcpy ; do copy

set a, b ; set a to buffer

set push, a ; store a

set push, b

set b, a

add b, 128

:buf_other_loop

and [a], 0x7f

add a, 1

ifl a, b

set pc, buf_other_loop

set b, pop

set a, pop

set push, a

set push, b

set push, z

set b, a

add b, 128

:buf_clean_loop ; clean out any text effects

ifn [a], 0x20 ; space

set pc, buf_clean_loop_skip

; deal with space stuff

set [a], 0 ; clear for nts delimiter

add i, 1 ; increment argc

set push, b

set push, c

add a, 1

set [z], a

add z, 1

sub a, 1

set c, pop

set b, pop

:buf_clean_loop_skip

add a, 1

ifl a, b

set pc, buf_clean_loop

set z, pop

set b, pop

set a, pop

; handle buffer:

jsr cmd_process ; process the actual command

jsr cli_prompt ; reprint new prompt

set b, 128 ; clear 64 words

set a, [cmd_buffer]

jsr memclear ; clear buffer

set c, pop

set b, pop

set a, pop

set j, pop

set i, pop

set z, pop

set [cmd_start], [vram_pointer] ; update cmd_start

set pc, cli_input_loop

; process the given command

:cmd_process

; just check for default commands

set push, a

set push, b

set push, c

set push, x

set push, y

set a, [cmd_buffer] ; first string is buffer

set push, cmd_process_end ; pseudo-jsr

set x, [cmd_buffer]

ifn [x], 0x26 ; not ampersand

set pc, cmd_process_l2 ; skip that stuff

; set new thread stuff

set y, 1 ; flag new process

add a, 1 ; skip ampersand

:cmd_process_l2

set x, 0

set b, proclist_cmd

jsr strcmp ; compare

ife c, 1 ; match

set x, proclist ; do that

set b, disp_time_cmd

jsr strcmp

ife c, 1

set x, disp_time

set b, testproc_cmd

jsr strcmp

ife c, 1

set x, testproc2

set b, devicelist_cmd

jsr strcmp

ife c, 1

set x, devicelist

set b, cli_kill_cmd

jsr strcmp

ife c, 1

set x, cli_kill

set b, ls_cmd

jsr strcmp

ife c, 1

set x, ls

set b, test_cmd

jsr strcmp

ife c, 1

set x, testing

ifn x, 0 ; we are going to do something

set pc, cmd_execute_base ; execute command

; command not understood

set a, cmd_unrecog

jsr print

add sp, 1

jsr newline

:cmd_process_end

set y, pop

set x, pop

set c, pop

set b, pop

set a, pop

set pc, pop

:cmd_execute_base

ife y, 1 ; gotta spawn new process

jsr cmd_execute_new ; new process

ife y, 0

jsr cmd_execute_current ; just do it within current process

set pc, pop

:cmd_execute_current

set a, i

set b, z

set z, 0

set i, 0

set j, 0

set push, x

set x, 0

jsr pop

set pc, pop

:cmd_execute_new

set push, a

set push, b

set a, x

jsr newproc

set b, cmd_new_proc_name

jsr setprocname

jsr startproc

set b, pop

set a, pop

set pc, pop

; CLI DATA

#segment data

:argv_buffer_pointer

dat 0x0

#segment text

:clistart

dat "", 0

:cliprompt_data

dat "%>", 0

:cmd_unrecog

dat "Command not recognized.", 0

:cmd_new_proc_name

dat "Console spawned", 0; --------------------------------------------

; Title: file

; Date: 7/13/2012

; Version:

; --------------------------------------------

; Sector Header Format: 32 words

;----------------------------------

; Word | What it is

;----------------------------------

; 0: Sector data type:

; 0: nothing

; 1: file

; 2: directory

;

; 1: Flags

;

; 2: Previous sector (0xFFFF if none)

;

; 3: Next sector (0xFFFF if none)

;

; 4:

#segment data

; pointer to sector buffer

:sector_buffer

dat 0x0

; sector of hard_drive that we are currently at

:cur_sector

dat 0x0

; pointer to path string that we're currently at

:cur_path

dat 0x0

#segment text

:root_path

dat "/", 0

#segment code

; initialize file system stuff

:fs_init

set push, a

set [hd_hwnum], i

set a, 512 ; sector buffer

jsr malloc ; allocate it

set [sector_buffer], c ; store that

set a, 128

jsr malloc

set [cur_path], c

jsr fs_format

set [cur_path], root_path ; default path

set a, pop

set pc, pop

; format the hard drive

:fs_format

set push, a

set push, b

set push, c

set push, x

set push, i

set i, [hd_hwnum]

; check there is media

set a, 0

hwi i

ife b, 0 ; no media

set pc, fsf_end ; return

set c, 1438 ; sector for root directory

set a, fs_format_data ; data to write

jsr sector_write ; write that data to that sector

:fsf_end

set i, pop

set x, pop

set c, pop

set b, pop

set a, pop

set pc, pop

#segment data

:fs_format_data

dat 0x0002, 0x0000, 0xFFFF, 0x059f, 0x0000, 0x0000, 0x0000, 0x0000

dat 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000

dat 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000

dat 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000

#segment code

; write *A to sector C on disk I

:sector_write

set push, a

set push, b

set push, c

set push, x

set b, c

set x, a

set c, 1

set a, 0x11 ; interrupt code

hwi i ; do the interrupt

set x, pop

set c, pop

set b, pop

set a, pop

set pc, pop

; Go to specified relative/absolute path

:cd

#segment text

:ls_cmd

dat "ls", 0

#segment code

; List contents of current directory

:ls

; first, print current path to screen

set push, a

set a, [cur_path]

jsr print ; print current path string

jsr newline ; newline of course

; now, print out contents of current directory

set a, pop

set pc, pop; --------------------------------------------

; Title: graphics

; Date: 7/13/2012

; Version:

; --------------------------------------------

; LEM1802 Driver

; Monitor display driver

#segment data

; default print color

:defaultcolor

dat 0xf000

#segment code

; print_hex

; prints the hex value in A, digit by digit, to screen

:print_hex

set push, a

set push, b

set push, c

set b, a

and b, 0xf000 ; highest digit

shr b, 12

jsr print_hex_sub

set b, a

and b, 0x0f00

shr b, 8

jsr print_hex_sub

set b, a

and b, 0x00f0

shr b, 4

jsr print_hex_sub

set b, a

and b, 0x000f

jsr print_hex_sub

set c, pop

set b, pop

set a, pop

set pc, pop ; return

:print_hex_sub

ifg b, 0x9 ; alphabetical digit

add b, 0x37 ; bring to ascii

ifl b, 0xa ; numerical digit

add b, 0x30 ; bring to ascii

bor b, [defaultcolor]

set c, [vram_pointer]

set [c], b

add c, 1

set [vram_pointer], c

ifg [vram_pointer], [vram_end]

jsr shiftlines

set pc, pop

; print

; This function prints nt string pointed by A to the monitor

:print

set push, a

set push, b

set push, c

set push, x

:print_loop

set x, [a] ; character to print

jsr putc

:print_loop_end

add a, 1

ifn [a], 0 ; not at end!

set pc, print_loop ; keep going

:print_end

set x, pop

set c, pop

set b, pop

set a, pop

set pc, pop ; return

; handle a carriage return

:carriage_ret

and [vram_pointer], 0xffe0

set pc, pop

; prints ascii character in a

:putc

; check for overflow

set b, [vram_pointer]

ifl b, [vram_end]

set pc, putc_cont ; good to go

jsr shiftlines

:putc_cont

ife x, 10 ; newline

set pc, newline

ife x, 8 ; backspace - this probably shouldn't show up but you never know

set pc, backspace

ife x, 13

set pc, carriage_ret

bor x, [defaultcolor] ; add in color

set b, [vram_pointer] ; get vram pointer

set [b], x ; print

add b, 1 ; increment

set [vram_pointer], b

set pc, pop

; print something out asynchronously from command line

:async_print

jsr newline ; force newline

jsr print ; print the thing

jsr newline

set pc, pop

; inserts a space

:space

add [vram_pointer], 1

set pc, pop

; shift the lines of everything down

:shiftlines

set push, i

set push, j

set push, z

set z, 0

set i, [vram_loc] ; i is beginning of vram

set j, [vram_end]

sub j, 32 ; j is end of 11th line (because 12th will be empty)

:sl_loop

set [i], [i+32] ; set everything to the respective value a line below

add i, 1 ; increment

ifl i, j ; if not to end

set pc, sl_loop ; go again

add j, 32 ; bring j to end

:sl_loop2

set [i], z ; clear i

add i, 1 ; increment

ifl i, j ; not at end...

set pc, sl_loop2 ; ...keep going

set [vram_pointer], 0x1360

set z, pop

set j, pop

set i, pop

set pc, pop ; return

:addcolor

set push, a

set push, b

set push, c

jsr strlen

set b, [defaultcolor]

add c, a

:addcolor_loop

bor [a], b ; add in the color to this word

add a, 1

ifl a, c

set pc, addcolor_loop

set c, pop

set b, pop

set a, pop

set pc, pop

:clearscreen

set push, a

set push, b

set push, c

set a, [vram_loc]

set b, [vram_end]

:csloop

set [a], 0

add a, 1

ifl a, b

set pc, csloop

; reset vram pointer

set [vram_pointer], [vram_loc]

set c, pop

set b, pop

set a, pop

set pc, pop

:newline

set push, x

set x, [vram_pointer]

sub x, [vram_loc]

and x, 0xffe0

add x, 32

add x, [vram_loc]

set [vram_pointer], x

; check for overflow

ifg [vram_pointer], [vram_end]

jsr shiftlines ; if so shift lines up

set x, pop

set pc, pop ; return

:backspace

set push, i

set i, [vram_pointer]

ifg i, [vram_loc] ; not out of vram

ifg i, [cmd_start] ; nor out of current command

sub i, 1 ; go back one

set [i], 0 ; clear old

set [vram_pointer], i ; re-store

set i, pop

set pc, pop ; return; --------------------------------------------

; Title: hardware

; Date: 7/13/2012

; Version:

; --------------------------------------------

; HARDWARE FUNCTIONS

; Functions designed to allow the OS to interact with hardware

; hardware_init

; looks through all connected hardware devices, attempts to recognize each one,

; and initializes it as appropriate

:hardware_init

set push, a

set push, b

set push, c

set push, x

set push, y

set push, z

set push, i

hwn z ; find number of hardware devices

; get ready for loop

set i, 0 ; counter

; loop for hardware init

:hi_loop

hwq i ; get info on i

; find lem1802

ife b, 0x7349

ife a, 0xf615

jsr lem1802_init ; initialize found monitor

; find clock

ife b, 0x12d0

ife a, 0xb402

jsr clock_init ; initialize found clock

; find keyboard

ife b, 0x30cf

ife a, 0x7406

jsr keyboard_init ; initialize found keyboard

ife b, 0x4cae

ife a, 0x74fa

jsr fs_init

add i, 1

; if we haven't found every hardware device, keep going

ifl i, z ; still less than z (total num)

set pc, hi_loop

; end of hi_loop

set i, pop ; start restoring registers

set z, pop

set y, pop

set x, pop

set c, pop

set b, pop

set a, pop

set pc, pop ; return to calling function

; lem1802_init

; This function initializes hardware device I as a lem1802 monitor.

:lem1802_init

ifn [lem_hwnum], 0 ; monitor already initializes

set pc, pop ; go back, only one monitor (currently)

set [lem_hwnum], i ; store the hwnum of the monitor

set push, a

set push, b

set push, c

set a, 0x0 ; interrupt num for vram-set

set b, [vram_loc] ; location of VRAM

hwi i ; send vram-set interrupt

; if desired, add additional configuration interrupts for monitor here

; calculate vram end

set b, [vram_loc]

add b, 384

set [vram_end], b

set [vram_pointer], [vram_loc]

set c, pop

set b, pop

set a, pop

set pc, pop ; return to calling function

; clock_init

; This function initializes a clock at hwnum I

:clock_init

set push, a

set push, b

set push, c

set [clock_hwnum], i

set a, 0 ; set clock freq interrupt num

set b, [clock_freq] ; frequency of clock data

hwi i ; do the interrupt

set a, 2 ; set interrupt code interupt num

set b, 0x01 ; code of clock

hwi i ; do the interrupt again

set c, pop

set b, pop

set a, pop

set pc, pop

; keyboard_init

; Initializes keyboard at hwnum i

:keyboard_init

set push, a

set push, b

set push, c

set [kb_hwnum], i

; do that interrupt

set c, pop

set b, pop

set a, pop

set pc, pop

; disp_time

; This function prints the current system time to the screen

:disp_time

set push, a

set a, disp_time_data

jsr print

set a, [sys_time+1]

jsr print_hex

set a, [sys_time]

jsr print_hex

jsr newline

set a, pop

set pc, pop

#segment text

:disp_time_data

dat "Current system time: ", 0

:disp_time_cmd

dat "time", 0

#segment code

; list all devices and print formatted list

:devicelist

hwn i

sub i, 1

:dl_loop

hwq i

set x, device_unrecog

; find lem1802

ife b, 0x7349

ife a, 0xf615

set x, monitor_text

; find clock

ife b, 0x12d0

ife a, 0xb402

set x, clock_text

; find keyboard

ife b, 0x30cf

ife a, 0x7406

set x, kb_text

set a, x

jsr print ; print text

jsr newline ; advance line

sub i, 1

ifn i, 0xffff

set pc, dl_loop

set pc, pop

#segment text

:monitor_text

dat "LEM1802 Monitor", 0

:clock_text

dat "Generic Clock", 0

:kb_text

dat "Generic Keyboard", 0

:device_unrecog

dat "Unrecognized Device", 0

:devicelist_cmd

dat "devicelist", 0; --------------------------------------------

; Title: kernel

; Date: 7/13/2012

; Version:

; --------------------------------------------

; Operating system for DCPU16

#segment boot

; Go to beginning of OS:

set pc, boot

; OS DATA

#segment data

; location of kernel's stack

:kernel_sp

dat 0x1200 ; provides 512-word stack for kernel

; clock interrupt frequency

:clock_freq

dat 1 ; 10 hertz

; system time

:sys_time

dat 0, 0 ; 32-bit time value, represents clock ticks since startup

; hwnum of the monitor the OS is using

:lem_hwnum

dat 0x0

; hwnum of the active keyboard

:kb_hwnum

dat 0x0

; hwnum of active clock

:clock_hwnum

dat 0x0

:hd_hwnum

dat 0x0

; process data

; pid of the current process

:cur_proc

dat 0x0

:proc_list_start

dat 0x1b00 ; start of data of process pointer list

:proc_maxnum

dat 0x10 ; max number of processes (16)

; malloc data

:malloc_reg

dat 0x1400

:malloc_reg_end

dat 0x0 ; calculated

:malloc_start

dat 0x2000

:malloc_length

dat 0xe000

:malloc_end

dat 0x0 ; calculated

:malloc_reg_pointer

dat 0x0

; video data

:vram_loc

dat 0x1200

:vram_pointer

dat 0x0 ; calculated

:vram_end

dat 0x0 ; calculated

; AUTO CLOCKSPEED FLAG

:autoclockflag

dat 0x0 ; 1 for yes, 0 for no

; Kernel Boot Functions

#segment code

; This is what happens when the dcpu is turned on originally.

:boot

set sp, [kernel_sp] ; move sp to the proper place

set [cur_proc], 0x1 ; this is the "pid" assigned to the launch process (for pid-dependent function purposes)

jsr malloc_init ; initialize dynamically allocated memory

; start test process for testing

;jsr testproc2_start

jsr hardware_init ; recognize and initialize hardware

jsr fs_init

jsr bootscreen

set a, [autoclockflag]

ife a, 1

jsr autoclock

ife a, 0

jsr standardclock

; Now, we need to set up the CLI process to get it all rolling

set a, cli ; starter PC of newproc

jsr newproc ; get the process for it going

set b, cli_name ; name of process

jsr setprocname ; set that

set b, 3 ; desired priority

jsr setprocpriority ; set that too

jsr startproc ; get process schedulable

; start up our processcleaner

jsr processcleaner

; start up interrupt handler, which will get actual OS running and end boot process

ias inthand

; after the boot process, idle until scheduler takes over

:idle

iaq 0 ; make sure interrupts are on (for scheduler to resume control)

:idleloop

set pc, idleloop ; endless loop

; OS has crashed for some reason

:crash

ias 0 ; no interrupts

sub pc, 1 ; hang

; autosset clock settings

:autoclock

; test cpu clock speed to set scheduling speed

set b, 1

set i, [clock_hwnum]

set a, 0

hwi i

set i, 0

:speed_test_loop

add i, 1

ifl i, 0xffff

set pc, speed_test_loop

set i, [clock_hwnum]

set a, 1

hwi i

div c, 40

add c, 1

set b, c

set a, 0

hwi i

set pc, pop

#segment text

:autoclock_cmd

dat "autoclock", 0

#segment code

:standardclock

set i, [clock_hwnum]

set a, 0

set b, 6

hwi i

set pc, pop

; TEST FUNCTIONS

:testproc2_start

set push, a

set a, testproc2

jsr newproc

set b, testprocname

jsr setprocname

jsr startproc

set a, pop

set pc, pop

:testproc2

set a, 0

set b, 0

set c, 0

:loopy

add a, 1

add b, ex

add c, ex

set pc, loopy

#segment text

:testprocname

dat "Test process", 0

:testproc_cmd

dat "testproc", 0

; OS API FUNCTIONS

; Designed to be used by other programs and the OS alike

#segment code

; STANDARD FUNCTIONS

; memcpy

; copies C words from A to B

:memcpy

set push, i

set push, j

set push, c

set i, a

set j, b

add c, i

:memcpy_loop

sti [j], [i]

ifl i, c

set pc, memcpy_loop

set c, pop

set j, pop

set i, pop

set pc, pop ; return

; memclear

; clears b words of memory starting at A

:memclear

set push, i

set push, j

set i, a ; beginning

set j, a

add j, b ; end

:memclear_loop

set [i], 0 ; clear

add i, 1 ; increment

ifl i, j ; not at end

set pc, memclear_loop ; keep going

set j, pop

set i, pop

set pc, pop

#segment code

; INTERRUPT HANDLER

; This is the OS interrupt handler. It handles all interrupts that can be caused.

; Interrupt Codes

; 0x01 - clock interrupt

; 0x02 - non-clock scheduling interrupt

; 0x03 - keyboard interrupt

; 0x20 - malloc

; Interrupt Handler data

:inthand

iaq 1 ; queue interrupts

set [extempstore], ex ; quickly store this

; handle the interrupts

set push, intreturn ; pseudo-jsr

ife a, 0x01 ; clock interrupt

set pc, clock_interrupt

ife a, 0x02

set pc, ci_cont ; schedule without incrementing clock

ife a, 0x20 ; malloc interrupt

set pc, malloc_interrupt

:intreturn

; end interrupt handler for non-process-switching interrupts and go back to proper code

rfi 1

; specific interrupt handlers

:keyboard_interrupt

set pc, pop ; return

:clock_interrupt

; increase system time

add [sys_time], 1 ; 32 bit increment

add [sys_time+1], ex

:ci_cont

; get all the things as they should be

add sp, 1 ; undo inthand's push

set pc, schedule ; go schedule next process

:malloc_interrupt

; do a malloc

set a, pop ; get a off stack

iaq 0 ; unqueue interrupts

set pc, malloc ; go do that

; PROCESS FUNCTIONS

; functions to handle the OS processes stuff

; process stati:

; 1 - run as normal

; 2 - in creation

; 3 - sleeping

; 4 - being killed

; 5 - indefinitely suspended

#segment data

; schedule

; Decide what process to run next, then set up and give that process control of dcpu

:stempstore

dat 0

:extempstore

dat 0

#segment code

:schedule

; first things first: store data of currently running process

set [stempstore], b

set a, [cur_proc]

ifl a, 2 ; not legit process

set pc, sched_start2

add a, [proc_list_start]

set b, [a] ; data of current process

set [b+7], pop ; pop A from stack

set [b+4], pop ; pop PC from stack

set [b+8], [stempstore] ; get b from temp

set [b+9], c ; store the rest of registers

set [b+10], x

set [b+11], y

set [b+12], z

set [b+13], i

set [b+14], j

set [b+5], sp ; store sp

:sched_start2

set [cur_proc], 0x1 ; kernel process

set sp, [kernel_sp]

set i, [proc_list_start]

add i, 2 ; bring i to start of processes

set z, [proc_list_start]

add z, [proc_maxnum]

set a, 0 ; maxval

set b, 0 ; maxpid

:sched_loop

set c, [i] ; proc data for i

set x, [c] ; shortcut

ife c, 0 ; nothing to do here...

set pc, sched_loop_end

ife x, 3 ; process sleeping

set pc, sched_sleep_handle ; handle that stuff

ifn x, 1 ; process not supposed to be running

set pc, sched_loop_end

set x, [sys_time]

set y, [sys_time+1]

sub x, [c+2] ; lower 16 bit difference

add y, ex ; factor in overflow

sub y, [c+3] ; upper 16 bit difference

add x, [c+1] ; increase time based on priority

add y, ex ; overflow

ifg y, 0 ; something present in y

set x, 0xffff ; set x to max possible

ifl x, a ; didn't set new max

set pc, sched_loop_end

; did set new max

set a, x ; change vals

set b, i

:sched_loop_end

add i, 1 ; increment

ifl i, z ; not at end

set pc, sched_loop

; now we know what process to launch, we have to launch it

set a, b ; move b to a

ife a, 0 ; no process wants to be fun

set pc, idle ; idle and wait

set b, [a]

set [b+2], [sys_time]

set [b+3], [sys_time+1]

sub a, [proc_list_start] ; a is pid of process to launch

; automatically continue to launch...

iaq 0 ; unqueue

:launch ; can also be started not from scheduler

ifl a, 2 ; not valid process

set pc, idle ; go idle and wait

iaq 1 ; queue interrupts

set [cur_proc], a ; set up current process

add a, [proc_list_start] ; bring a to entry in list

set a, [a] ; bring a to proc data

set b, [a+8] ; start setting registers

set c, [a+9]

set x, [a+10]

set y, [a+11]

set z, [a+12]

set i, [a+13]

set j, [a+14]

set ex, [a+6]

set sp, [a+5]

set push, [a+4] ; push pc

set a, [a+7]

iaq 0 ; unqueue interrupts

set pc, pop ; process launched

; handle sleeping process

:sched_sleep_handle

set x, [sys_time]

set y, [sys_time+1]

ifl y, [c+16] ; upper 16 bits less

set pc, sched_loop_end

ifl x, [c+15] ; lower 16 bits less

set pc, sched_loop_end

; stop sleeping!

set [c], 1 ; set status 1 - run normally

set pc, sched_loop_end ; go back into scheduling loop

:cli_kill

ifl a, 1 ; missing argument

set pc, cli_kill_fail

set a, [b]

set i, [a]

sub i, 0x30 ; ascii number to

add a, 1

set j, [a]

ife j, 0 ; single number given in arguments

set pc, cli_kill_1d

; 2 digit

sub j, 0x30

mul i, 10

add j, i ; j is pid

set a, j

jsr killproc

set pc, pop

:cli_kill_1d

set a, i

jsr killproc

set pc, pop

:cli_kill_fail

set pc, pop

#segment text

:cli_kill_cmd

dat "kill", 0

; processcleaner

; This process goes and cleans up after dead processes.

#segment text

:procclean_name

dat "Process Cleaner", 0

#segment code

:processcleaner

; start up processcleaner process

set push, a

set a, processcleaner_outer

jsr newproc

set b, procclean_name

jsr setprocname

jsr startproc

set a, pop

set pc, pop ; return

:processcleaner_outer ; outer loops

set i, [proc_list_start]

set j, i

add i, 1

add j, [proc_maxnum]

:pcloop

add i, 1

set b, [i]

ife [b], 4

set pc, pc_clean

:pcloop_return

ifl i, j ; not and end

set pc, pcloop

:pc_break

set a, 10 ; 10 cycle sleep

jsr sleepproc ; go sleep

set pc, processcleaner_outer

:pc_clean

set [i], 0 ; remove process listing

set a, i

sub a, [proc_list_start] ; get pid

jsr free_pid ; remove memory

set pc, pcloop_return

; Lists data on all active processes

:proclist

set push, a

set push, c

set push, x

set push, y

set push, i

set push, j

set a, proclist_header

jsr print

jsr newline

set a, 32

jsr malloc ; allocate some stuff

set i, [proc_list_start]

set j, i

add i, 2

add j, [proc_maxnum] ; j to end

:proclist_loop

set a, [i]

ife a, 0 ; no process in this slot

set pc, proclist_loop_end

ife [a], 4 ; process to be killed

set pc, proclist_loop_end

; there is a process here

set x, i

sub x, [proc_list_start] ; x is pid

set y, x ; y too

div x, 10 ; upper digit base 10

mod y, 10 ; lower digit base 10

add x, 48 ; bring to ascii

add y, 48

set [c], x ; put into string in malloc'ed area

set [c+1], y

set push, a

set a, c

jsr print

set a, pop

jsr space

jsr space

set a, [a+18] ; pointer to process name

jsr print ; print name

jsr newline ; get newline

:proclist_loop_end

add i, 1

ifl i, j

set pc, proclist_loop

set a, 32

jsr free ; free what we malloced

set j, pop

set i, pop

set y, pop

set x, pop

set c, pop

set a, pop

set pc, pop

#segment text

:proclist_header

dat "PID Process Name", 0

:proclist_cmd

dat "proclist", 0

#segment code

:getc

set push, a

set push, b

set push, j

set j, [kb_hwnum]

set a, 1

:getc_loop

hwi j

ife c, 0 ; nothing yet

set pc, getc_loop

set j, pop

set b, pop

set a, pop

set pc, pop

#segment text

; Screen for OS to display while booting

:bootsdat

dat " Booting up OS!", 10

dat " Please wait...", 0

#segment code

:bootscreen

set push, a

jsr newline

jsr newline

jsr newline

set a, bootsdat

jsr print

set a, pop

set pc, pop; --------------------------------------------

; Title: malloc

; Date: 7/13/2012

; Version:

; --------------------------------------------

; MALLOC

; allocates A words of RAM, returning in C the address of the RAM

:malloc

set push, a

set push, b

set push, i

set push, j

ife [cur_proc], 0

set [cur_proc], 0xffff

; find in registry enough spaces for what we want

; convert A from words to blocks

jsr calc_block_num

set i, [malloc_reg]

;set i, [malloc_reg_pointer]

:malloc_find_loop

set j, 0 ; number of found blocks

:malloc_inner_loop

ifn [i], 0 ; current block unused

set pc, mil_fail ; found a used block, restart looking

add j, 1 ; increment found blocks count

add i, 1 ; increment search counter

ife j, a ; we've found enough blocks

set pc, malloc_success ; finished alloc

ife i, malloc_reg_end ; finished search, malloc failed

set pc, malloc_fail

set pc, malloc_inner_loop

:malloc_success

sub i, j ; set i to beginning of found area in registry

; indicate allocation

set push, i

set j, i

add j, a

:m_allocate_loop

set [i], [cur_proc]

add i, 1

ifl i, j

set pc, m_allocate_loop

set [malloc_reg_pointer], i

set i, pop

sub i, [malloc_reg] ; set i to number of blocks after start

mul i, 32 ; set i to offset of data start

add i, [malloc_start] ; set i to actual location

set c, i ; move that into c

:malloc_break

set j, pop

set i, pop

set b, pop

set a, pop

set pc, pop

; failure of malloc inner loop, just increment and restart

:mil_fail

set j, 0 ; reset found blocks

add i, 1 ; go to next block for search

set pc, malloc_inner_loop

:malloc_fail

; this is bad - not enough memory for what we want

; have to terminate current process

set pc, crash

; FREE

; frees A words starting at address given in C

:free

set push, a

set push, b

set push, c

jsr calc_block_num ; switch a from words to blocks

sub c, [malloc_start]

div c, 32

add c, [malloc_reg] ; c is place in malloc reg

set b, c

add b, a

:free_loop

set [c], 0 ; clear

add c, 1 ; increment

ifl c, b ; not at end

set pc, free_loop ; continue

set c, pop

set b, pop

set a, pop

set pc, pop

; free_pid

; frees all blocks for a certain pid

:free_pid

set push, i

set push, j

set i, [malloc_reg]

set j, [malloc_reg_end]

:freepid_loop

ife [i], a ; remove this allocation.

set [i], 0 ; do that

add i, 1 ; increment

ifl i, j ; not at end yet

set pc, freepid_loop ; keep going

set j, pop

set i, pop

set pc, pop ; return

:calc_block_num

set push, x

set x, a

mod x, 32

div a, 32

ifn x, 0

add a, 1

set x, pop

set pc, pop ; return

; malloc_init

; Initializes dynamic memory stuff

:malloc_init

set push, a

set push, b

set push, c

set a, [malloc_reg]

set b, [malloc_length]

div b, 32

add b, a

set [malloc_reg_end], b

set a, [malloc_start]

add a, [malloc_length]

set [malloc_end], a

set [malloc_reg_pointer], [malloc_reg]

set c, pop

set b, pop

set a, pop

set pc, pop ; return

; --------------------------------------------

; Title: proc

; Date: 7/13/2012

; Version:

; --------------------------------------------

#segment code

; newproc

; Creates a process skeleton and returns a pointer in A

; Skeleton does not contain most critical data required to start it

:newproc

iaq 1 ; queue interrupts during this

set push, a

set push, b

set push, c

set push, [cur_proc]

set [cur_proc], 0x1 ; proc data stored under kernel pid

jsr newpid ; get a new pid in a

set push, a ; push pid

set a, 32 ; length of proc data

jsr malloc ; allocate proc data

set a, pop

set [a], c ; set pointer to new process data location

set [c], 2 ; status of 2 - in creation

set [c+1], 1 ; priority - 1 (standard)

set b, c

add b, 32 ; b is end

set push, c

:newprocloop

add c, 1 ; increment

set [c], 0 ; clear a

ifl c, b ; not at end

set pc, newprocloop ; keep going

set [cur_proc], a ; new process's pid

sub [cur_proc], [proc_list_start]

set push, a

set a, 1024 ; size of new process's stack

jsr malloc ; allocate its stack

set b, c ; temp

set a, pop

add b, 1023 ; bring to start of stack - 1

set c, pop ; restore

set [c+5], b ; set SP

set [b], kill_me ; last address on stack, if it set pc, pops one time too many

set [c+2], [sys_time] ; time of creation

set [c+3], [sys_time + 1] ; cont

set a, [cur_proc]

set [cur_proc], pop

set c, pop

set b, pop

set push, a

add a, [proc_list_start]

set a, [a]

set [a+4], pick 1 ; pc

set a, pop

add sp, 1

iaq 0 ; unqueue interrupts

set pc, pop ; return

; newpid

; Finds a new, empty process id and returns it.

:newpid

set push, i

set push, j

set i, [proc_list_start]

add i, 2

set j, i

add j, [proc_maxnum]

sub j, 2

:np_loop

ife [i], 0

set pc, np_found

add i, 1

ife i, j

set pc, np_fail

set pc, np_loop

:np_fail

:np_found

set a, i

set j, pop

set i, pop

set pc, pop ; return

; startproc

; This process takes a pid of a process "in creation," and sets it to

; actually start, aka eligiblizes it for scheduling

:startproc

set push, a

ifl a, 2

ifg a, 16

set pc, pop ; invalid pid

add a, [proc_list_start] ; get to proc list entry

set a, [a] ; get pointer to proc data

ifn [a], 2 ; process NOT in creation

set pc, pop ; return without doing anything

set [a], 1 ; set status 1: run normally

set a, pop

set pc, pop ; return

; killproc

; "kills" the process with pid A

; This doesn't actually kill it, but rather mark it for death,

; to be cleaned up later.

:killproc

set push, a

add a, [proc_list_start]

ifl a, 2

ifg a, 16

set pc, pop ; invalid pid

set a, [a]

set [a], 4 ; set status 4: kill process

set a, pop

set pc, pop ; return

; kill_me

; This function causes the process that calls it to die.

:kill_me

set a, [cur_proc]

jsr killproc ; flag process to die

int 0x02 ; auto-reschedule

set pc, idle

; set the name of a pid A to *B

:setprocname

ifl a, 2

ifg a, 0x10

set pc, pop ; do nothing

set push, a

add a, [proc_list_start]

set a, [a]

set [a+18], b ; set that pointer there

set a, pop

set pc, pop

:setprocpriority

ifl a, 2

ifg a, 0x10

set pc, pop ; do nothing

set push, a

add a, [proc_list_start]

set a, [a]

set [a+1], b ; set that pointer there

set a, pop

set pc, pop

#segment code

; sleepproc

; causes caller to sleep for A cycles

:sleepproc

set push, z

set push, y

set push, x

set push, a

set a, [cur_proc] ; get current process

add a, [proc_list_start]

set a, [a]

set y, [sys_time+1]

set x, [sys_time]

set z, a

set a, pop

add x, a

add y, ex

set a, z

set [a+15], x

set [a+16], y

set [a], 3 ; set status 3 - sleeping

set x, pop

set y, pop

set z, pop

int 0x02 ; reschedule

set pc, pop ; wait

; --------------------------------------------

; Title: string

; Date: 9/23/2012

; Version:

; --------------------------------------------

; strcpy

; copies null-terminated string from A to B

:strcpy

set push, c

jsr strlen ; get length in C

jsr memcpy ; do the copy

set c, pop

set pc, pop ; return

; strlen

; gets the length of a null-terminated string at A into C

:strlen

set push, i

set i, a

:strlen_loop

ife [i], 0 ; found end

set pc, strlen_end ; break loop

add i, 1 ; increment

set pc, strlen_loop ; restart loop

:strlen_end

sub i, a ; set i to length

set c, i ; set c to length

set i, pop

set pc, pop ; return

; Compares string *a and *b, c = 0 for mismatch, c = 1 for match

:strcmp

set push, a

set push, i

set push, j

set i, a

set j, b

:strcmp_inner_loop

set a, [i]

set b, [j]

ifn a, b ; difference found!

set pc, strcmp_fail ; go fail

ife a, 0 ; done

set pc, strcmp_succeed ; yay!

add i, 1 ; increment

add j, 1

set pc, strcmp_inner_loop ; keep going

:strcmp_end

set j, pop

set i, pop

set a, pop

set pc, pop ; return

:strcmp_fail

set c, 0 ; for fail

set pc, strcmp_end ; end function

:strcmp_succeed ; for success

set c, 1 ; for succeed

set pc, strcmp_end ; end function; --------------------------------------------

; Title: tests

; Date: 9/28/2012

; Version:

; --------------------------------------------

; a test process for the operating system

#segment text

:test_text

dat "testing1234567899", 8, "0", 10, 0

:test_cmd

dat "test", 0

#segment code

:testing

; test printing

set i, 0

set a, test_text

:test_text_loop

jsr print

add i, 1

ifl i, 20

set pc, test_text_loop

; test printing hexes

set a, 0x1000

:test_hex_loop

jsr print_hex

jsr newline

add a, 0x20

ifl a, 0x2000

set pc, test_hex_loop

; test process creation

set i, 0

set x, testproc2

:test_proc_loop

jsr cmd_execute_new ; spawn the new process

add i, 1

ifl i, 10

set pc, test_proc_loop

; proclist

jsr newline

jsr proclist

; wait a little bit

set a, 100

jsr sleepproc

; kill all the processes

set a, 4

:test_kill_loop

jsr killproc

add a, 1

ifl a, 14

set pc, test_kill_loop

jsr newline

jsr proclist

; done!