mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v027 release.
This version replaces libui with miu -- a new GUI wrapper library, and cleans up large portions of the source code. Unfortunately, the GUI rewrite took far, far longer than I ever imagined. As a result, no work has gone into the core emulation for this version. But with the GUI rewrite out of the way, that should change in the near future. And thanks to the new UI library, I can now begin work on adding a cross-platform debugger to bsnes, at long last. Changelog: - Major source code cleanup (lib/, ui/miu/, ui/vai/) - Cheat code editor was broken in v0.026, this is now fixed - Cheat code file format simplified for human readability - Makefile install target improvements [belegdol] - libui replaced with miu GUI library - Custom video / audio / input drivers replaced with vai HW library - ppc and ppc64 libco targets added [Vas Crabb] - x86 and x86-64 libco targets now work on OS X [Lucas Newman]
This commit is contained in:
commit
b934ce41d9
|
@ -0,0 +1,478 @@
|
|||
;*****
|
||||
;libco.ppc (2007-11-29)
|
||||
;author: Vas Crabb
|
||||
;license: public domain
|
||||
;
|
||||
;cross-platform PowerPC implementation of libco
|
||||
;special thanks to byuu for writing the original version
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- gcc; mac os x; ppc
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- GPR1, GPR13 - GPR31
|
||||
;- FPR14 - FPR31
|
||||
;- V20 - V31
|
||||
;- VRSAVE, CR2 - CR4
|
||||
;
|
||||
;[volatile registers]
|
||||
;- GPR0, GPR2 - GPR12
|
||||
;- FPR0 - FPR13
|
||||
;- V0 - V19
|
||||
;- LR, CTR, XER, CR0, CR1, CR5 - CR7
|
||||
;*****
|
||||
|
||||
|
||||
;Declare some target-specific stuff
|
||||
|
||||
.section __TEXT,__text,regular,pure_instructions
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.machine ppc
|
||||
|
||||
|
||||
;Constants
|
||||
|
||||
.cstring
|
||||
.align 2
|
||||
|
||||
_sysctl_altivec:
|
||||
.ascii "hw.optional.altivec\0"
|
||||
|
||||
|
||||
;Declare space for variables
|
||||
|
||||
.lcomm _co_environ,4,2 ;bit 0 = initialised, bit 1 = have Altivec/VMX
|
||||
.lcomm _co_primary_buffer,1024,2 ;buffer (will be zeroed by loader)
|
||||
|
||||
.data
|
||||
.align 2
|
||||
|
||||
_co_active_context:
|
||||
.long _co_primary_buffer
|
||||
|
||||
|
||||
.text
|
||||
.align 2
|
||||
|
||||
|
||||
;Declare exported names
|
||||
|
||||
.globl _co_active
|
||||
.globl _co_create
|
||||
.globl _co_delete
|
||||
.globl _co_switch
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_active();
|
||||
;return = GPR3
|
||||
;*****
|
||||
|
||||
_co_active:
|
||||
mflr r0 ;GPR0 = return address
|
||||
bcl 20,31,L_co_active$spb
|
||||
L_co_active$spb:
|
||||
mflr r2 ;GPR2 set for position-independance
|
||||
addis r3,r2,ha16(_co_active_context-L_co_active$spb) ;get value in GPR3
|
||||
lwz r3,lo16(_co_active_context-L_co_active$spb)(r3)
|
||||
mtlr r0 ;LR = return address
|
||||
blr ;return
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
;GPR3 = heapsize
|
||||
;GPR4 = coentry
|
||||
;return = GPR3
|
||||
;*****
|
||||
|
||||
_co_create:
|
||||
mflr r0 ;GPR0 = return address
|
||||
stmw r30,-8(r1) ;save GPR30 and GPR31
|
||||
stw r0,8(r1) ;save return address
|
||||
stwu r1,-(2*4+16+24)(r1) ;allocate 16 bytes for locals/parameters
|
||||
|
||||
;create heap space (stack + register storage)
|
||||
addi r31,r3,1024-24 ;subtract space for linkage
|
||||
mr r30,r4 ;GPR30 = coentry
|
||||
addi r3,r3,1024 ;allocate extra memory for contextual info
|
||||
bl L_malloc$stub ;GPR3 = malloc(heapsize + 1024)
|
||||
add r4,r3,r31 ;GPR4 points to top-of-stack
|
||||
rlwinm r5,r4,0,0,27 ;force 16-byte alignment
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
stw r30,8(r5) ;store entry point
|
||||
addi r6,0,2+19+18*2+12*4+1 ;clear for CR, old GPR1, 19 GPRs, 18 FPRs, 12 VRs, VRSAVE
|
||||
addi r0,0,0
|
||||
addi r7,0,4 ;start at 4(GPR5)
|
||||
mtctr r6
|
||||
L_co_create$clear_loop:
|
||||
stwx r0,r5,r7 ;clear a word
|
||||
addi r7,r7,-4 ;increment pointer
|
||||
bdnz L_co_create$clear_loop ;loop
|
||||
stwu r5,-448(r5) ;store top of stack
|
||||
|
||||
;initialize context memory heap and return
|
||||
stw r5,0(r3) ;*cothread_t = stack heap pointer (GPR1)
|
||||
lwz r1,0(r1) ;deallocate stack frame
|
||||
lwz r8,8(r1) ;fetch return address
|
||||
lmw r30,-8(r1) ;restore GPR30 and GPR31
|
||||
mtlr r8 ;return address in LR
|
||||
blr ;return
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" void co_delete(cothread_t cothread);
|
||||
;GPR3 = cothread
|
||||
;*****
|
||||
|
||||
_co_delete:
|
||||
b L_free$stub ;free(GPR3)
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" void co_switch(cothread_t cothread);
|
||||
;GPR3 = cothread
|
||||
;*****
|
||||
;
|
||||
;Frame looks like:
|
||||
;
|
||||
;Old New Value
|
||||
; 8(r1) 456(r1) Saved LR
|
||||
; 4(r1) 452(r1) Saved CR
|
||||
; 0(r1) 448(r1) Old GPR1
|
||||
; -4(r1) 444(r1) Saved GPR31
|
||||
; -8(r1) 440(r1) Saved GPR30
|
||||
;... ... ...
|
||||
; -72(r1) 376(r1) Saved GPR14
|
||||
; -76(r1) 372(r1) Saved GPR13
|
||||
; -80(r1) 368(r1) Saved VRSAVE
|
||||
; -84(r1) 364(r1) +++
|
||||
; -88(r1) 360(r1) Saved FPR31
|
||||
; -92(r1) 356(r1) +++
|
||||
; -96(r1) 352(r1) Saved FPR30
|
||||
;... ... ...
|
||||
;-212(r1) 236(r1) +++
|
||||
;-216(r1) 232(r1) Saved FPR15
|
||||
;-220(r1) 228(r1) +++
|
||||
;-224(r1) 224(r1) Saved FPR14
|
||||
;-228(r1) 220(r1) +++ value
|
||||
;-232(r1) 216(r1) +++ len
|
||||
;-236(r1) 212(r1) +++
|
||||
;-240(r1) 208(r1) Saved VR31
|
||||
;-244(r1) 204(r1) +++
|
||||
;-248(r1) 200(r1) +++
|
||||
;-252(r1) 196(r1) +++
|
||||
;-256(r1) 192(r1) Saved VR30
|
||||
;... ... ...
|
||||
;-388(r1) 60(r1) +++
|
||||
;-392(r1) 56(r1) +++
|
||||
;-396(r1) 52(r1) +++
|
||||
;-400(r1) 48(r1) Saved VR21
|
||||
;-404(r1) 44(r1) +++
|
||||
;-408(r1) 40(r1) +++ Param 5 (GPR7)
|
||||
;-412(r1) 36(r1) +++ Param 4 (GPR6)
|
||||
;-416(r1) 32(r1) Saved VR20 Param 3 (GPR5)
|
||||
;-420(r1) 28(r1) - Param 2 (GPR4)
|
||||
;-424(r1) 24(r1) - Param 1 (GPR3)
|
||||
;-428(r1) 20(r1) - Reserved
|
||||
;-432(r1) 16(r1) - Reserved
|
||||
;-436(r1) 12(r1) - Reserved
|
||||
;-440(r1) 8(r1) - New LR
|
||||
;-444(r1) 4(r1) - New CR
|
||||
;-448(r1) 0(r1) Saved GPR1
|
||||
|
||||
|
||||
_co_switch:
|
||||
stmw r13,-76(r1) ;save preserved GPRs
|
||||
stfd f14,-224(r1) ;save preserved FPRs
|
||||
stfd f15,-216(r1)
|
||||
stfd f16,-208(r1)
|
||||
stfd f17,-200(r1)
|
||||
stfd f18,-192(r1)
|
||||
stfd f19,-184(r1)
|
||||
stfd f20,-176(r1)
|
||||
stfd f21,-168(r1)
|
||||
stfd f22,-160(r1)
|
||||
stfd f23,-152(r1)
|
||||
stfd f24,-144(r1)
|
||||
stfd f25,-136(r1)
|
||||
stfd f26,-128(r1)
|
||||
stfd f27,-120(r1)
|
||||
stfd f28,-112(r1)
|
||||
stfd f29,-104(r1)
|
||||
stfd f30,-96(r1)
|
||||
stfd f31,-88(r1)
|
||||
mflr r0 ;save return address
|
||||
stw r0,8(r1)
|
||||
mfcr r2 ;save condition codes
|
||||
stw r2,4(r1)
|
||||
stwu r1,-448(r1) ;create stack frame (save 19 GPRs, 18 FRPs, 12 VRs, VRSAVE)
|
||||
|
||||
mr r30,r3 ;save new context pointer
|
||||
bcl 20,31,L_co_switch$spb ;get address of co_active_context
|
||||
L_co_switch$spb:
|
||||
mflr r31
|
||||
|
||||
addis r29,r31,ha16(_co_environ-L_co_switch$spb) ;get environment flags
|
||||
lwz r8,lo16(_co_environ-L_co_switch$spb)(r29)
|
||||
andis. r9,r8,0x8000 ;is it initialised?
|
||||
bne+ L_co_switch$initialised
|
||||
|
||||
addi r0,0,4 ;len = sizeof(int)
|
||||
stw r0,216(r1)
|
||||
addis r3,r31,ha16(_sysctl_altivec-L_co_switch$spb) ;GPR3 = "hw.optional.altivec"
|
||||
addi r3,r3,lo16(_sysctl_altivec-L_co_switch$spb)
|
||||
addi r4,r1,220 ;GPR4 = &value
|
||||
addi r5,r1,216 ;GPR5 = &len
|
||||
addi r6,0,0 ;newp = 0
|
||||
addi r7,0,0 ;newlen = 0
|
||||
bl L_sysctlbyname$stub ;call sysctlbyname
|
||||
lwz r2,220(r1) ;fetch result
|
||||
addis r8,0,0x8000 ;set initialised bit
|
||||
cmpwi cr5,r3,0 ;assume error means not present
|
||||
cmpwi cr6,r2,0 ;test result
|
||||
blt- cr5,L_co_switch$store_environ
|
||||
beq cr6,L_co_switch$store_environ
|
||||
oris r8,r8,0x4000 ;set the flag to say we have it!
|
||||
L_co_switch$store_environ:
|
||||
stw r8,lo16(_co_environ-L_co_switch$spb)(r29) ;store environment flags
|
||||
L_co_switch$initialised:
|
||||
|
||||
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
|
||||
beq L_co_switch$save_no_vmx
|
||||
mfspr r11,256 ;save VRSAVE
|
||||
andi. r0,r11,0x0FFF ;short-circuit if it's zero
|
||||
stw r11,368(r1)
|
||||
beq L_co_switch$save_no_vmx
|
||||
andi. r0,r11,0x0800 ;check bit 20
|
||||
addi r2,0,32 ;starting index
|
||||
beq L_co_switch$save_skip_vr20
|
||||
stvx v20,r1,r2 ;save VR20
|
||||
L_co_switch$save_skip_vr20:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0400 ;check bit 21
|
||||
beq L_co_switch$save_skip_vr21
|
||||
stvx v21,r1,r2 ;save VR21
|
||||
L_co_switch$save_skip_vr21:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0200 ;check bit 22
|
||||
beq L_co_switch$save_skip_vr22
|
||||
stvx v22,r1,r2 ;save VR22
|
||||
L_co_switch$save_skip_vr22:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0100 ;check bit 23
|
||||
beq L_co_switch$save_skip_vr23
|
||||
stvx v23,r1,r2 ;save VR23
|
||||
L_co_switch$save_skip_vr23:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0080 ;check bit 24
|
||||
beq L_co_switch$save_skip_vr24
|
||||
stvx v24,r1,r2 ;save VR24
|
||||
L_co_switch$save_skip_vr24:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0040 ;check bit 25
|
||||
beq L_co_switch$save_skip_vr25
|
||||
stvx v25,r1,r2 ;save VR25
|
||||
L_co_switch$save_skip_vr25:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0020 ;check bit 26
|
||||
beq L_co_switch$save_skip_vr26
|
||||
stvx v26,r1,r2 ;save VR26
|
||||
L_co_switch$save_skip_vr26:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0010 ;check bit 27
|
||||
beq L_co_switch$save_skip_vr27
|
||||
stvx v27,r1,r2 ;save VR27
|
||||
L_co_switch$save_skip_vr27:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0008 ;check bit 28
|
||||
beq L_co_switch$save_skip_vr28
|
||||
stvx v28,r1,r2 ;save VR28
|
||||
L_co_switch$save_skip_vr28:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0004 ;check bit 29
|
||||
beq L_co_switch$save_skip_vr29
|
||||
stvx v29,r1,r2 ;save VR29
|
||||
L_co_switch$save_skip_vr29:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0002 ;check bit 30
|
||||
beq L_co_switch$save_skip_vr30
|
||||
stvx v30,r1,r2 ;save VR30
|
||||
L_co_switch$save_skip_vr30:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0001 ;check bit 31
|
||||
beq L_co_switch$save_skip_vr31
|
||||
stvx v31,r1,r2 ;save VR31
|
||||
L_co_switch$save_skip_vr31:
|
||||
L_co_switch$save_no_vmx:
|
||||
|
||||
addis r4,r31,ha16(_co_active_context-L_co_switch$spb) ;save current context
|
||||
lwz r5,lo16(_co_active_context-L_co_switch$spb)(r4)
|
||||
stw r30,lo16(_co_active_context-L_co_switch$spb)(r4);set new context
|
||||
stw r1,0(r5) ;save current stack pointer
|
||||
lwz r1,0(r30) ;get new stack pointer
|
||||
|
||||
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
|
||||
beq L_co_switch$restore_no_vmx
|
||||
lwz r11,368(r1) ;restore VRSAVE
|
||||
andi. r0,r11,0x0FFF ;short-circuit if it's zero
|
||||
mtspr 256,r11
|
||||
beq L_co_switch$restore_no_vmx
|
||||
andi. r0,r11,0x0800 ;check bit 20
|
||||
addi r2,0,32 ;starting index
|
||||
beq L_co_switch$restore_skip_vr20
|
||||
lvx v20,r1,r2 ;restore VR20
|
||||
L_co_switch$restore_skip_vr20:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0400 ;check bit 21
|
||||
beq L_co_switch$restore_skip_vr21
|
||||
lvx v21,r1,r2 ;restore VR21
|
||||
L_co_switch$restore_skip_vr21:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0200 ;check bit 22
|
||||
beq L_co_switch$restore_skip_vr22
|
||||
lvx v22,r1,r2 ;restore VR22
|
||||
L_co_switch$restore_skip_vr22:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0100 ;check bit 23
|
||||
beq L_co_switch$restore_skip_vr23
|
||||
lvx v23,r1,r2 ;restore VR23
|
||||
L_co_switch$restore_skip_vr23:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0080 ;check bit 24
|
||||
beq L_co_switch$restore_skip_vr24
|
||||
lvx v24,r1,r2 ;restore VR24
|
||||
L_co_switch$restore_skip_vr24:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0040 ;check bit 25
|
||||
beq L_co_switch$restore_skip_vr25
|
||||
lvx v25,r1,r2 ;restore VR25
|
||||
L_co_switch$restore_skip_vr25:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0020 ;check bit 26
|
||||
beq L_co_switch$restore_skip_vr26
|
||||
lvx v26,r1,r2 ;restore VR26
|
||||
L_co_switch$restore_skip_vr26:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0010 ;check bit 27
|
||||
beq L_co_switch$restore_skip_vr27
|
||||
lvx v27,r1,r2 ;restore VR27
|
||||
L_co_switch$restore_skip_vr27:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0008 ;check bit 28
|
||||
beq L_co_switch$restore_skip_vr28
|
||||
lvx v28,r1,r2 ;restore VR28
|
||||
L_co_switch$restore_skip_vr28:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0004 ;check bit 29
|
||||
beq L_co_switch$restore_skip_vr29
|
||||
lvx v29,r1,r2 ;restore VR29
|
||||
L_co_switch$restore_skip_vr29:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0002 ;check bit 30
|
||||
beq L_co_switch$restore_skip_vr30
|
||||
lvx v30,r1,r2 ;restore VR30
|
||||
L_co_switch$restore_skip_vr30:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0001 ;check bit 31
|
||||
beq L_co_switch$restore_skip_vr31
|
||||
lvx v31,r1,r2 ;restore VR31
|
||||
L_co_switch$restore_skip_vr31:
|
||||
L_co_switch$restore_no_vmx:
|
||||
|
||||
lwz r1,0(r1) ;deallocate stack frame
|
||||
lwz r6,8(r1) ;return address in GPR6
|
||||
lwz r7,4(r1) ;condition codes in GPR7
|
||||
addi r0,0,0 ;make thread main crash if it returns
|
||||
lmw r13,-76(r1) ;restore preserved GPRs
|
||||
lfd f14,-224(r1) ;restore preserved FPRs
|
||||
lfd f15,-216(r1)
|
||||
lfd f16,-208(r1)
|
||||
lfd f17,-200(r1)
|
||||
lfd f18,-192(r1)
|
||||
lfd f19,-184(r1)
|
||||
lfd f20,-176(r1)
|
||||
lfd f21,-168(r1)
|
||||
lfd f22,-160(r1)
|
||||
lfd f23,-152(r1)
|
||||
lfd f24,-144(r1)
|
||||
lfd f25,-136(r1)
|
||||
lfd f26,-128(r1)
|
||||
lfd f27,-120(r1)
|
||||
lfd f28,-112(r1)
|
||||
lfd f29,-104(r1)
|
||||
lfd f30,-96(r1)
|
||||
lfd f31,-88(r1)
|
||||
mtlr r0
|
||||
mtctr r6 ;restore return address
|
||||
mtcrf 32,r7 ;restore preserved condition codes
|
||||
mtcrf 16,r7
|
||||
mtcrf 8,r7
|
||||
bctr ;return
|
||||
|
||||
|
||||
|
||||
;Import external functions
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_malloc$stub:
|
||||
.indirect_symbol _malloc
|
||||
mflr r0
|
||||
bcl 20,31,L_malloc$spb
|
||||
L_malloc$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_malloc$lazy_ptr-L_malloc$spb)
|
||||
mtlr r0
|
||||
lwzu r12,lo16(L_malloc$lazy_ptr-L_malloc$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_malloc$lazy_ptr:
|
||||
.indirect_symbol _malloc
|
||||
.long dyld_stub_binding_helper
|
||||
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_free$stub:
|
||||
.indirect_symbol _free
|
||||
mflr r0
|
||||
bcl 20,31,L_free$spb
|
||||
L_free$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_free$lazy_ptr-L_free$spb)
|
||||
mtlr r0
|
||||
lwzu r12,lo16(L_free$lazy_ptr-L_free$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_free$lazy_ptr:
|
||||
.indirect_symbol _free
|
||||
.long dyld_stub_binding_helper
|
||||
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_sysctlbyname$stub:
|
||||
.indirect_symbol _sysctlbyname
|
||||
mflr r0
|
||||
bcl 20,31,L_sysctlbyname$spb
|
||||
L_sysctlbyname$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)
|
||||
mtlr r0
|
||||
lwzu r12,lo16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_sysctlbyname$lazy_ptr:
|
||||
.indirect_symbol _sysctlbyname
|
||||
.long dyld_stub_binding_helper
|
||||
|
||||
|
||||
;This needs to be here!
|
||||
|
||||
.subsections_via_symbols
|
||||
|
|
@ -0,0 +1,513 @@
|
|||
;*****
|
||||
;libco.ppc64 (2007-12-05)
|
||||
;author: Vas Crabb
|
||||
;license: public domain
|
||||
;
|
||||
;cross-platform 64-bit PowerPC implementation of libco
|
||||
;special thanks to byuu for writing the original version
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- gcc; mac os x; ppc64
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- GPR1, GPR13 - GPR31
|
||||
;- FPR14 - FPR31
|
||||
;- V20 - V31
|
||||
;- VRSAVE, CR2 - CR4
|
||||
;
|
||||
;[volatile registers]
|
||||
;- GPR0, GPR2 - GPR12
|
||||
;- FPR0 - FPR13
|
||||
;- V0 - V19
|
||||
;- LR, CTR, XER, CR0, CR1, CR5 - CR7
|
||||
;*****
|
||||
|
||||
|
||||
;Declare some target-specific stuff
|
||||
|
||||
.section __TEXT,__text,regular,pure_instructions
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.machine ppc64
|
||||
|
||||
|
||||
;Constants
|
||||
|
||||
.cstring
|
||||
.align 3
|
||||
|
||||
_sysctl_altivec:
|
||||
.ascii "hw.optional.altivec\0"
|
||||
|
||||
|
||||
;Declare space for variables
|
||||
|
||||
.lcomm _co_environ,4,2 ;bit 0 = initialised, bit 1 = have Altivec/VMX
|
||||
.lcomm _co_primary_buffer,1024,3 ;buffer (will be zeroed by loader)
|
||||
|
||||
.data
|
||||
.align 3
|
||||
|
||||
_co_active_context:
|
||||
.quad _co_primary_buffer
|
||||
|
||||
|
||||
.text
|
||||
.align 2
|
||||
|
||||
|
||||
;Declare exported names
|
||||
|
||||
.globl _co_active
|
||||
.globl _co_create
|
||||
.globl _co_delete
|
||||
.globl _co_switch
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_active();
|
||||
;return = GPR3
|
||||
;*****
|
||||
|
||||
_co_active:
|
||||
mflr r0 ;GPR0 = return address
|
||||
bcl 20,31,L_co_active$spb
|
||||
L_co_active$spb:
|
||||
mflr r2 ;GPR2 set for position-independance
|
||||
addis r3,r2,ha16(_co_active_context-L_co_active$spb) ;get value in GPR3
|
||||
ld r3,lo16(_co_active_context-L_co_active$spb)(r3)
|
||||
mtlr r0 ;LR = return address
|
||||
blr ;return
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
;GPR3 = heapsize
|
||||
;GPR4 = coentry
|
||||
;return = GPR3
|
||||
;*****
|
||||
|
||||
_co_create:
|
||||
mflr r0 ;GPR0 = return address
|
||||
std r30,-16(r1) ;save GPR30 and GPR31
|
||||
std r31,-8(r1)
|
||||
std r0,16(r1) ;save return address
|
||||
stdu r1,-(2*8+16+48)(r1) ;allocate 16 bytes for locals/parameters
|
||||
|
||||
;create heap space (stack + register storage)
|
||||
addi r31,r3,1024-48 ;subtract space for linkage
|
||||
mr r30,r4 ;GPR30 = coentry
|
||||
addi r3,r3,1024 ;allocate extra memory for contextual info
|
||||
bl L_malloc$stub ;GPR3 = malloc(heapsize + 1024)
|
||||
add r4,r3,r31 ;GPR4 points to top-of-stack
|
||||
rldicr r5,r4,0,59 ;force 16-byte alignment
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
std r30,16(r5) ;store entry point
|
||||
addi r6,0,2+19+18+12*2+1 ;clear for CR, old GPR1, 19 GPRs, 18 FPRs, 12 VRs, VRSAVE
|
||||
addi r0,0,0
|
||||
addi r7,0,8 ;start at 8(GPR5)
|
||||
mtctr r6
|
||||
L_co_create$clear_loop:
|
||||
stdx r0,r5,r7 ;clear a double
|
||||
addi r7,r7,-8 ;increment pointer
|
||||
bdnz L_co_create$clear_loop ;loop
|
||||
stdu r5,-544(r5) ;store top of stack
|
||||
|
||||
;initialize context memory heap and return
|
||||
addis r9,0,0x8000 ;GPR13 not set (system TLS)
|
||||
std r5,0(r3) ;*cothread_t = stack heap pointer (GPR1)
|
||||
stw r9,8(r3) ;this is a flag word
|
||||
ld r1,0(r1) ;deallocate stack frame
|
||||
ld r8,16(r1) ;fetch return address
|
||||
ld r30,-16(r1) ;restore GPR30 and GPR31
|
||||
ld r31,-8(r1)
|
||||
mtlr r8 ;return address in LR
|
||||
blr ;return
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" void co_delete(cothread_t cothread);
|
||||
;GPR3 = cothread
|
||||
;*****
|
||||
|
||||
_co_delete:
|
||||
b L_free$stub ;free(GPR3)
|
||||
|
||||
|
||||
;*****
|
||||
;extern "C" void co_switch(cothread_t cothread);
|
||||
;GPR3 = cothread
|
||||
;*****
|
||||
;
|
||||
;Frame looks like:
|
||||
;
|
||||
;Old New Value
|
||||
; 16(r1) 560(r1) Saved LR
|
||||
; 8(r1) 552(r1) Saved CR
|
||||
; 0(r1) 544(r1) Old GPR1
|
||||
; -8(r1) 536(r1) Saved GPR31
|
||||
; -16(r1) 528(r1) Saved GPR30
|
||||
;... ... ...
|
||||
;-144(r1) 400(r1) Saved GPR14
|
||||
;-152(r1) 392(r1) Saved GPR13
|
||||
;-160(r1) 384(r1) Saved FPR31
|
||||
;-168(r1) 376(r1) Saved FPR30
|
||||
;... ... ...
|
||||
;-288(r1) 256(r1) Saved FPR15
|
||||
;-296(r1) 248(r1) Saved FPR14
|
||||
;-304(r1) 240(r1) Saved VRSAVE
|
||||
;-312(r1) 232(r1) +++ value
|
||||
;-320(r1) 224(r1) Saved VR31 len
|
||||
;-328(r1) 216(r1) +++
|
||||
;-336(r1) 208(r1) Saved VR30
|
||||
;... ... ...
|
||||
;-456(r1) 88(r1) +++
|
||||
;-464(r1) 80(r1) Saved VR22 Param 5 (GPR7)
|
||||
;-472(r1) 72(r1) +++ Param 4 (GPR6)
|
||||
;-480(r1) 64(r1) Saved VR21 Param 3 (GPR5)
|
||||
;-488(r1) 56(r1) +++ Param 2 (GPR4)
|
||||
;-496(r1) 48(r1) Saved VR20 Param 1 (GPR3)
|
||||
;-504(r1) 40(r1) - Reserved
|
||||
;-512(r1) 32(r1) - Reserved
|
||||
;-520(r1) 24(r1) - Reserved
|
||||
;-528(r1) 16(r1) - New LR
|
||||
;-536(r1) 8(r1) - New CR
|
||||
;-544(r1) 0(r1) Saved GPR1
|
||||
|
||||
|
||||
_co_switch:
|
||||
std r13,-152(r1) ;save preserved GPRs
|
||||
std r14,-144(r1)
|
||||
std r15,-136(r1)
|
||||
std r16,-128(r1)
|
||||
std r17,-120(r1)
|
||||
std r18,-112(r1)
|
||||
std r19,-104(r1)
|
||||
std r20,-96(r1)
|
||||
std r21,-88(r1)
|
||||
std r22,-80(r1)
|
||||
std r23,-72(r1)
|
||||
std r24,-64(r1)
|
||||
std r25,-56(r1)
|
||||
std r26,-48(r1)
|
||||
std r27,-40(r1)
|
||||
std r28,-32(r1)
|
||||
std r29,-24(r1)
|
||||
std r30,-16(r1)
|
||||
std r31,-8(r1)
|
||||
mflr r0 ;save return address
|
||||
std r0,16(r1)
|
||||
mfcr r2 ;save condition codes
|
||||
stw r2,8(r1)
|
||||
stdu r1,-544(r1) ;create stack frame (save 19 GPRs, 18 FRPs, 12 VRs, VRSAVE)
|
||||
stfd f14,248(r1) ;save preserved FPRs
|
||||
stfd f15,256(r1)
|
||||
stfd f16,264(r1)
|
||||
stfd f17,272(r1)
|
||||
stfd f18,280(r1)
|
||||
stfd f19,288(r1)
|
||||
stfd f20,296(r1)
|
||||
stfd f21,304(r1)
|
||||
stfd f22,312(r1)
|
||||
stfd f23,320(r1)
|
||||
stfd f24,328(r1)
|
||||
stfd f25,336(r1)
|
||||
stfd f26,344(r1)
|
||||
stfd f27,352(r1)
|
||||
stfd f28,360(r1)
|
||||
stfd f29,368(r1)
|
||||
stfd f30,376(r1)
|
||||
stfd f31,384(r1)
|
||||
|
||||
mr r30,r3 ;save new context pointer
|
||||
bcl 20,31,L_co_switch$spb ;get address of co_active_context
|
||||
L_co_switch$spb:
|
||||
mflr r31
|
||||
|
||||
addis r29,r31,ha16(_co_environ-L_co_switch$spb) ;get environment flags
|
||||
lwz r8,lo16(_co_environ-L_co_switch$spb)(r29)
|
||||
andis. r9,r8,0x8000 ;is it initialised?
|
||||
bne+ L_co_switch$initialised
|
||||
|
||||
addi r0,0,4 ;len = sizeof(int)
|
||||
std r0,224(r1)
|
||||
addis r3,r31,ha16(_sysctl_altivec-L_co_switch$spb) ;GPR3 = "hw.optional.altivec"
|
||||
addi r3,r3,lo16(_sysctl_altivec-L_co_switch$spb)
|
||||
addi r4,r1,232 ;GPR4 = &value
|
||||
addi r5,r1,224 ;GPR5 = &len
|
||||
addi r6,0,0 ;newp = 0
|
||||
addi r7,0,0 ;newlen = 0
|
||||
bl L_sysctlbyname$stub ;call sysctlbyname
|
||||
lwz r2,232(r1) ;fetch result
|
||||
addis r8,0,0x8000 ;set initialised bit
|
||||
cmpdi cr5,r3,0 ;assume error means not present
|
||||
cmpwi cr6,r2,0 ;test result
|
||||
blt- cr5,L_co_switch$store_environ
|
||||
beq cr6,L_co_switch$store_environ
|
||||
oris r8,r8,0x4000 ;set the flag to say we have it!
|
||||
L_co_switch$store_environ:
|
||||
stw r8,lo16(_co_environ-L_co_switch$spb)(r29) ;store environment flags
|
||||
L_co_switch$initialised:
|
||||
|
||||
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
|
||||
beq L_co_switch$save_no_vmx
|
||||
mfspr r11,256 ;save VRSAVE
|
||||
andi. r0,r11,0x0FFF ;short-circuit if it's zero
|
||||
stw r11,240(r1)
|
||||
beq L_co_switch$save_no_vmx
|
||||
andi. r0,r11,0x0800 ;check bit 20
|
||||
addi r2,0,48 ;starting index
|
||||
beq L_co_switch$save_skip_vr20
|
||||
stvx v20,r1,r2 ;save VR20
|
||||
L_co_switch$save_skip_vr20:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0400 ;check bit 21
|
||||
beq L_co_switch$save_skip_vr21
|
||||
stvx v21,r1,r2 ;save VR21
|
||||
L_co_switch$save_skip_vr21:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0200 ;check bit 22
|
||||
beq L_co_switch$save_skip_vr22
|
||||
stvx v22,r1,r2 ;save VR22
|
||||
L_co_switch$save_skip_vr22:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0100 ;check bit 23
|
||||
beq L_co_switch$save_skip_vr23
|
||||
stvx v23,r1,r2 ;save VR23
|
||||
L_co_switch$save_skip_vr23:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0080 ;check bit 24
|
||||
beq L_co_switch$save_skip_vr24
|
||||
stvx v24,r1,r2 ;save VR24
|
||||
L_co_switch$save_skip_vr24:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0040 ;check bit 25
|
||||
beq L_co_switch$save_skip_vr25
|
||||
stvx v25,r1,r2 ;save VR25
|
||||
L_co_switch$save_skip_vr25:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0020 ;check bit 26
|
||||
beq L_co_switch$save_skip_vr26
|
||||
stvx v26,r1,r2 ;save VR26
|
||||
L_co_switch$save_skip_vr26:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0010 ;check bit 27
|
||||
beq L_co_switch$save_skip_vr27
|
||||
stvx v27,r1,r2 ;save VR27
|
||||
L_co_switch$save_skip_vr27:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0008 ;check bit 28
|
||||
beq L_co_switch$save_skip_vr28
|
||||
stvx v28,r1,r2 ;save VR28
|
||||
L_co_switch$save_skip_vr28:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0004 ;check bit 29
|
||||
beq L_co_switch$save_skip_vr29
|
||||
stvx v29,r1,r2 ;save VR29
|
||||
L_co_switch$save_skip_vr29:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0002 ;check bit 30
|
||||
beq L_co_switch$save_skip_vr30
|
||||
stvx v30,r1,r2 ;save VR30
|
||||
L_co_switch$save_skip_vr30:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0001 ;check bit 31
|
||||
beq L_co_switch$save_skip_vr31
|
||||
stvx v31,r1,r2 ;save VR31
|
||||
L_co_switch$save_skip_vr31:
|
||||
L_co_switch$save_no_vmx:
|
||||
|
||||
addis r4,r31,ha16(_co_active_context-L_co_switch$spb) ;save current context
|
||||
ld r5,lo16(_co_active_context-L_co_switch$spb)(r4)
|
||||
std r30,lo16(_co_active_context-L_co_switch$spb)(r4);set new context
|
||||
std r1,0(r5) ;save current stack pointer
|
||||
ld r1,0(r30) ;get new stack pointer
|
||||
lwz r12,8(r30) ;have we already set GPR13 (system TLS)?
|
||||
andis. r0,r12,0x8000
|
||||
beq+ L_co_switch$gpr13_set
|
||||
std r13,392(r1)
|
||||
xoris r12,r12,0x8000
|
||||
stw r12,8(r30)
|
||||
L_co_switch$gpr13_set:
|
||||
|
||||
andis. r10,r8,0x4000 ;do we have Altivec/VMX?
|
||||
beq L_co_switch$restore_no_vmx
|
||||
lwz r11,240(r1) ;restore VRSAVE
|
||||
andi. r0,r11,0x0FFF ;short-circuit if it's zero
|
||||
mtspr 256,r11
|
||||
beq L_co_switch$restore_no_vmx
|
||||
andi. r0,r11,0x0800 ;check bit 20
|
||||
addi r2,0,48 ;starting index
|
||||
beq L_co_switch$restore_skip_vr20
|
||||
lvx v20,r1,r2 ;restore VR20
|
||||
L_co_switch$restore_skip_vr20:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0400 ;check bit 21
|
||||
beq L_co_switch$restore_skip_vr21
|
||||
lvx v21,r1,r2 ;restore VR21
|
||||
L_co_switch$restore_skip_vr21:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0200 ;check bit 22
|
||||
beq L_co_switch$restore_skip_vr22
|
||||
lvx v22,r1,r2 ;restore VR22
|
||||
L_co_switch$restore_skip_vr22:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0100 ;check bit 23
|
||||
beq L_co_switch$restore_skip_vr23
|
||||
lvx v23,r1,r2 ;restore VR23
|
||||
L_co_switch$restore_skip_vr23:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0080 ;check bit 24
|
||||
beq L_co_switch$restore_skip_vr24
|
||||
lvx v24,r1,r2 ;restore VR24
|
||||
L_co_switch$restore_skip_vr24:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0040 ;check bit 25
|
||||
beq L_co_switch$restore_skip_vr25
|
||||
lvx v25,r1,r2 ;restore VR25
|
||||
L_co_switch$restore_skip_vr25:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0020 ;check bit 26
|
||||
beq L_co_switch$restore_skip_vr26
|
||||
lvx v26,r1,r2 ;restore VR26
|
||||
L_co_switch$restore_skip_vr26:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0010 ;check bit 27
|
||||
beq L_co_switch$restore_skip_vr27
|
||||
lvx v27,r1,r2 ;restore VR27
|
||||
L_co_switch$restore_skip_vr27:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0008 ;check bit 28
|
||||
beq L_co_switch$restore_skip_vr28
|
||||
lvx v28,r1,r2 ;restore VR28
|
||||
L_co_switch$restore_skip_vr28:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0004 ;check bit 29
|
||||
beq L_co_switch$restore_skip_vr29
|
||||
lvx v29,r1,r2 ;restore VR29
|
||||
L_co_switch$restore_skip_vr29:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0002 ;check bit 30
|
||||
beq L_co_switch$restore_skip_vr30
|
||||
lvx v30,r1,r2 ;restore VR30
|
||||
L_co_switch$restore_skip_vr30:
|
||||
addi r2,r2,16 ;stride
|
||||
andi. r0,r11,0x0001 ;check bit 31
|
||||
beq L_co_switch$restore_skip_vr31
|
||||
lvx v31,r1,r2 ;restore VR31
|
||||
L_co_switch$restore_skip_vr31:
|
||||
L_co_switch$restore_no_vmx:
|
||||
|
||||
lfd f14,248(r1) ;restore preserved FPRs
|
||||
lfd f15,256(r1)
|
||||
lfd f16,264(r1)
|
||||
lfd f17,272(r1)
|
||||
lfd f18,280(r1)
|
||||
lfd f19,288(r1)
|
||||
lfd f20,296(r1)
|
||||
lfd f21,304(r1)
|
||||
lfd f22,312(r1)
|
||||
lfd f23,320(r1)
|
||||
lfd f24,328(r1)
|
||||
lfd f25,336(r1)
|
||||
lfd f26,344(r1)
|
||||
lfd f27,352(r1)
|
||||
lfd f28,360(r1)
|
||||
lfd f29,368(r1)
|
||||
lfd f30,376(r1)
|
||||
lfd f31,384(r1)
|
||||
addi r0,0,0 ;make thread main crash if it returns
|
||||
ld r1,0(r1) ;deallocate stack frame
|
||||
ld r6,16(r1) ;return address in GPR6
|
||||
lwz r7,8(r1) ;condition codes in GPR7
|
||||
ld r13,-152(r1) ;restore preserved GPRs
|
||||
ld r14,-144(r1)
|
||||
ld r15,-136(r1)
|
||||
ld r16,-128(r1)
|
||||
ld r17,-120(r1)
|
||||
ld r18,-112(r1)
|
||||
ld r19,-104(r1)
|
||||
ld r20,-96(r1)
|
||||
ld r21,-88(r1)
|
||||
ld r22,-80(r1)
|
||||
ld r23,-72(r1)
|
||||
ld r24,-64(r1)
|
||||
ld r25,-56(r1)
|
||||
ld r26,-48(r1)
|
||||
ld r27,-40(r1)
|
||||
ld r28,-32(r1)
|
||||
ld r29,-24(r1)
|
||||
ld r30,-16(r1)
|
||||
ld r31,-8(r1)
|
||||
mtlr r0
|
||||
mtctr r6 ;restore return address
|
||||
mtcrf 32,r7 ;restore preserved condition codes
|
||||
mtcrf 16,r7
|
||||
mtcrf 8,r7
|
||||
bctr ;return
|
||||
|
||||
|
||||
|
||||
;Import external functions
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_malloc$stub:
|
||||
.indirect_symbol _malloc
|
||||
mflr r0
|
||||
bcl 20,31,L_malloc$spb
|
||||
L_malloc$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_malloc$lazy_ptr-L_malloc$spb)
|
||||
mtlr r0
|
||||
ldu r12,lo16(L_malloc$lazy_ptr-L_malloc$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_malloc$lazy_ptr:
|
||||
.indirect_symbol _malloc
|
||||
.quad dyld_stub_binding_helper
|
||||
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_free$stub:
|
||||
.indirect_symbol _free
|
||||
mflr r0
|
||||
bcl 20,31,L_free$spb
|
||||
L_free$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_free$lazy_ptr-L_free$spb)
|
||||
mtlr r0
|
||||
ldu r12,lo16(L_free$lazy_ptr-L_free$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_free$lazy_ptr:
|
||||
.indirect_symbol _free
|
||||
.quad dyld_stub_binding_helper
|
||||
|
||||
|
||||
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
|
||||
.align 5
|
||||
L_sysctlbyname$stub:
|
||||
.indirect_symbol _sysctlbyname
|
||||
mflr r0
|
||||
bcl 20,31,L_sysctlbyname$spb
|
||||
L_sysctlbyname$spb:
|
||||
mflr r11
|
||||
addis r11,r11,ha16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)
|
||||
mtlr r0
|
||||
ldu r12,lo16(L_sysctlbyname$lazy_ptr-L_sysctlbyname$spb)(r11)
|
||||
mtctr r12
|
||||
bctr
|
||||
.lazy_symbol_pointer
|
||||
L_sysctlbyname$lazy_ptr:
|
||||
.indirect_symbol _sysctlbyname
|
||||
.quad dyld_stub_binding_helper
|
||||
|
||||
|
||||
;This needs to be here!
|
||||
|
||||
.subsections_via_symbols
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
libco.ucontext (2007-09-08)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ucontext.h>
|
||||
#include "../libco.h"
|
||||
|
||||
//WARNING: the overhead of POSIX ucontext is very high,
|
||||
//averaging ~450x that of standard subroutine calls.
|
||||
//(tested on FreeBSD 6.2-RELEASE)
|
||||
//By contrast, on the same system, libco_x86's overhead
|
||||
//is ~7.25x standard subroutine calls; or fifty times faster.
|
||||
//
|
||||
//This library only exists for two reasons:
|
||||
//1 - as an initial test for the viability of a ucontext implementation
|
||||
//2 - to demonstrate the power and speed of libco over existing implementations,
|
||||
// such as pth (which defaults to wrapping ucontext on unix targets)
|
||||
//
|
||||
//Use this library only as a *last resort*
|
||||
|
||||
struct cothread_struct {
|
||||
ucontext_t cohandle;
|
||||
void (*coentry)();
|
||||
};
|
||||
|
||||
cothread_t __co_active = 0, __co_primary = 0;
|
||||
void co_entrypoint(cothread_t cothread);
|
||||
void co_init();
|
||||
|
||||
/*****
|
||||
* library functions
|
||||
*****/
|
||||
|
||||
cothread_t co_active() {
|
||||
if(__co_primary == 0)co_init();
|
||||
return __co_active;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)()) {
|
||||
if(__co_primary == 0)co_init();
|
||||
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
thread->coentry = coentry;
|
||||
getcontext(&thread->cohandle);
|
||||
heapsize += 512;
|
||||
thread->cohandle.uc_stack.ss_sp = (char*)malloc(heapsize);
|
||||
thread->cohandle.uc_stack.ss_size = heapsize;
|
||||
makecontext(&thread->cohandle, (void (*)())co_entrypoint, 1, thread);
|
||||
return (cothread_t)thread;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
cothread_struct *thread = (cothread_struct*)cothread;
|
||||
free(thread->cohandle.uc_stack.ss_sp);
|
||||
free(thread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
cothread_struct *active = (cothread_struct*)__co_active;
|
||||
cothread_struct *swap = (cothread_struct*)cothread;
|
||||
__co_active = cothread;
|
||||
swapcontext(&active->cohandle, &swap->cohandle);
|
||||
}
|
||||
|
||||
/*****
|
||||
* internal functions
|
||||
*****/
|
||||
|
||||
void co_entrypoint(cothread_t cothread) {
|
||||
((cothread_struct*)cothread)->coentry();
|
||||
}
|
||||
|
||||
void co_init() {
|
||||
cothread_struct *thread = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
thread->coentry = 0;
|
||||
getcontext(&thread->cohandle);
|
||||
__co_active = __co_primary = (cothread_t)thread;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
libco.win (2007-09-08)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
#define WINVER 0x0400
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <windows.h>
|
||||
#include "../libco.h"
|
||||
|
||||
struct cothread_struct {
|
||||
void *cohandle;
|
||||
void (*coentry)();
|
||||
};
|
||||
|
||||
cothread_t __co_active = 0, __co_primary = 0;
|
||||
|
||||
void __stdcall co_entryproc(void*);
|
||||
cothread_t co_init();
|
||||
|
||||
/*****
|
||||
* library functions
|
||||
*****/
|
||||
|
||||
cothread_t co_active() {
|
||||
if(__co_primary == 0)co_init();
|
||||
return __co_active;
|
||||
}
|
||||
|
||||
cothread_t co_create(unsigned int heapsize, void (*coentry)()) {
|
||||
if(__co_primary == 0)co_init();
|
||||
cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
s->coentry = coentry;
|
||||
s->cohandle = CreateFiber(heapsize + 512, co_entryproc, (void*)s);
|
||||
return (cothread_t)s;
|
||||
}
|
||||
|
||||
void co_delete(cothread_t cothread) {
|
||||
cothread_struct *s = (cothread_struct*)cothread;
|
||||
DeleteFiber(s->cohandle);
|
||||
free(cothread);
|
||||
}
|
||||
|
||||
void co_switch(cothread_t cothread) {
|
||||
__co_active = cothread;
|
||||
cothread_struct *s = (cothread_struct*)cothread;
|
||||
SwitchToFiber(s->cohandle);
|
||||
}
|
||||
|
||||
/*****
|
||||
* internal functions
|
||||
*****/
|
||||
|
||||
void __stdcall co_entryproc(void *cothread) {
|
||||
((cothread_struct*)cothread)->coentry();
|
||||
}
|
||||
|
||||
cothread_t co_init() {
|
||||
ConvertThreadToFiber(0);
|
||||
cothread_struct *s = (cothread_struct*)malloc(sizeof(cothread_struct));
|
||||
s->coentry = 0;
|
||||
s->cohandle = GetCurrentFiber();
|
||||
__co_active = __co_primary = (cothread_t)s;
|
||||
return __co_active;
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
;*****
|
||||
;libco.x86-64 (2007-12-11)
|
||||
;author: byuu
|
||||
;license: public domain
|
||||
;
|
||||
;cross-platform x86-64 implementation of libco
|
||||
;thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;thanks to Lucas Newman and Vas Crabb for assistance with OS X support
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- SystemV ( http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf )
|
||||
;- gcc; mac os x; x86-64
|
||||
;- gcc; linux; x86-64
|
||||
;- gcc; freebsd; x86-64
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- rsp, rbp, rbx, r12, r13, r14, r15
|
||||
;
|
||||
;[volatile registers]
|
||||
;- rax, rcx, rdx, r8, r9, r10, r11, rdi, rsi
|
||||
;- st0 - st7
|
||||
;- xmm0 - xmm15
|
||||
;*****
|
||||
|
||||
;*****
|
||||
;linker-specific name decorations
|
||||
;*****
|
||||
|
||||
%ifdef OSX
|
||||
%define malloc _malloc
|
||||
%define free _free
|
||||
|
||||
%define co_active _co_active
|
||||
%define co_create _co_create
|
||||
%define co_delete _co_delete
|
||||
%define co_switch _co_switch
|
||||
%endif
|
||||
|
||||
bits 64
|
||||
|
||||
section .bss
|
||||
|
||||
align 8
|
||||
co_primary_buffer resb 512
|
||||
|
||||
section .data
|
||||
|
||||
align 8
|
||||
co_active_context dq co_primary_buffer
|
||||
|
||||
section .text
|
||||
|
||||
extern malloc
|
||||
extern free
|
||||
|
||||
global co_active
|
||||
global co_create
|
||||
global co_delete
|
||||
global co_switch
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_active();
|
||||
;return = rax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_active:
|
||||
mov rax,[co_active_context wrt rip]
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t co_create(unsigned int heapsize, void (*coentry)());
|
||||
;rdi = heapsize
|
||||
;rsi = coentry
|
||||
;return = rax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_create:
|
||||
;create heap space (stack + context)
|
||||
add rdi,512 ;allocate extra memory for contextual info
|
||||
|
||||
push rdi ;backup volatile registers before malloc call
|
||||
push rsi
|
||||
|
||||
sub rsp,8 ;SSE 16-byte stack alignment
|
||||
call malloc ;rax = malloc(rdi)
|
||||
add rsp,8
|
||||
|
||||
pop rsi ;restore volatile registers
|
||||
pop rdi
|
||||
|
||||
add rdi,rax ;set rdi to point to top of stack heap
|
||||
and rdi,-16 ;force 16-byte alignment of stack heap
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
mov qword[rdi-8],0 ;crash if entry point returns
|
||||
mov qword[rdi-16],rsi ;entry point
|
||||
mov qword[rdi-24],0 ;r15
|
||||
mov qword[rdi-32],0 ;r14
|
||||
mov qword[rdi-40],0 ;r13
|
||||
mov qword[rdi-48],0 ;r12
|
||||
mov qword[rdi-56],0 ;rbx
|
||||
mov qword[rdi-64],0 ;rbp
|
||||
sub rdi,64
|
||||
|
||||
;initialize context memory heap and return
|
||||
mov [rax],rdi ;*cothread_t = stack heap pointer (rsp)
|
||||
ret ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
;extern "C" void co_delete(cothread_t cothread);
|
||||
;rdi = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_delete:
|
||||
jmp free ;free(rdi)
|
||||
|
||||
;*****
|
||||
;extern "C" void co_switch(cothread_t cothread);
|
||||
;rdi = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_switch:
|
||||
mov rax,[co_active_context wrt rip] ;backup current context
|
||||
mov [co_active_context wrt rip],rdi ;set new active context
|
||||
|
||||
push rbp
|
||||
push rbx
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
mov [rax],rsp
|
||||
|
||||
mov rsp,[rdi]
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbx
|
||||
pop rbp
|
||||
|
||||
ret
|
|
@ -0,0 +1,155 @@
|
|||
;*****
|
||||
;libco.x86 (2007-12-11)
|
||||
;author: byuu
|
||||
;license: public domain
|
||||
;
|
||||
;cross-platform x86 implementation of libco
|
||||
;thanks to Aaron Giles and Joel Yliluoma for various optimizations
|
||||
;thanks to Lucas Newman and Vas Crabb for assistance with OS X support
|
||||
;
|
||||
;[ABI compatibility]
|
||||
;- visual c++; windows; x86
|
||||
;- mingw; windows; x86
|
||||
;- gcc; mac os x; x86
|
||||
;- gcc; linux; x86
|
||||
;- gcc; freebsd; x86
|
||||
;
|
||||
;[nonvolatile registers]
|
||||
;- esp, ebp, edi, esi, ebx
|
||||
;
|
||||
;[volatile registers]
|
||||
;- eax, ecx, edx
|
||||
;- st0 - st7
|
||||
;- xmm0 - xmm15
|
||||
;*****
|
||||
|
||||
;*****
|
||||
;linker-specific name decorations
|
||||
;*****
|
||||
|
||||
%ifdef WIN
|
||||
%define malloc _malloc
|
||||
%define free _free
|
||||
|
||||
%define co_active @co_active@0
|
||||
%define co_create @co_create@8
|
||||
%define co_delete @co_delete@4
|
||||
%define co_switch @co_switch@4
|
||||
%endif
|
||||
|
||||
%ifdef OSX
|
||||
%define malloc _malloc
|
||||
%define free _free
|
||||
|
||||
%define co_active _co_active
|
||||
%define co_create _co_create
|
||||
%define co_delete _co_delete
|
||||
%define co_switch _co_switch
|
||||
%endif
|
||||
|
||||
bits 32
|
||||
|
||||
section .bss
|
||||
|
||||
align 4
|
||||
co_primary_buffer resb 512
|
||||
|
||||
section .data
|
||||
|
||||
align 4
|
||||
co_active_context dd co_primary_buffer
|
||||
|
||||
section .text
|
||||
|
||||
extern malloc
|
||||
extern free
|
||||
|
||||
global co_active
|
||||
global co_create
|
||||
global co_delete
|
||||
global co_switch
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_active();
|
||||
;return = eax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_active:
|
||||
mov eax,[co_active_context]
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" cothread_t fastcall co_create(unsigned int heapsize, void (*coentry)());
|
||||
;ecx = heapsize
|
||||
;edx = coentry
|
||||
;return = eax
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_create:
|
||||
;create heap space (stack + context)
|
||||
add ecx,512 ;allocate extra memory for contextual info
|
||||
|
||||
push ecx ;backup volatile registers before malloc call
|
||||
push edx
|
||||
|
||||
push ecx
|
||||
call malloc ;eax = malloc(ecx)
|
||||
add esp,4
|
||||
|
||||
pop edx ;restore volatile registers
|
||||
pop ecx
|
||||
|
||||
add ecx,eax ;set edx to point to top of stack heap
|
||||
and ecx,-16 ;force 16-byte alignment of stack heap
|
||||
|
||||
;store thread entry point + registers, so that first call to co_switch will execute coentry
|
||||
mov dword[ecx-4],0 ;crash if entry point returns
|
||||
mov dword[ecx-8],edx ;entry point
|
||||
mov dword[ecx-12],0 ;ebp
|
||||
mov dword[ecx-16],0 ;esi
|
||||
mov dword[ecx-20],0 ;edi
|
||||
mov dword[ecx-24],0 ;ebx
|
||||
sub ecx,24
|
||||
|
||||
;initialize context memory heap and return
|
||||
mov [eax],ecx ;*cothread_t = stack heap pointer (esp)
|
||||
ret ;return allocated memory block as thread handle
|
||||
|
||||
;*****
|
||||
;extern "C" void fastcall co_delete(cothread_t cothread);
|
||||
;ecx = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_delete:
|
||||
sub esp,8 ;SSE 16-byte stack alignment
|
||||
push ecx
|
||||
call free ;free(ecx)
|
||||
add esp,4+8
|
||||
ret
|
||||
|
||||
;*****
|
||||
;extern "C" void fastcall co_switch(cothread_t cothread);
|
||||
;ecx = cothread
|
||||
;*****
|
||||
|
||||
align 16
|
||||
co_switch:
|
||||
mov eax,[co_active_context] ;backup current context
|
||||
mov [co_active_context],ecx ;set new active context
|
||||
|
||||
push ebp
|
||||
push esi
|
||||
push edi
|
||||
push ebx
|
||||
mov [eax],esp
|
||||
|
||||
mov esp,[ecx]
|
||||
pop ebx
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
|
||||
ret
|
Loading…
Reference in New Issue