wg_asm ABI: Word structure: 64bits per word Datatypes: Instruction: 8bits opcode 4bits condition code 6bits addressing mode 1 6bits addressing mode 2 20bits data 1 20bits data 2 Integer: 64bits data (unsigned or 2s complement) Float: 64bits data (IEEE double) Pointer: 29bits padding 3bits byte offset 32bits address Function call: : There are four standard calling conventions, gencall, regcall, syscall, and intcall. These have no effect on code generation, and are simply annotations. gencall (for general functions): (Registers preserved) Caller responsibility:| [arg] holds number of stack arguments given to the function Callee responsibility:| [arg] holds number of stack return values All registers other than [arg] and [jump] should be in the same state as before the call No garbage may be left on the hstack regcall (for functions which take a specific small number of arguments): (Registers undefined) Caller responsibility:| Arguments 1, 2, 3, 4 are placed in [arg], [gp0], [gp1], [counter] respectively. Additional arguments are passed on the stack. All argument registers not used for arguments must be saved by the caller. Callee responsibility:| Function must know how many arguments to expect. Return values 1, 2, 3, 4 are held in [arg], [gp0], [gp1], [counter] respectively. The stack and hstack must contain no garbage syscall (for system calls): (Registers preserved) Caller responsibility:| Arguments 1, 2, 3, 4 are placed in [arg], [gp0], [gp1], [counter] respectively. Callee responsibility:| Function must know how many arguments to expect. Return values 1, 2, 3, 4 are held in [arg], [gp0], [gp1], [counter] respectively. The stack and hstack must contain no garbage. All registers except [jump] not used for arguments or return values must be preserved. intcall (interrupt handlers): (Registers undefined in general) Caller responsibility: | N/A (called implicitly) Callee responsibility:| Must handle before returning. [jump] holds the interrupt number. Other registers unchanged from calling context. Program state on return unspecified by the ABI, instead it is up to the particular handler. List of defined trap codes: 000h $__no_error__ : not an error (pri: 0) # class handlers 00Nh : if the high nibble is zero, sets a class handler for all 0Nnh interrupts. Defined names: 001h $__iclass_math__ : (pri: 1) 002h $__iclass_mem__ : (pri: 2) 003h $__iclass_stack__ : (pri: 2) 004h $__iclass_exec__ : (pri: 2) 005h $__iclass_com__ : (pri: 1) 006h $__iclass_sys__ : (pri: 3) 008h $__iclass_soft__ : (pri: 1) # math errors 010h $__div_by_zero__ : div with 0 divisor 011h $__fdiv_by_zero__ : fdiv with 0 divisor 012h $__signed_ovlf__ : A signed integer operation overflowed 013h $__signed_unfl__ : A signed integer operation underflowed 014h $__fpe_domain__ : An FP instruction was given an argument out of its domain. (i.e. push -1 sqrt) 015h $__fpe_ovfl__ : the result of an FP instruction is infinite but out of range 016h $__fpe_unfl__ : the result of an FP instruction is non-zero but becomes zero after rounding # memory errors (segfaults) 020h $__perm_no_read__ : read from non-visble address 021h $__perm_nowrite__ : write to non-writable address 022h $__perm_no_exec__ : jump to noexec address 023h $__perm_denied__ : jump to privileged code 024h $__exec_nsm_v__ : jump to writable memory with noselfmodify set # stack error conditions 030h $__stack_crash__ : Attempted to grow the stack into the hstack 031h $__hstack_crash__ : Attempted to grow the hstack into the stack 032h $__stack_clear__ : Popped from empty stack 033h $__hstack_clear__ : Popped from empty hstack 034h $__null_deref__ : attempted to read from the first 16 bytes of memory # Interrupts relating to illegal code execution 040h $__call_depth__ : Call stack capacity exceeded 042h $__illegal_inst__ : Attempted execution of an undefined instruction 043h $__handle_none__ : Attempted to handle when no interrupt was being processed. 044h $__no_privs__ : Attempted to execute a privileged instruction in user mode # serial interrupts 050h $__no_input__ : executed input with empty queue 051h $__no_output__ : Executed output with output device not accepting output # system interrupts (do not catch) 060h (no symbol) : push caused stack to cross a page boundary 061h (no symbol) : hpush caused hstack to cross a page boundary 063h (no symbol) : transfer caused call stack to cross a page boundary 064h (no symbol) : return from main function (empty call stack) 065h (no symbol) : pop caused stack to cross a page boundary 066h (no symbol) : hpop caused hstack to cross a page boundary 067h (no symbol) : return caused call stack to cross a page boundary 068h $__resume_exec__ : Resume from a halt at the next instruction. # timing interrupts 070h $__timer_fired__ : A time-based interrupt timer has completed. 071h $__ccnt_fired__ : A cycle-based interrupt timer has completed. # Software interrupts 080h $__assert_fail__ : used for failed assert 081h - 08fh (no symbol): Reserved to the programmer Exception handling: Interrupts: | Program state is unchanged by any instruction that traps. General code: | (*err)+HH for HH in range 000h ... 0FFh holds a jump position Initial configuration: *[err]+0Nh for all N except 6 points to a builtin function, shown here: proc __ABI_handler__ output *"\nExited by interrupt: " lookup [jump] output *%P output *".\n" set [arg] [jump] err end *[err]+6 points to a different builtin function, shown here: proc __ABI_sysfault__ set [arg] [jump] set [jump] $sys_except systransfer handle return end [err]+$__fpe_ovfl__ and [err]+$__fpe_unfl__ are set to functions which quietly set [flag], named $__ABI_fpe_ovfl__, and $__ABI_fpe_unfl__ respectively. All other [err]+0NNh are null. Upon raising an interrupt 0IIh, first [err]+0IIh is checked for a jump location. The conditions are: If [err]+0IIh == 0, check [err]+00Ih instead Else if select([err]+0IIh, 1<<32) == 0, perform a local jump. Else, perform a function call. (For difference, see below) If [err]+00Ih == 0, goto $__ABI_invalid__, shown here: proc __ABI_invalid__ output *$"\nInterrupt raised without handler.\n" set [arg] [jump] err end An interrupt handler with the value 1 is masked, that is, no jump is performed at all. Exception handler responsibility (function type):| [jump] holds a numeric value representing the exception. All other registers are unaltered. Execution handler responsibility (label type):| [jump] holds a numeric value representing the exception No provision for returning. Operating System:| The basic OS includes a small library of functions and handles the initial memory layout of the program. Initially, the devices 1, 2, 3 correspond to STDIN, STDOUT, and STDERR. Memory layout: Memory is organized into 256 pages of 4096 words. Each page has certain associated permissions. The OS creates the following structure at program initialization text segment: pages 0-3, 16k words. read-only. 0-15: reserved 16-31: Special input register alias addresses 32-1055: Input register alias addresses 1056-2047: symbols (1-2W each; 1-8 or 9-16 characters) 2048-16383: strings/data ROM Code/scratch segment:| 32 pages, 128k words memory[4] = MMUentry(Perms::read | Perms::write | Perms::exec) Call stack segment:| 2 pages, 8k words memory[36] = MMUentry(Perms::read | (Perms::write * selfmod) | Perms::priv) Data stack segment:| 864k words memory[38] = MMUentry(Perms::read | Perms::write) High data stack:| grows downward toward data stack memory[251] = MMUentry(Perms::read | Perms::write) Library code segment:| 4 pages, 16k words memory[252] = MMUentry(Perms::read | Perms::exec) memory[253] = MMUentry(Perms::read | Perms::exec) memory[254] = MMUentry(Perms::read | Perms::exec) memory[255] = MMUentry(Perms::read | Perms::exec) Library code: The standard library exposes the following symbols $ua_strcpy: Function regcall(length, source, dest, c_o): Copies len words starting from *source to *dest, with 3-bit offsets (see unaligned memory access instructions) for source and dest stored in the high and low halfwords of c_o, respectively. The offsets are implicitly anded with 7. $memcmp: Function regcall(length, a, b): compares the ranges of size length at a and b lexicographically $ua_strcpy: Function regcall(length, source, dest, c_o): System calls: $noselfmodify: syscall(): revokes write permission to code segment $doselfmodify: syscall(): grants write permission to code segment $comstatus: syscall(device): returns status of com device. $sys_except: syscall(ex): Handles a system interrupt. Usually maps/unmaps pages. $rand: syscall(words): push (words) words of random data from the host's /dev/urandom or similar to the stack $shutdown: syscall(retc): Ends the process. $fopen: syscall(fname): Opens a file on the first unused device and returns its device number. $fclose: syscall(device): Closes the file opened on device.