What is the best means of passing address pointers in a segmented architecture ?
Background:
I have a really simple segmented processor core in the works.
Its a 32 bit word oriented RISC processor (30-40 insn). Using segments a 40 bit address is supported (2^42 bytes).
The goal is having enough support to run an OS like LINUX.
The core is not pipelined. It takes multiple clock cycles to fetch, decode and execute each instruction. A typical instruction will take five clock cycles.
The segmentation model allows virtual addresses with bounds checking. There's no stack segment.
Stack addresses are part of the data segment, but there are dedicated stack upper and lower bounds registers, and a stack fault rather than a bounds fault. There's minimal privilege level checking on some instructions that should be executed only in supervisor mode.
There are four complete sets of registers including segment registers and the flags register. There is one set for each operating mode. So there is no need to save/restore registers when switching modes.
The upper three bits of an effective address identify the segment register used for address formation. So addressing is limited to 29 bits (2GB) in a segment. The program counter is limited to 27 bits (512MB per segment) this is tied to the fact there is only 27 bits available in an jump instruction to specify the address with.
I came up with a way to pass address parameters by first disecting the address into components using extraction instructions. But it's really ugly but I can't see an easy way around it. The actual values for the segmented part of the address have to be passed as well as the offset. So ther's an extraction at call time and then a rebuild of the address inside the API function.
Code:
// Before the call to the api
// For instance the pointer might be to thread data in fs:r1
exs r2,r1 ; extract segment value into r2
exl r3,r1 ; extract segment limit value
and r1,r1,#$1FFFFFFF ; clear the top 3 bits of offset
mov sys,r1,r2,r3 ; move registers to system regs
brk #1 ; invoke the api
// Sample entrance to api, perhaps to display a string
// The register set is automatically switched by the BRK
// instruction. The move to alternate register set
// instruction must have been used to setup parameters.
//
api_entrance:
mtspr es,r2 ; use es as the segment register
mtspr esl,r3 ; and set limit
or r1,r1,#$20000000 ; set reference to es
; the pointer is now in es:r1
...
rti
The BRK instruction stores the code segment limit, code segment,program counter and machine status word on the stack. And switches to register set #2.
The RTI instruction then restores them all. And switches back to the original register set.