mirror of
https://github.com/open-goal/jak-project
synced 2026-09-10 20:29:51 -04:00
the kernel does things other than crash
This commit is contained in:
@@ -97,6 +97,18 @@ Form* try_cast_simplify(Form* in,
|
||||
return in;
|
||||
}
|
||||
|
||||
if (env.version == GameVersion::Jak2) {
|
||||
if (new_type == TypeSpec("float")) {
|
||||
auto ic = get_goal_integer_constant(in, env);
|
||||
if (ic) {
|
||||
ASSERT(*ic <= UINT32_MAX);
|
||||
float f;
|
||||
memcpy(&f, &ic.value(), sizeof(float));
|
||||
return pool.form<ConstantFloatElement>(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (new_type == TypeSpec("meters")) {
|
||||
auto fc = get_goal_float_constant(in);
|
||||
|
||||
|
||||
+264
-195
@@ -14,6 +14,7 @@
|
||||
(define-extern integer type)
|
||||
(define-extern float type)
|
||||
(define-extern boolean type) ;; not actually added as a runtime type in jak2, but valid? supports it.
|
||||
(define-extern uint32 type)
|
||||
(define-extern int64 type)
|
||||
(define-extern uint64 type)
|
||||
(define-extern process-tree type)
|
||||
@@ -162,7 +163,7 @@
|
||||
(define-extern *trace-list* pair)
|
||||
(define-extern print-tree-bitmask (function int int symbol))
|
||||
(define-extern breakpoint-range-set! (function uint uint uint int))
|
||||
(define-extern valid? (function object type basic basic object symbol))
|
||||
(define-extern valid? (function object type symbol symbol object symbol))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; gstring-h ;;
|
||||
@@ -231,7 +232,7 @@
|
||||
(self process-tree :offset-assert 32)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type basic) _type_ 0)
|
||||
(new (symbol type string) _type_ 0)
|
||||
(activate (_type_ process-tree basic pointer) process-tree 9)
|
||||
(deactivate (_type_) none 10)
|
||||
(init-from-entity! (_type_ entity-actor) none 11) ;; todo check
|
||||
@@ -254,7 +255,7 @@
|
||||
(relocating-min int32 :offset-assert 32)
|
||||
(relocating-max int32 :offset-assert 36)
|
||||
(relocating-offset int32 :offset-assert 40)
|
||||
(relocating-level object :offset-assert 44) ;; guessing here
|
||||
(relocating-level level :offset-assert 44) ;; guessing here
|
||||
(low-memory-message symbol :offset-assert 48) ;; guessed by decompiler
|
||||
(login-object basic :offset-assert 52)
|
||||
)
|
||||
@@ -271,37 +272,37 @@
|
||||
|
||||
|
||||
(deftype clock (basic)
|
||||
((index int32 :offset-assert 4)
|
||||
(mask uint32 :offset-assert 8)
|
||||
(clock-ratio float :offset-assert 12)
|
||||
(accum float :offset-assert 16)
|
||||
(integral-accum float :offset-assert 20)
|
||||
(frame-counter uint64 :offset-assert 24)
|
||||
(old-frame-counter uint64 :offset-assert 32)
|
||||
(integral-frame-counter uint64 :offset-assert 40)
|
||||
(old-integral-frame-counter uint64 :offset-assert 48)
|
||||
(sparticle-data vector :inline :offset-assert 64)
|
||||
(seconds-per-frame float :offset-assert 80)
|
||||
(frames-per-second float :offset-assert 84)
|
||||
(time-adjust-ratio float :offset-assert 88)
|
||||
((index int32 :offset-assert 4) ;; which clock we are, in *display*
|
||||
(mask process-mask :offset-assert 8) ;; mask for ticking
|
||||
(clock-ratio float :offset-assert 12) ;; how fast to run. 1.0 = realtime.
|
||||
(accum float :offset-assert 16) ;; fractional time for frame-counter (time-frame units)
|
||||
(integral-accum float :offset-assert 20) ;; fractional time for integral (time-frame untis)
|
||||
(frame-counter time-frame :offset-assert 24) ;; how much time has gone by since reset (time-frame units)
|
||||
(old-frame-counter time-frame :offset-assert 32) ;; the frame-counter on the last engine iteration
|
||||
(integral-frame-counter uint64 :offset-assert 40) ;; how many vsyncs have gone by since reset
|
||||
(old-integral-frame-counter uint64 :offset-assert 48) ;; the integral-frame-counter on the last engine iteration
|
||||
(sparticle-data vector :inline :offset-assert 64) ;; sparticle timescale info
|
||||
(seconds-per-frame float :offset-assert 80) ;; how many seconds (not time-frames) should go by in 1 vsync
|
||||
(frames-per-second float :offset-assert 84) ;; inverse of above
|
||||
(time-adjust-ratio float :offset-assert 88) ;; 1, if the game runs at 60fps NTSC with clock-ratio = 1.
|
||||
)
|
||||
:method-count-assert 15
|
||||
:size-assert #x5c
|
||||
:flag-assert #xf0000005c
|
||||
(:methods
|
||||
(new (symbol type int) _type_ 0)
|
||||
(dummy-9 (_type_ float) none 9)
|
||||
(dummy-10 () none 10)
|
||||
(dummy-11 () none 11)
|
||||
(dummy-12 () none 12)
|
||||
(dummy-13 () none 13)
|
||||
(dummy-14 () none 14)
|
||||
(update-rates! (_type_ float) none 9)
|
||||
(advance-by! (_type_ float) none 10)
|
||||
(tick! (_type_) none 11)
|
||||
(save! (_type_ (pointer uint64)) int 12)
|
||||
(load! (_type_ (pointer uint64)) int 13)
|
||||
(reset! (_type_) none 14)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
(deftype thread (basic)
|
||||
((name basic :offset-assert 4)
|
||||
((name symbol :offset-assert 4)
|
||||
(process process :offset-assert 8) ;; guessed by decompiler
|
||||
(previous thread :offset-assert 12) ;; guessed by decompiler
|
||||
(suspend-hook (function cpu-thread none) :offset-assert 16) ;; guessed by decompiler
|
||||
@@ -349,7 +350,7 @@
|
||||
:flag-assert #x1000000024
|
||||
;; Failed to read fields.
|
||||
(:methods
|
||||
(new (symbol type int int basic) _type_ 0)
|
||||
(new (symbol type int int string) _type_ 0)
|
||||
(dummy-13 () none 13)
|
||||
(get-process (_type_ type int) process 14)
|
||||
(return-process (_type_ process) none 15)
|
||||
@@ -388,7 +389,7 @@
|
||||
:flag-assert #x1c00000068
|
||||
;; Failed to read fields.
|
||||
(:methods
|
||||
(new (symbol type basic int int) _type_ 0)
|
||||
(new (symbol type string int int) _type_ 0)
|
||||
(init (_type_ symbol int) none 16)
|
||||
(compact (dead-pool-heap int) none 17)
|
||||
(shrink-heap (dead-pool-heap process) dead-pool-heap 18)
|
||||
@@ -404,8 +405,6 @@
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
(deftype stack-frame (basic)
|
||||
((name symbol :offset 4)
|
||||
(next stack-frame :offset 8) ;; which way does this point?
|
||||
@@ -500,7 +499,7 @@
|
||||
|
||||
(deftype process (process-tree)
|
||||
((pool dead-pool)
|
||||
(status basic :offset-assert 40)
|
||||
(status symbol :offset-assert 40)
|
||||
(pid int32)
|
||||
(main-thread cpu-thread :offset-assert 48)
|
||||
(top-thread cpu-thread :offset-assert 52)
|
||||
@@ -518,28 +517,10 @@
|
||||
(heap-cur pointer :offset-assert 104)
|
||||
(stack-frame-top stack-frame :offset-assert 108)
|
||||
(connection-list connectable :inline :offset-assert 112)
|
||||
|
||||
; (pool dead-pool :offset-assert 36)
|
||||
; (status basic :offset-assert 40)
|
||||
; (pid int32 :offset-assert 44)
|
||||
; (main-thread cpu-thread :offset-assert 48)
|
||||
; (top-thread thread :offset-assert 52)
|
||||
; (entity entity-actor :offset-assert 56)
|
||||
; (state state :offset-assert 60)
|
||||
; (trans-hook function :offset-assert 64)
|
||||
; (post-hook function :offset-assert 68)
|
||||
; (event-hook (function process int symbol event-message-block object) :offset-assert 72)
|
||||
; (allocated-length int32 :offset-assert 76)
|
||||
; (next-state state :offset-assert 80)
|
||||
; (heap-base pointer :offset-assert 84)
|
||||
; (heap-top pointer :offset-assert 88)
|
||||
; (heap-cur pointer :offset-assert 92)
|
||||
; (stack-frame-top stack-frame :offset-assert 96)
|
||||
; (connection-list connectable :inline :offset-assert 112) ;; can be a connection
|
||||
(stack uint8 :dynamic :offset-assert 128)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type basic int) _type_ 0)
|
||||
(new (symbol type string int) _type_ 0)
|
||||
)
|
||||
(:states
|
||||
dead-state
|
||||
@@ -592,7 +573,7 @@
|
||||
(define-extern *global-search-name* basic)
|
||||
(define-extern *global-search-count* int)
|
||||
(define-extern process-by-name (function string process-tree process))
|
||||
(define-extern process-not-name (function object process-tree process))
|
||||
(define-extern process-not-name (function string process-tree process))
|
||||
(define-extern process-count (function process-tree int))
|
||||
(define-extern kill-by-name (function string process-tree symbol))
|
||||
(define-extern kill-by-type (function type process-tree symbol))
|
||||
@@ -617,7 +598,7 @@
|
||||
(define-extern entity-deactivate-handler (function process entity-actor none))
|
||||
(define-extern *listener-process* process)
|
||||
(define-extern *null-process* process)
|
||||
(define-extern *vis-boot* basic)
|
||||
(define-extern *vis-boot* symbol)
|
||||
(define-extern *kernel-clock* clock)
|
||||
(define-extern *16k-dead-pool* dead-pool)
|
||||
(define-extern *8k-dead-pool* dead-pool)
|
||||
@@ -780,6 +761,16 @@
|
||||
;; math ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(deftype rgba (uint32)
|
||||
((r uint8 :offset 0)
|
||||
(g uint8 :offset 8)
|
||||
(b uint8 :offset 16)
|
||||
(a uint8 :offset 24)
|
||||
)
|
||||
:flag-assert #x900000004
|
||||
:no-runtime-type
|
||||
)
|
||||
|
||||
#|
|
||||
(deftype random-generator (basic)
|
||||
((seed uint32 :offset-assert 4)
|
||||
@@ -2275,42 +2266,66 @@
|
||||
;; timer-h ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
#|
|
||||
(defenum timer-clock-selection
|
||||
:type uint8
|
||||
(busclk 0)
|
||||
(busclk/16 1)
|
||||
(busclk/256 2)
|
||||
(hblank 3)
|
||||
)
|
||||
|
||||
(deftype timer-mode (uint32)
|
||||
((clks timer-clock-selection :offset 0 :size 2)
|
||||
(gate uint8 :offset 2 :size 1) ;; gate function enable
|
||||
(gats uint8 :offset 3 :size 1) ;; gate selection: 0 = hblank, 1 = vblank
|
||||
;; gate mode:
|
||||
;; 0: count while gate signal is low
|
||||
;; 1: start when gate signal rises
|
||||
;; 2: start when gate signal falls
|
||||
;; 3: start when gate signal rises/falls
|
||||
(gatm uint8 :offset 4 :size 2)
|
||||
(zret uint8 :offset 6 :size 1) ;; zero return: clear counter when equal to reference value
|
||||
(cue uint8 :offset 7 :size 1) ;; count-up enable
|
||||
(cmpe uint8 :offset 8 :size 1) ;; compare-interrupt enable
|
||||
(ovfe uint8 :offset 9 :size 1) ;; overflow-interrupt enable
|
||||
(equf uint8 :offset 10 :size 1) ;; equal-flag
|
||||
(ovff uint8 :offset 11 :size 1) ;; overflow-flag
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x4
|
||||
:flag-assert #x900000004
|
||||
)
|
||||
|
||||
(deftype timer-bank (structure)
|
||||
((count uint32 :offset-assert 0)
|
||||
(mode timer-mode :offset-assert 16) ;; guessed by decompiler
|
||||
(comp uint32 :offset-assert 32)
|
||||
(mode timer-mode :offset 16)
|
||||
(comp uint32 :offset 32)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x24
|
||||
:flag-assert #x900000024
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
(deftype timer-hold-bank (timer-bank)
|
||||
((hold uint32 :offset-assert 48)
|
||||
((hold uint32 :offset 48)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x34
|
||||
:flag-assert #x900000034
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
(deftype stopwatch (basic)
|
||||
((prev-time-elapsed uint64 :offset-assert 8) ;; time-frame
|
||||
(start-time uint64 :offset-assert 16) ;; time-frame
|
||||
(begin-level int32 :offset-assert 24)
|
||||
((prev-time-elapsed time-frame :offset-assert 8)
|
||||
(start-time time-frame :offset-assert 16)
|
||||
(begin-level int32 :offset-assert 24)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x1c
|
||||
:flag-assert #x90000001c
|
||||
)
|
||||
|#
|
||||
|
||||
;; (define-extern *ticks-per-frame* object) ;; int
|
||||
;; (define-extern timer-init object) ;; (function timer-bank timer-mode int)
|
||||
(define-extern *ticks-per-frame* int)
|
||||
(define-extern timer-init (function timer-bank timer-mode int))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; vif-h ;;
|
||||
@@ -2447,41 +2462,107 @@
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
(defenum dma-tag-id
|
||||
:bitfield #f
|
||||
:type uint8
|
||||
(refe 0) ;; addr=ADDR, ends after this transfer
|
||||
(cnt 1) ;; addr=after tag, next-tag=after data
|
||||
(next 2) ;; addr=after tag, next-tag=ADDR
|
||||
(ref 3) ;; addr=ADDR, next-tag=after tag
|
||||
(refs 4) ;; ref, but stall controled
|
||||
(call 5) ;;
|
||||
(ret 6) ;;
|
||||
(end 7) ;; next, but ends.
|
||||
)
|
||||
|
||||
(deftype dma-tag (uint64)
|
||||
()
|
||||
((qwc uint16 :offset 0) ;; quadword count
|
||||
(pce uint8 :offset 26 :size 2) ;; priority (source mode)
|
||||
(id dma-tag-id :offset 28 :size 3) ;; ID (what the tag means)
|
||||
(irq uint8 :offset 31 :size 1) ;; interrupt at the end?
|
||||
(addr uint32 :offset 32 :size 31) ;; address (31 bits)
|
||||
(spr uint8 :offset 63 :size 1) ;; spr or not flag.
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x8
|
||||
:flag-assert #x900000008
|
||||
;; Failed to read some fields.
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
(deftype dma-bucket (structure)
|
||||
((tag uint64 :offset-assert 0) ;; dma-tag
|
||||
(last (pointer dma-tag) :offset-assert 8) ;; guessed by decompiler
|
||||
((tag dma-tag :offset-assert 0)
|
||||
(last (pointer dma-tag) :offset-assert 8)
|
||||
(dummy uint32 :offset-assert 12)
|
||||
(next uint32 :offset-assert 4)
|
||||
(clear uint64 :offset-assert 8)
|
||||
(vif0 uint32 :offset-assert 8)
|
||||
(vif1 uint32 :offset-assert 12)
|
||||
(next uint32 :offset 4)
|
||||
(clear uint64 :offset 8)
|
||||
(vif0 uint32 :offset 8)
|
||||
(vif1 uint32 :offset 12)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
;; all these have mask (only applies to unpacks) and interrupt not set.
|
||||
(defenum vif-cmd
|
||||
:bitfield #f
|
||||
:type uint8
|
||||
(nop 0) ;; no-op, can still have irq set.
|
||||
(stcycl 1) ;; set write recycle register
|
||||
(offset 2) ;; set offset register
|
||||
(base 3) ;; set base register
|
||||
(itop 4) ;; set data pointer register (itops)
|
||||
(stmod 5) ;; set mode register
|
||||
(mskpath3 6) ;; set path 3 mask
|
||||
(mark 7) ;; set mark register
|
||||
(pc-port 8) ;; special tag for PC Port data.
|
||||
(flushe 16) ;; wait for end of microprogram
|
||||
(flush 17) ;; wait for end of microprogram and transfer (path1/path2)
|
||||
(flusha 19) ;; wait for end of microprogram and transfer (path1/path2/path3)
|
||||
(mscal 20) ;; activate microprogram (call)
|
||||
(mscalf 21) ;; flushe and activate (call)
|
||||
(mscnt 23) ;; activate microprogram (continue)
|
||||
(stmask 32) ;; set MASK register.
|
||||
(strow 48) ;; set filling data
|
||||
(stcol 49) ;; set filling data
|
||||
(mpg 74) ;; transfer microprogram
|
||||
(direct 80) ;; straight to GIF.
|
||||
(directhl 81)
|
||||
(unpack-s-32 96)
|
||||
(unpack-s-16 97)
|
||||
(unpack-s-8 98)
|
||||
;; 99 is invalid
|
||||
(unpack-v2-32 100)
|
||||
(unpack-v2-16 101)
|
||||
(unpack-v2-8 102)
|
||||
;; 103 is invalid
|
||||
(unpack-v3-32 104)
|
||||
(unpack-v3-16 105)
|
||||
(unpack-v3-8 106)
|
||||
;; 107 is invalid
|
||||
(unpack-v4-32 108)
|
||||
(unpack-v4-16 109)
|
||||
(unpack-v4-8 110)
|
||||
(unpack-v4-5 111)
|
||||
(cmd-mask 239) ;; not sure what this is
|
||||
)
|
||||
|
||||
(defenum vif-cmd-32
|
||||
:bitfield #f
|
||||
:type uint32
|
||||
:copy-entries vif-cmd
|
||||
)
|
||||
|
||||
(deftype vif-tag (uint32)
|
||||
()
|
||||
((imm uint16 :offset 0 :size 16)
|
||||
(num uint8 :offset 16 :size 8)
|
||||
(cmd vif-cmd :offset 24 :size 7)
|
||||
(irq uint8 :offset 31 :size 1)
|
||||
(msk uint8 :offset 28 :size 1)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x4
|
||||
:flag-assert #x900000004
|
||||
;; Failed to read some fields.
|
||||
)
|
||||
|#
|
||||
|
||||
;; (define-extern dma-sync-fast object) ;; (function dma-bank none)
|
||||
;; (define-extern dma-send-no-scratch object) ;; (function dma-bank uint32 uint32 none)
|
||||
@@ -2555,7 +2636,6 @@
|
||||
;; profile-h ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
#|
|
||||
(deftype profile-segment (structure)
|
||||
((name basic :offset-assert 0)
|
||||
(start-time int16 :offset-assert 4)
|
||||
@@ -2564,50 +2644,49 @@
|
||||
(vu-count uint8 :offset-assert 9)
|
||||
(depth uint16 :offset-assert 10)
|
||||
(color uint32 :offset-assert 12)
|
||||
(code-time uint16 :offset-assert 4)
|
||||
(vu-time uint16 :offset-assert 6)
|
||||
(code-time uint16 :offset 4)
|
||||
(vu-time uint16 :offset 6)
|
||||
)
|
||||
:allow-misaligned
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
|
||||
(deftype profile-collapse (structure)
|
||||
((count int32 :offset-assert 0)
|
||||
(data UNKNOWN 48 :offset-assert 4)
|
||||
(data profile-segment 48 :inline :offset-assert 4)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x304
|
||||
:flag-assert #x900000304
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
|
||||
(deftype profile-segment-array (basic)
|
||||
((count int16 :offset-assert 4)
|
||||
(depth int8 :offset-assert 6)
|
||||
(max-depth int8 :offset-assert 7)
|
||||
(base-time int16 :offset-assert 8)
|
||||
(segment UNKNOWN 9 :offset-assert 12)
|
||||
(data UNKNOWN 512 :offset-assert 48)
|
||||
(segment basic 9 :offset-assert 12) ;; todo
|
||||
(data profile-segment 512 :inline :offset-assert 48)
|
||||
)
|
||||
:method-count-assert 13
|
||||
:size-assert #x2030
|
||||
:flag-assert #xd00002030
|
||||
(:methods
|
||||
(dummy-9 () none 9)
|
||||
(get-total-time (_type_) int 9)
|
||||
(dummy-10 () none 10)
|
||||
(dummy-11 () none 11)
|
||||
(dummy-12 () none 12)
|
||||
)
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
|
||||
|
||||
(deftype profile-array (structure)
|
||||
((data UNKNOWN 2 :offset-assert 0)
|
||||
((data profile-segment-array 2 :offset-assert 0) ;; guess
|
||||
)
|
||||
:method-count-assert 12
|
||||
:size-assert #x8
|
||||
@@ -2618,45 +2697,45 @@
|
||||
(dummy-11 () none 11)
|
||||
)
|
||||
)
|
||||
|#
|
||||
|
||||
;; (define-extern *profile-gap-color* object)
|
||||
;; (define-extern *profile-all-color* object)
|
||||
;; (define-extern *profile-particles-color* object)
|
||||
;; (define-extern *profile-target-color* object)
|
||||
;; (define-extern *profile-target-post-color* object)
|
||||
;; (define-extern *profile-joints-color* object)
|
||||
;; (define-extern *profile-debug-color* object)
|
||||
;; (define-extern *profile-draw-hook-color* object)
|
||||
;; (define-extern *profile-sky-color* object)
|
||||
;; (define-extern *profile-ocean-color* object)
|
||||
;; (define-extern *profile-background-color* object)
|
||||
;; (define-extern *profile-bsp-color* object)
|
||||
;; (define-extern *profile-foreground-color* object)
|
||||
;; (define-extern *profile-tfrag-color* object)
|
||||
;; (define-extern *profile-instance-tie-color* object)
|
||||
;; (define-extern *profile-instance-shrubbery-color* object)
|
||||
;; (define-extern *profile-generic-tie-color* object)
|
||||
;; (define-extern *profile-bones-color* object)
|
||||
;; (define-extern *profile-generic-merc-color* object)
|
||||
;; (define-extern *profile-shadow-color* object)
|
||||
;; (define-extern *profile-update-actors-color* object)
|
||||
;; (define-extern *profile-menu-hook-color* object)
|
||||
;; (define-extern *profile-texture-color* object)
|
||||
;; (define-extern *profile-effects-color* object)
|
||||
;; (define-extern *profile-sprite-color* object)
|
||||
;; (define-extern *profile-merc-color* object)
|
||||
;; (define-extern *profile-actors-color* object)
|
||||
;; (define-extern *profile-collide-color* object)
|
||||
;; (define-extern *profile-nav-color* object)
|
||||
;; (define-extern *profile-camera-color* object)
|
||||
;; (define-extern *profile-blit-color* object)
|
||||
;; (define-extern *profile-hud-color* object)
|
||||
;; (define-extern *profile-emerc-color* object)
|
||||
;; (define-extern *profile-array* object)
|
||||
;; (define-extern *profile-collapse* object)
|
||||
;; (define-extern *profile-interrupt-segment* object)
|
||||
;; (define-extern *profile-interrupt-start* object)
|
||||
|
||||
(define-extern *profile-gap-color* rgba)
|
||||
(define-extern *profile-all-color* rgba)
|
||||
(define-extern *profile-particles-color* rgba)
|
||||
(define-extern *profile-target-color* rgba)
|
||||
(define-extern *profile-target-post-color* rgba)
|
||||
(define-extern *profile-joints-color* rgba)
|
||||
(define-extern *profile-debug-color* rgba)
|
||||
(define-extern *profile-draw-hook-color* rgba)
|
||||
(define-extern *profile-sky-color* rgba)
|
||||
(define-extern *profile-ocean-color* rgba)
|
||||
(define-extern *profile-background-color* rgba)
|
||||
(define-extern *profile-bsp-color* rgba)
|
||||
(define-extern *profile-foreground-color* rgba)
|
||||
(define-extern *profile-tfrag-color* rgba)
|
||||
(define-extern *profile-instance-tie-color* rgba)
|
||||
(define-extern *profile-instance-shrubbery-color* rgba)
|
||||
(define-extern *profile-generic-tie-color* rgba)
|
||||
(define-extern *profile-bones-color* rgba)
|
||||
(define-extern *profile-generic-merc-color* rgba)
|
||||
(define-extern *profile-shadow-color* rgba)
|
||||
(define-extern *profile-update-actors-color* rgba)
|
||||
(define-extern *profile-menu-hook-color* rgba)
|
||||
(define-extern *profile-texture-color* rgba)
|
||||
(define-extern *profile-effects-color* rgba)
|
||||
(define-extern *profile-sprite-color* rgba)
|
||||
(define-extern *profile-merc-color* rgba)
|
||||
(define-extern *profile-actors-color* rgba)
|
||||
(define-extern *profile-collide-color* rgba)
|
||||
(define-extern *profile-nav-color* rgba)
|
||||
(define-extern *profile-camera-color* rgba)
|
||||
(define-extern *profile-blit-color* rgba)
|
||||
(define-extern *profile-hud-color* rgba)
|
||||
(define-extern *profile-emerc-color* rgba)
|
||||
(define-extern *profile-array* profile-array)
|
||||
(define-extern *profile-collapse* profile-collapse)
|
||||
(define-extern *profile-interrupt-segment* profile-segment-array)
|
||||
(define-extern *profile-interrupt-start* symbol)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; dma ;;
|
||||
@@ -2686,18 +2765,17 @@
|
||||
;; dma-buffer ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
#|
|
||||
|
||||
(deftype dma-packet (structure)
|
||||
((dma uint64 :offset-assert 0) ;; dma-tag
|
||||
(vif0 vif-tag :offset-assert 8) ;; guessed by decompiler
|
||||
(vif1 vif-tag :offset-assert 12) ;; guessed by decompiler
|
||||
(quad uint128 :offset-assert 0)
|
||||
((dma dma-tag :offset-assert 0)
|
||||
(vif0 vif-tag :offset-assert 8)
|
||||
(vif1 vif-tag :offset-assert 12)
|
||||
(quad uint128 :offset 0)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
(deftype dma-packet-array (inline-array-class)
|
||||
@@ -2709,41 +2787,37 @@
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
(deftype dma-gif (structure)
|
||||
((gif UNKNOWN 2 :offset-assert 0)
|
||||
(quad uint128 :offset-assert 0)
|
||||
((gif uint64 2 :offset-assert 0)
|
||||
(quad uint128 :offset 0)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
(deftype dma-gif-packet (structure)
|
||||
((dma-vif dma-packet :inline :offset-assert 0)
|
||||
(gif uint64 2 :offset-assert 16) ;; guessed by decompiler
|
||||
(quad uint128 2 :offset-assert 0) ;; guessed by decompiler
|
||||
(gif uint64 2 :offset-assert 16)
|
||||
(quad uint128 2 :offset 0)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x20
|
||||
:flag-assert #x900000020
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
|
||||
(deftype dma-buffer (basic)
|
||||
((allocated-length int32 :offset-assert 4)
|
||||
(base pointer :offset-assert 8) ;; guessed by decompiler
|
||||
(end pointer :offset-assert 12) ;; guessed by decompiler
|
||||
(data uint64 1 :offset-assert 16) ;; guessed by decompiler
|
||||
(base pointer :offset-assert 8)
|
||||
(end pointer :offset-assert 12)
|
||||
(data uint64 1 :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x18
|
||||
:flag-assert #x900000018
|
||||
)
|
||||
|#
|
||||
|
||||
|
||||
;; (define-extern dma-buffer-inplace-new object) ;; (function dma-buffer int dma-buffer)
|
||||
;; (define-extern dma-buffer-length object) ;; (function dma-buffer int)
|
||||
@@ -3140,14 +3214,13 @@
|
||||
;; display-h ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
#|
|
||||
(deftype display-frame (basic)
|
||||
((buffer dma-buffer 11 :offset-assert 4) ;; guessed by decompiler
|
||||
(calc-buf dma-buffer :offset-assert 8) ;; guessed by decompiler
|
||||
(vu1-buf dma-buffer :offset-assert 8) ;; guessed by decompiler
|
||||
(debug-buf dma-buffer :offset-assert 36) ;; guessed by decompiler
|
||||
(global-buf dma-buffer :offset-assert 40) ;; guessed by decompiler
|
||||
(bucket-group dma-bucket :offset-assert 44) ;; (inline-array dma-bucket)
|
||||
(calc-buf dma-buffer :offset 8)
|
||||
(vu1-buf dma-buffer :offset 8)
|
||||
(debug-buf dma-buffer :offset 36)
|
||||
(global-buf dma-buffer :offset 40)
|
||||
(bucket-group dma-bucket :offset 44) ;; (inline-array dma-bucket)
|
||||
(profile-array profile-array :inline :offset-assert 48)
|
||||
(start-time uint64 :offset-assert 56)
|
||||
(run-time uint64 :offset-assert 64) ;; int64
|
||||
@@ -3156,32 +3229,30 @@
|
||||
:size-assert #x48
|
||||
:flag-assert #x900000048
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
(deftype display (basic)
|
||||
((on-screen int32 :offset-assert 4)
|
||||
(last-screen int32 :offset-assert 8)
|
||||
(frames virtual-frame 2 :offset-assert 12) ;; guessed by decompiler
|
||||
(frames display-frame 2 :offset-assert 12)
|
||||
(bgcolor uint64 :offset-assert 24)
|
||||
(pmode uint64 :offset-assert 32)
|
||||
(clock UNKNOWN 13 :offset-assert 40)
|
||||
(session-clock basic :offset-assert 40)
|
||||
(game-clock basic :offset-assert 44)
|
||||
(base-clock basic :offset-assert 48)
|
||||
(real-clock basic :offset-assert 52)
|
||||
(frame-clock basic :offset-assert 56)
|
||||
(real-frame-clock basic :offset-assert 60)
|
||||
(target-clock basic :offset-assert 64)
|
||||
(entity-clock basic :offset-assert 68)
|
||||
(part-clock basic :offset-assert 72)
|
||||
(bg-clock basic :offset-assert 76)
|
||||
(camera-clock basic :offset-assert 80)
|
||||
(user0-clock basic :offset-assert 84)
|
||||
(total-game-clock basic :offset-assert 88)
|
||||
(clock clock 13 :offset-assert 40)
|
||||
(session-clock clock :offset 40)
|
||||
(game-clock clock :offset 44)
|
||||
(base-clock clock :offset 48)
|
||||
(real-clock clock :offset 52)
|
||||
(frame-clock clock :offset 56)
|
||||
(real-frame-clock clock :offset 60)
|
||||
(target-clock clock :offset 64)
|
||||
(entity-clock clock :offset 68)
|
||||
(part-clock clock :offset 72)
|
||||
(bg-clock clock :offset 76)
|
||||
(camera-clock clock :offset 80)
|
||||
(user0-clock clock :offset 84)
|
||||
(total-game-clock clock :offset 88)
|
||||
(time-factor float :offset-assert 92)
|
||||
(dog-ratio float :offset-assert 96)
|
||||
(vblank-start-time UNKNOWN 2 :offset-assert 104)
|
||||
(vblank-start-time uint64 2 :offset-assert 104)
|
||||
(total-run-time uint64 :offset-assert 120)
|
||||
(run-half-speed basic :offset-assert 128)
|
||||
(dog-count float :offset-assert 132)
|
||||
@@ -3197,7 +3268,6 @@
|
||||
(dummy-9 () none 9) ;; (set-time-ratios (_type_ float) float 9)
|
||||
)
|
||||
)
|
||||
|#
|
||||
|
||||
;; (define-extern *pre-draw-hook* object) ;; (function object none)
|
||||
;; (define-extern *post-draw-hook* object) ;; (function dma-buffer none)
|
||||
@@ -3264,17 +3334,17 @@
|
||||
;; timer ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; (define-extern timer-count object) ;; (function timer-bank uint)
|
||||
;; (define-extern disable-irq object) ;; (function none)
|
||||
;; (define-extern enable-irq object) ;; (function none)
|
||||
;; (define-extern stopwatch-init object) ;; (function stopwatch int)
|
||||
;; (define-extern stopwatch-reset object) ;; (function stopwatch int)
|
||||
;; (define-extern stopwatch-start object) ;; (function stopwatch int)
|
||||
;; (define-extern stopwatch-stop object) ;; (function stopwatch none)
|
||||
;; (define-extern stopwatch-begin object) ;; (function stopwatch int)
|
||||
;; (define-extern stopwatch-end object) ;; (function stopwatch none)
|
||||
;; (define-extern stopwatch-elapsed-ticks object) ;; (function stopwatch time-frame)
|
||||
;; (define-extern stopwatch-elapsed-seconds object) ;; (function stopwatch float)
|
||||
(define-extern timer-count (function timer-bank uint))
|
||||
(define-extern disable-irq (function none))
|
||||
(define-extern enable-irq (function none))
|
||||
(define-extern stopwatch-init (function stopwatch int))
|
||||
(define-extern stopwatch-reset (function stopwatch int))
|
||||
(define-extern stopwatch-start (function stopwatch int))
|
||||
(define-extern stopwatch-stop (function stopwatch none))
|
||||
(define-extern stopwatch-begin (function stopwatch int))
|
||||
(define-extern stopwatch-end (function stopwatch none))
|
||||
(define-extern stopwatch-elapsed-ticks (function stopwatch time-frame))
|
||||
(define-extern stopwatch-elapsed-seconds (function stopwatch float))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; vector ;;
|
||||
@@ -4823,7 +4893,7 @@
|
||||
;; profile ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
#|
|
||||
|
||||
(deftype profile-work (structure)
|
||||
((sprite-tmpl dma-gif-packet :inline :offset-assert 0)
|
||||
(line-tmpl dma-gif-packet :inline :offset-assert 32)
|
||||
@@ -4833,14 +4903,13 @@
|
||||
:size-assert #x44
|
||||
:flag-assert #x900000044
|
||||
)
|
||||
|#
|
||||
|
||||
;; (define-extern *profile-work* object)
|
||||
;; (define-extern *profile-x* object) ;; int
|
||||
;; (define-extern *profile-y* object) ;; int
|
||||
;; (define-extern *profile-w* object) ;; int
|
||||
;; (define-extern *profile-h* object) ;; int
|
||||
;; (define-extern *profile-ticks* object) ;; symbol
|
||||
(define-extern *profile-work* profile-work)
|
||||
(define-extern *profile-x* int)
|
||||
(define-extern *profile-y* int)
|
||||
(define-extern *profile-w* int)
|
||||
(define-extern *profile-h* int)
|
||||
(define-extern *profile-ticks* symbol)
|
||||
;; (define-extern profile-texture-test object)
|
||||
;; (define-extern profile-tfrag-test object)
|
||||
;; (define-extern profile-tie-test object)
|
||||
@@ -4868,7 +4937,7 @@
|
||||
;; (define-extern set-display-gs-state-offset object) ;; (function dma-buffer int int int int int int int dma-buffer)
|
||||
;; (define-extern reset-display-gs-state object) ;; (function display dma-buffer int display)
|
||||
;; (define-extern *vu0-dma-list* object) ;; dma-buffer
|
||||
;; (define-extern *display* object) ;; display
|
||||
(define-extern *display* display)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; connect ;;
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
{}
|
||||
{
|
||||
"profile": [
|
||||
["L14", "profile-work"]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
("KERNEL.CGO"
|
||||
("gcommon.o" "gcommon")
|
||||
("gstring-h.o" "gstring-h")
|
||||
("gkernel-h.o" "gkernel-h")
|
||||
("gkernel.o" "gkernel")
|
||||
("pskernel.o" "pskernel")
|
||||
("gstring.o" "gstring")
|
||||
("dgo-h.o" "dgo-h")
|
||||
("gstate.o" "gstate")
|
||||
)
|
||||
@@ -5,3 +5,89 @@
|
||||
;; name in dgo: timer-h
|
||||
;; dgos: ENGINE, GAME
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; PC Port Timer
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(defmacro get-cpu-clock ()
|
||||
"Read the 300 MHz clock."
|
||||
;; __read-ee-timer is a 300 MHz timer from the C Kernel.
|
||||
;; it's a real timer.
|
||||
`(the uint (logand #xffffffff (__read-ee-timer)))
|
||||
)
|
||||
|
||||
(defmacro get-bus-clock/256 ()
|
||||
"Read the 150 MHz / 256 clock."
|
||||
;; 300 MHz / (2^9)
|
||||
`(the uint (logand #xffffffff (shr (__read-ee-timer) 9)))
|
||||
)
|
||||
|
||||
(#when PC_PORT
|
||||
;; the bus clock can be reset, which just stores the current count here.
|
||||
(define *timer-reset-value* (the uint 0))
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Timer HW
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(deftype timer-mode (uint32)
|
||||
((clks timer-clock-selection :offset 0 :size 2)
|
||||
(gate uint8 :offset 2 :size 1)
|
||||
(gats uint8 :offset 3 :size 1)
|
||||
(gatm uint8 :offset 4 :size 2)
|
||||
(zret uint8 :offset 6 :size 1)
|
||||
(cue uint8 :offset 7 :size 1)
|
||||
(cmpe uint8 :offset 8 :size 1)
|
||||
(ovfe uint8 :offset 9 :size 1)
|
||||
(equf uint8 :offset 10 :size 1)
|
||||
(ovff uint8 :offset 11 :size 1)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x4
|
||||
:flag-assert #x900000004
|
||||
)
|
||||
|
||||
(deftype timer-bank (structure)
|
||||
((count uint32 :offset-assert 0)
|
||||
(mode timer-mode :offset 16)
|
||||
(comp uint32 :offset 32)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x24
|
||||
:flag-assert #x900000024
|
||||
)
|
||||
|
||||
(deftype timer-hold-bank (timer-bank)
|
||||
((hold uint32 :offset 48)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x34
|
||||
:flag-assert #x900000034
|
||||
)
|
||||
|
||||
(deftype stopwatch (basic)
|
||||
((prev-time-elapsed time-frame :offset-assert 8)
|
||||
(start-time time-frame :offset-assert 16)
|
||||
(begin-level int32 :offset-assert 24)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x1c
|
||||
:flag-assert #x90000001c
|
||||
)
|
||||
|
||||
(define *ticks-per-frame* 9765)
|
||||
|
||||
(defun timer-init ((arg0 timer-bank) (arg1 timer-mode))
|
||||
(set! (-> arg0 mode) arg1)
|
||||
(set! (-> arg0 count) (the-as uint 0))
|
||||
0
|
||||
)
|
||||
|
||||
(#unless PC_PORT
|
||||
(timer-init
|
||||
(the-as timer-bank #x10000800)
|
||||
(new 'static 'timer-mode :clks (timer-clock-selection busclk/256) :cue #x1)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -173,4 +173,9 @@
|
||||
,@(reverse *all-mus*)
|
||||
,@(reverse *all-vag*)
|
||||
,@(reverse *all-cgos*))
|
||||
)
|
||||
)
|
||||
|
||||
;; used for the type consistency test.
|
||||
(group-list "all-code"
|
||||
`(,@(reverse *all-gc*))
|
||||
)
|
||||
|
||||
@@ -5,6 +5,26 @@
|
||||
;;;; kscheme - InitHeapAndSymbol
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defenum kmalloc-flags
|
||||
:bitfield #t
|
||||
(align-16 4)
|
||||
(align-64 6)
|
||||
(align-256 8)
|
||||
(memset 12)
|
||||
(top 13)
|
||||
)
|
||||
|
||||
(defenum link-flag
|
||||
:bitfield #t
|
||||
:type int32
|
||||
(output-load-msg 0)
|
||||
(output-load-true-msg 1)
|
||||
(execute-login 2)
|
||||
(print-login 3)
|
||||
(force-debug 4)
|
||||
(fast-link 5)
|
||||
)
|
||||
|
||||
;; fixed symbols
|
||||
(define-extern #f symbol)
|
||||
(define-extern #t symbol)
|
||||
@@ -59,32 +79,19 @@
|
||||
;; InitHeapAndSymbol
|
||||
(define-extern _format (function _varargs_ object))
|
||||
(define-extern method-set! (function type int object none)) ;; may actually return function.
|
||||
(define-extern kmemopen (function kheap string none))
|
||||
(define-extern kmemclose (function none))
|
||||
|
||||
(define-extern *enable-method-set* int)
|
||||
|
||||
(define-extern *listener-function* (function object))
|
||||
(define-extern *debug-segment* symbol)
|
||||
|
||||
(define-extern dgo-load (function string kheap link-flag int none))
|
||||
(define-extern malloc (function symbol int pointer))
|
||||
|
||||
|
||||
(defenum kmalloc-flags
|
||||
:bitfield #t
|
||||
(align-16 4)
|
||||
(align-64 6)
|
||||
(align-256 8)
|
||||
(memset 12)
|
||||
(top 13)
|
||||
)
|
||||
|
||||
(defenum link-flag
|
||||
:bitfield #t
|
||||
:type int32
|
||||
(output-load-msg 0)
|
||||
(output-load-true-msg 1)
|
||||
(execute-login 2)
|
||||
(print-login 3)
|
||||
(force-debug 4)
|
||||
(fast-link 5)
|
||||
)
|
||||
|
||||
|
||||
;; PC stuff
|
||||
|
||||
@@ -5,3 +5,23 @@
|
||||
;; name in dgo: dgo-h
|
||||
;; dgos: KERNEL
|
||||
|
||||
(deftype dgo-entry (structure)
|
||||
((offset uint32 :offset-assert 0)
|
||||
(length uint32 :offset-assert 4)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x8
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
|
||||
(deftype dgo-file (basic)
|
||||
((num-go-files uint32 :offset-assert 4)
|
||||
(total-length uint32 :offset-assert 8)
|
||||
(rsvd uint32 :offset-assert 12)
|
||||
(data uint8 :dynamic :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
@@ -24,6 +24,23 @@
|
||||
;; GOAL code to the frame profiler in C++.
|
||||
(defglobalconstant PC_PROFILER_ENABLE #t)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; GOAL language constants
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; distance from a symbol pointer to a (pointer string)
|
||||
;; this relies on the memory layout of the symbol table
|
||||
;; this must match SYM_TO_STRING_OFFSET in goal_constants.h
|
||||
(defconstant SYM_TO_STRING_OFFSET #xff37)
|
||||
|
||||
(defmacro symbol->string (sym)
|
||||
"Convert a symbol to a goal string."
|
||||
`(-> (the-as (pointer string) (+ SYM_TO_STRING_OFFSET (the-as int ,sym))))
|
||||
)
|
||||
|
||||
;; pointers larger than this are invalid by valid?
|
||||
(defconstant END_OF_MEMORY #x8000000)
|
||||
|
||||
(defun identity ((arg0 object))
|
||||
arg0
|
||||
)
|
||||
@@ -170,6 +187,19 @@
|
||||
obj
|
||||
)
|
||||
|
||||
(deftype vector (structure)
|
||||
((data float 4 :offset-assert 0)
|
||||
(x float :offset 0)
|
||||
(y float :offset 4)
|
||||
(z float :offset 8)
|
||||
(w float :offset 12)
|
||||
(quad uint128 :offset 0)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
(defmacro print128 (value &key (stream #t))
|
||||
"Print a 128-bit value"
|
||||
`(let ((temp (new 'stack-no-clear 'array 'uint64 2)))
|
||||
@@ -911,6 +941,208 @@
|
||||
(break!)
|
||||
)
|
||||
|
||||
(defmacro start-of-symbol-table ()
|
||||
`(rlet ((st :reg r14 :reset-here #t :type uint))
|
||||
(the uint (- st 32768))
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro end-of-symbol-table ()
|
||||
`(rlet ((st :reg r14 :reset-here #t :type uint))
|
||||
(the uint (+ st 32768))
|
||||
)
|
||||
)
|
||||
|
||||
(define-extern boolean type) ;; not really... but they use it here as if it was one.
|
||||
(define-extern valid? (function object type symbol symbol object symbol))
|
||||
|
||||
(defun valid? ((arg0 object) (arg1 type) (arg2 symbol) (arg3 symbol) (arg4 object))
|
||||
(let ((v1-1
|
||||
(and (>= (the-as uint arg0) (start-of-symbol-table)) (< (the-as uint arg0) END_OF_MEMORY))
|
||||
)
|
||||
)
|
||||
(cond
|
||||
((not arg1)
|
||||
(cond
|
||||
((logtest? (the-as int arg0) 3)
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object (misaligned)~%" arg0 arg2)
|
||||
)
|
||||
#f
|
||||
)
|
||||
((not v1-1)
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object (bad address)~%" arg0 arg2)
|
||||
)
|
||||
#f
|
||||
)
|
||||
(else
|
||||
#t
|
||||
)
|
||||
)
|
||||
)
|
||||
((and arg3 (not arg0))
|
||||
#t
|
||||
)
|
||||
((= arg1 structure)
|
||||
(cond
|
||||
((logtest? (the-as int arg0) 15)
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1)
|
||||
)
|
||||
#f
|
||||
)
|
||||
((or (not v1-1) (< (the-as uint arg0) (end-of-symbol-table)))
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" arg0 arg2 arg1)
|
||||
)
|
||||
#f
|
||||
)
|
||||
(else
|
||||
#t
|
||||
)
|
||||
)
|
||||
)
|
||||
((= arg1 pair)
|
||||
(cond
|
||||
((not (pair? arg0))
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1)
|
||||
)
|
||||
#f
|
||||
)
|
||||
((not v1-1)
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" arg0 arg2 arg1)
|
||||
)
|
||||
#f
|
||||
)
|
||||
(else
|
||||
#t
|
||||
)
|
||||
)
|
||||
)
|
||||
((= arg1 binteger)
|
||||
(cond
|
||||
((zero? (logand (the-as int arg0) 7))
|
||||
#t
|
||||
)
|
||||
(else
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1)
|
||||
)
|
||||
#f
|
||||
)
|
||||
)
|
||||
)
|
||||
((or (= arg1 symbol) (= arg1 boolean))
|
||||
(cond
|
||||
((zero? (logand (the-as int arg0) 1))
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1)
|
||||
)
|
||||
#f
|
||||
)
|
||||
((or (not v1-1) (< (the-as int arg0) (start-of-symbol-table))(>= (the-as int arg0) (end-of-symbol-table)))
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" arg0 arg2 arg1)
|
||||
)
|
||||
#f
|
||||
)
|
||||
(else
|
||||
#t
|
||||
)
|
||||
)
|
||||
)
|
||||
((!= (logand (the-as int arg0) 7) 4)
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (misaligned)~%" arg0 arg2 arg1)
|
||||
)
|
||||
#f
|
||||
)
|
||||
((not v1-1)
|
||||
(if arg2
|
||||
(format arg4 "ERROR: object #x~X ~S is not a valid object of type '~A' (bad address)~%" arg0 arg2 arg1)
|
||||
)
|
||||
#f
|
||||
)
|
||||
((and (= arg1 type) (!= (rtype-of arg0) type))
|
||||
(if arg2
|
||||
(format
|
||||
arg4
|
||||
"ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%"
|
||||
arg0
|
||||
arg2
|
||||
arg1
|
||||
(rtype-of arg0)
|
||||
)
|
||||
)
|
||||
#f
|
||||
)
|
||||
((and (!= arg1 type) (not (valid? (rtype-of arg0) type #f #t 0)))
|
||||
(if arg2
|
||||
(format
|
||||
arg4
|
||||
"ERROR: object #x~X ~S is not a valid object of type '~A' (invalid type #x~X)~%"
|
||||
arg0
|
||||
arg2
|
||||
arg1
|
||||
(rtype-of arg0)
|
||||
)
|
||||
)
|
||||
#f
|
||||
)
|
||||
((not (type? arg0 arg1))
|
||||
(if arg2
|
||||
(format
|
||||
arg4
|
||||
"ERROR: object #x~X ~S is not a valid object of type '~A' (is type '~A' instead)~%"
|
||||
arg0
|
||||
arg2
|
||||
arg1
|
||||
(rtype-of arg0)
|
||||
)
|
||||
)
|
||||
#f
|
||||
)
|
||||
((= arg1 symbol)
|
||||
(cond
|
||||
((>= (the-as uint arg0) (end-of-symbol-table))
|
||||
(if arg2
|
||||
(format
|
||||
arg4
|
||||
"ERROR: object #x~X ~S is not a valid object of type '~A' (not in symbol table)~%"
|
||||
arg0
|
||||
arg2
|
||||
arg1
|
||||
)
|
||||
)
|
||||
#f
|
||||
)
|
||||
(else
|
||||
#t
|
||||
)
|
||||
)
|
||||
)
|
||||
((< (the-as uint arg0) (end-of-symbol-table))
|
||||
(if arg2
|
||||
(format
|
||||
arg4
|
||||
"ERROR: object #x~X ~S is not a valid object of type '~A' (inside symbol table)~%"
|
||||
arg0
|
||||
arg2
|
||||
arg1
|
||||
)
|
||||
)
|
||||
#f
|
||||
)
|
||||
(else
|
||||
#t
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;
|
||||
;; Profiler Macros
|
||||
;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@@ -6,4 +6,687 @@
|
||||
;; dgos: KERNEL
|
||||
|
||||
(defconstant *kernel-major-version* 2)
|
||||
(defconstant *kernel-minor-version* 0)
|
||||
(defconstant *kernel-minor-version* 0)
|
||||
|
||||
(defconstant DPROCESS_STACK_SIZE (#if PC_PORT #x8000 #x3800))
|
||||
(defconstant PROCESS_STACK_SIZE (#if PC_PORT #x6000 #x1c00))
|
||||
|
||||
(defconstant *tab-size* (the binteger 8))
|
||||
(defconstant *gtype-basic-offset* 4)
|
||||
|
||||
;; if set, will attempt to detect memory corruption and stack overflow bugs
|
||||
;; to some extent.
|
||||
(defglobalconstant KERNEL_DEBUG #t)
|
||||
|
||||
(defconstant *scratch-memory-top* (the pointer #x70004000))
|
||||
|
||||
|
||||
;; Each process has a bitmask.
|
||||
;; The kernel can be configured to skip processes with certain mask bits set.
|
||||
(defenum process-mask
|
||||
:type uint32
|
||||
:bitfield #t
|
||||
(execute 0)
|
||||
(freeze 1)
|
||||
(pause 2)
|
||||
(menu 3)
|
||||
(progress 4)
|
||||
(actor-pause 5)
|
||||
(sleep 6)
|
||||
(sleep-code 7)
|
||||
(process-tree 8)
|
||||
(heap-shrunk 9)
|
||||
(going 10)
|
||||
(kernel-run 11)
|
||||
(no-kill 12)
|
||||
(movie 13)
|
||||
(dark-effect 14)
|
||||
(target 15)
|
||||
(sidekick 16)
|
||||
(crate 17)
|
||||
(bit18 18) ;; unused?
|
||||
(enemy 19)
|
||||
(camera 20)
|
||||
(platform 21)
|
||||
(ambient 22)
|
||||
(entity 23)
|
||||
(projectile 24)
|
||||
(bot 25)
|
||||
(collectable 26)
|
||||
(death 27)
|
||||
(no-track 28)
|
||||
(guard 29)
|
||||
(vehicle 30)
|
||||
(civilian 31)
|
||||
)
|
||||
|
||||
;; forward declarations
|
||||
(declare-type process-tree basic)
|
||||
(declare-type process process-tree)
|
||||
(declare-type entity basic)
|
||||
(declare-type entity-actor entity)
|
||||
(declare-type dead-pool basic)
|
||||
(declare-type level basic)
|
||||
(declare-type state basic)
|
||||
(declare-type event-message-block structure)
|
||||
(declare-type stack-frame basic)
|
||||
(declare-type cpu-thread basic)
|
||||
|
||||
|
||||
;; The state of the kernel, containing the masks to allow/deny certain processes,
|
||||
;; the currently running process, and the currently relocating process.
|
||||
(deftype kernel-context (basic)
|
||||
((prevent-from-run process-mask :offset-assert 4)
|
||||
(require-for-run process-mask :offset-assert 8)
|
||||
(allow-to-run process-mask :offset-assert 12)
|
||||
(next-pid int32 :offset-assert 16)
|
||||
(fast-stack-top pointer :offset-assert 20)
|
||||
(current-process process :offset-assert 24)
|
||||
(relocating-process basic :offset-assert 28)
|
||||
(relocating-min int32 :offset-assert 32)
|
||||
(relocating-max int32 :offset-assert 36)
|
||||
(relocating-offset int32 :offset-assert 40)
|
||||
(relocating-level level :offset-assert 44)
|
||||
(low-memory-message symbol :offset-assert 48)
|
||||
(login-object basic :offset-assert 52)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x38
|
||||
:flag-assert #x900000038
|
||||
)
|
||||
|
||||
;; The usual "time" type.
|
||||
(deftype time-frame (int64)
|
||||
()
|
||||
:method-count-assert 9
|
||||
:size-assert #x8
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
;; times are stored in 300ths of a second.
|
||||
;; this divides evenly into frames at both 50 and 60 fps.
|
||||
;; typically these are stored as integers as more precision is not useful.
|
||||
;; an unsigned 32-bit integer can store about 150 days
|
||||
(defglobalconstant TICKS_PER_SECOND 300) ;; 5 t/frame @ 60fps, 6 t/frame @ 50fps
|
||||
|
||||
;; this was usec in GOAL
|
||||
(defmacro seconds (x)
|
||||
"Convert number to seconds unit.
|
||||
Returns uint."
|
||||
(cond
|
||||
((integer? x)
|
||||
(* TICKS_PER_SECOND x)
|
||||
)
|
||||
((float? x)
|
||||
(* 1 (* 1.0 x TICKS_PER_SECOND))
|
||||
)
|
||||
(#t
|
||||
`(the uint (* TICKS_PER_SECOND ,x))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; Each clock counts in 3 different ways:
|
||||
;;
|
||||
;; 1). A "frame counter", which, confusingly, doesn't count frames.
|
||||
;; It counts elapsed time, in 1/300ths of a second.
|
||||
;; This counts in real-time, even if the game is lagging.
|
||||
;;
|
||||
;; 2). A "integral-frame-counter", which counts the number of vsyncs.
|
||||
;; This doens't count the number of frames the game actually manages to draw,
|
||||
;; just the number of vsyncs. It counts at different rates in NTSC/PAL.
|
||||
;; NOTE: changing clock-ratio will make this count faster/slower. This only counts real
|
||||
;; vsyncs if clock-ratio is 1.0.
|
||||
;;
|
||||
;; 3). The "time ratio", which adjusts based on the actual achieved framerate.
|
||||
;; Unlock the others, this isn't a incrementing counter, but instead ratios:
|
||||
;; time-adjust-ratio, frames-per-second, seconds-per-frame.
|
||||
;;
|
||||
;;
|
||||
;; The clock won't tick if its process-mask is prevent-from-run in the kernel.
|
||||
;; A clock can change the rate it runs at with clock-ratio.
|
||||
;; Note: both integral-frame-counter and seconds-per-frame/frames-per-second are affected by
|
||||
;; clock-ratio, which is somewhat weird.
|
||||
;; Changing clock-ratio will make integral-frame-counter not count actual vsyncs
|
||||
|
||||
(deftype clock (basic)
|
||||
((index int32 :offset-assert 4) ;; which clock we are, in *display*
|
||||
(mask process-mask :offset-assert 8) ;; mask for ticking
|
||||
(clock-ratio float :offset-assert 12) ;; how fast to run. 1.0 = realtime.
|
||||
(accum float :offset-assert 16) ;; fractional time for frame-counter (time-frame units)
|
||||
(integral-accum float :offset-assert 20) ;; fractional time for integral (time-frame untis)
|
||||
(frame-counter time-frame :offset-assert 24) ;; how much time has gone by since reset (time-frame units)
|
||||
(old-frame-counter time-frame :offset-assert 32) ;; the frame-counter on the last engine iteration
|
||||
(integral-frame-counter uint64 :offset-assert 40) ;; how many vsyncs have gone by since reset
|
||||
(old-integral-frame-counter uint64 :offset-assert 48) ;; the integral-frame-counter on the last engine iteration
|
||||
(sparticle-data vector :inline :offset-assert 64) ;; sparticle timescale info
|
||||
(seconds-per-frame float :offset-assert 80) ;; how many seconds (not time-frames) should go by in 1 vsync
|
||||
(frames-per-second float :offset-assert 84) ;; inverse of above
|
||||
(time-adjust-ratio float :offset-assert 88) ;; 1, if the game runs at 60fps NTSC with clock-ratio = 1.
|
||||
)
|
||||
:method-count-assert 15
|
||||
:size-assert #x5c
|
||||
:flag-assert #xf0000005c
|
||||
(:methods
|
||||
(new (symbol type int) _type_ 0)
|
||||
(update-rates! (_type_ float) none 9)
|
||||
(advance-by! (_type_ float) none 10)
|
||||
(tick! (_type_) none 11)
|
||||
(save! (_type_ (pointer uint64)) int 12)
|
||||
(load! (_type_ (pointer uint64)) int 13)
|
||||
(reset! (_type_) none 14)
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod new clock ((allocation symbol) (type-to-make type) (arg0 int))
|
||||
(let ((gp-0 (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
|
||||
(set! (-> gp-0 index) arg0)
|
||||
(set! (-> gp-0 frame-counter) (seconds 1000))
|
||||
(set! (-> gp-0 integral-frame-counter) (the-as uint 300000))
|
||||
(set! (-> gp-0 old-frame-counter) (+ (-> gp-0 frame-counter) -1))
|
||||
(set! (-> gp-0 old-integral-frame-counter) (+ (-> gp-0 integral-frame-counter) -1))
|
||||
(update-rates! gp-0 1.0)
|
||||
gp-0
|
||||
)
|
||||
)
|
||||
|
||||
;; The basic node used to organize processes into a tree.
|
||||
;; The process types themselves are children of the process-tree type
|
||||
;; Typically, each instance of a game object is a process.
|
||||
(deftype process-tree (basic)
|
||||
((name string :offset-assert 4)
|
||||
(mask process-mask :offset-assert 8)
|
||||
(clock clock :offset-assert 12)
|
||||
(parent (pointer process-tree) :offset-assert 16)
|
||||
(brother (pointer process-tree) :offset-assert 20)
|
||||
(child (pointer process-tree) :offset-assert 24)
|
||||
(ppointer (pointer process) :offset-assert 28)
|
||||
(self process-tree :offset-assert 32)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type string) _type_ 0)
|
||||
(activate (_type_ process-tree basic pointer) process-tree 9)
|
||||
(deactivate (_type_) none 10)
|
||||
(init-from-entity! (_type_ entity-actor) none 11) ;; todo check
|
||||
(run-logic? (_type_) symbol 12)
|
||||
(dummy-13 () none 13)
|
||||
)
|
||||
:size-assert #x24
|
||||
:method-count-assert 14
|
||||
:no-runtime-type
|
||||
)
|
||||
|
||||
;; Each process has a single "main" thread that is suspended and resumed.
|
||||
;; The "thread" object is what holds the needed state to start, suspend, and resume execution.
|
||||
;; Additionally, the kernel creates various temporary threads to run single functions.
|
||||
;; These "temporary" threads are never suspended.
|
||||
|
||||
;; unlike modern implementations, the "thread" objects store small "backup" stacks (often only 100's of bytes).
|
||||
;; when a thread is suspended, it copies the stack from the execution stack to the backup stack.
|
||||
;; this seems silly, but it has an advantage to reduce memory - typically threads suspend without a very deep call
|
||||
;; stack, so the backup stack can be much, much smaller than a single large, shared execution stack.
|
||||
(deftype thread (basic)
|
||||
((name symbol :offset-assert 4)
|
||||
(process process :offset-assert 8)
|
||||
(previous thread :offset-assert 12)
|
||||
(suspend-hook (function cpu-thread none) :offset-assert 16) ;; called by user to suspend
|
||||
(resume-hook (function cpu-thread none) :offset-assert 20) ;; called by kernel to resume
|
||||
(pc pointer :offset-assert 24) ;; pc (x86 rip) to resume to
|
||||
(sp pointer :offset-assert 28) ;; stack pointer of thread
|
||||
(stack-top pointer :offset-assert 32) ;; stack to execute on
|
||||
(stack-size int32 :offset-assert 36) ;; size of _suspend_ stack
|
||||
)
|
||||
:method-count-assert 12
|
||||
:size-assert #x28
|
||||
:flag-assert #xc00000028
|
||||
(:methods
|
||||
(stack-size-set! (_type_ int) none 9)
|
||||
(thread-suspend (_type_) none 10)
|
||||
(thread-resume (_type_) none 11)
|
||||
)
|
||||
)
|
||||
|
||||
;; additional information to context switch
|
||||
(deftype cpu-thread (thread)
|
||||
((rreg uint64 7 :offset-assert 40) ;; GPRs
|
||||
(freg float 8 :offset-assert 96) ;; FPRs
|
||||
(stack uint8 :dynamic :offset-assert 128) ;; backup stack (dynamically sized)
|
||||
)
|
||||
:method-count-assert 12
|
||||
:size-assert #x80
|
||||
:flag-assert #xc00000080
|
||||
(:methods
|
||||
(new (symbol type process symbol int pointer) _type_ 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; Base type for all actual processes.
|
||||
;; this can be used directly, or child types can be made.
|
||||
(deftype process (process-tree)
|
||||
((pool dead-pool ) ;; where to return us when we die
|
||||
(status symbol :offset-assert 40) ;; used by kernel to track init/death
|
||||
(pid int32 ) ;; globally unique ID, never reused for another
|
||||
(main-thread cpu-thread :offset-assert 48) ;; suspendable main thread
|
||||
(top-thread cpu-thread :offset-assert 52) ;; currently running thread
|
||||
(entity entity :offset-assert 56) ;; if we were spawned from an entity, that entity
|
||||
(level level :offset-assert 60) ;; if we're associated with a level, that level
|
||||
(state state :offset-assert 64) ;; current state, if we're in one
|
||||
(next-state state :offset-assert 68) ;; set if we have a pending (go)
|
||||
(trans-hook function :offset-assert 72) ;; function to run before resuming
|
||||
(post-hook function :offset-assert 76) ;; function to run after suspending
|
||||
|
||||
;; function to run if we receive an event
|
||||
(event-hook (function process int symbol event-message-block object) :offset-assert 80)
|
||||
|
||||
;; process heap size
|
||||
(allocated-length int32 :offset-assert 84)
|
||||
|
||||
;; ??
|
||||
(pad0 uint32 2)
|
||||
|
||||
;; process heap
|
||||
(heap-base pointer :offset-assert 96)
|
||||
(heap-top pointer :offset-assert 100)
|
||||
(heap-cur pointer :offset-assert 104)
|
||||
|
||||
;; linked list of stack frames that have been created.
|
||||
;; note that these aren't created on every function call, only
|
||||
;; if the user explicitly creates a catch block or similar
|
||||
(stack-frame-top stack-frame :offset-assert 108)
|
||||
|
||||
;; list of engines this process is connected to
|
||||
(connection-list connectable :inline :offset-assert 112)
|
||||
|
||||
;; the process memory: contains child fields, then the process heap.
|
||||
(stack uint8 :dynamic :offset-assert 128)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type string int) _type_ 0)
|
||||
)
|
||||
(:states
|
||||
dead-state
|
||||
empty-state)
|
||||
:size-assert #x80
|
||||
:method-count-assert 14
|
||||
:no-runtime-type ;; already defined by kscheme. Don't do it again.
|
||||
)
|
||||
|
||||
;; dead-pool simplest way to store dead processes - it's just a tree of processes that
|
||||
;; are inactive.
|
||||
(deftype dead-pool (process-tree)
|
||||
()
|
||||
:method-count-assert 16
|
||||
:size-assert #x24
|
||||
:flag-assert #x1000000024
|
||||
(:methods
|
||||
(new (symbol type int int string) _type_ 0)
|
||||
(get-process (_type_ type int) process 14)
|
||||
(return-process (_type_ process) none 15)
|
||||
)
|
||||
)
|
||||
|
||||
;; todo inspect
|
||||
|
||||
;; dead-pool-heap is a special thing - it pretends to be a dead-pool, but secretly
|
||||
;; creates and destroys processes on demand, as they are requested/returned.
|
||||
;; to do this, it has a single large heap and memory allocator.
|
||||
;; to prevent fragmentation of this heap, it has a relocate/compaction system
|
||||
;; that moves processes in memory.
|
||||
|
||||
|
||||
;; A dead-pool-heap-rec is a record for a process used by the handle system.
|
||||
;; The kernel will make sure that:
|
||||
;; - the dead-pool-heap-rec for a process will continue to point to that process until the process
|
||||
;; is killed.
|
||||
;; - the dead-pool-heap-rec itself is never moved in memory, and it always points to some process, or #f.
|
||||
;; (it is always safe to do (-> rec process pid) and see if it still points to your process)
|
||||
(deftype dead-pool-heap-rec (structure)
|
||||
((process process :offset-assert 0)
|
||||
(prev dead-pool-heap-rec :offset-assert 4)
|
||||
(next dead-pool-heap-rec :offset-assert 8)
|
||||
)
|
||||
:pack-me
|
||||
:method-count-assert 9
|
||||
:size-assert #xc
|
||||
:flag-assert #x90000000c
|
||||
)
|
||||
|
||||
;; the actual pool implementation
|
||||
(deftype dead-pool-heap (dead-pool)
|
||||
((allocated-length int32 :offset-assert 36)
|
||||
(compact-time uint32 :offset-assert 40)
|
||||
(compact-count-targ uint32 :offset-assert 44)
|
||||
(compact-count uint32 :offset-assert 48)
|
||||
(fill-percent float :offset-assert 52)
|
||||
(first-gap dead-pool-heap-rec :offset-assert 56)
|
||||
(first-shrink dead-pool-heap-rec :offset-assert 60)
|
||||
(heap kheap :inline :offset-assert 64)
|
||||
(alive-list dead-pool-heap-rec :inline :offset-assert 80)
|
||||
(last dead-pool-heap-rec :offset 84)
|
||||
(dead-list dead-pool-heap-rec :inline :offset-assert 92)
|
||||
(process-list dead-pool-heap-rec :inline :dynamic :offset-assert 104)
|
||||
)
|
||||
:method-count-assert 28
|
||||
:size-assert #x68
|
||||
:flag-assert #x1c00000068
|
||||
(:methods
|
||||
(new (symbol type string int int) _type_ 0)
|
||||
(init (_type_ symbol int) none 16)
|
||||
(compact (dead-pool-heap int) none 17)
|
||||
(shrink-heap (dead-pool-heap process) dead-pool-heap 18)
|
||||
(churn (dead-pool-heap int) none 19)
|
||||
(memory-used (_type_) int 20)
|
||||
(memory-total (_type_) int 21)
|
||||
(memory-free (dead-pool-heap) int 22)
|
||||
(compact-time (dead-pool-heap) uint 23)
|
||||
(gap-size (dead-pool-heap dead-pool-heap-rec) int 24)
|
||||
(gap-location (dead-pool-heap dead-pool-heap-rec) pointer 25)
|
||||
(find-gap (dead-pool-heap dead-pool-heap-rec) dead-pool-heap-rec 26)
|
||||
(find-gap-by-size (dead-pool-heap int) dead-pool-heap-rec 27)
|
||||
)
|
||||
)
|
||||
|
||||
;; todo inspect
|
||||
|
||||
;; parent type for all kinds of stack-frames.
|
||||
;; at least for jak 1, these are only used internally by the kernel
|
||||
;; "next" brings you "up" the stack (toward the caller)
|
||||
(deftype stack-frame (basic)
|
||||
((name symbol :offset 4)
|
||||
(next stack-frame :offset 8)
|
||||
)
|
||||
:size-assert #xc
|
||||
:method-count-assert 9
|
||||
:flag-assert #x90000000c
|
||||
)
|
||||
|
||||
;; a "catch" frame is a frame that can be "thrown" to.
|
||||
;; the "throw" is a nonlocal control flow back to the state befor the "catch" block.
|
||||
(deftype catch-frame (stack-frame)
|
||||
((sp int32 :offset-assert 12)
|
||||
(ra int32 :offset-assert 16)
|
||||
(freg float 6 :offset-assert 20)
|
||||
(rreg uint128 8 :offset-assert 48)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #xb0
|
||||
:flag-assert #x9000000b0
|
||||
(:methods
|
||||
(new (symbol type symbol function (pointer uint64)) object 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; a "protect" frame is a way to indicate there's a "exit" function that should
|
||||
;; run if there's a "throw" or "abandon".
|
||||
(deftype protect-frame (stack-frame)
|
||||
((exit (function none) :offset-assert 12)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
(:methods
|
||||
(new (symbol type (function none)) protect-frame 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; a handle is a safe way to refer to a process. It solves two problems:
|
||||
;; - it allows you to find a process that moves in memory
|
||||
;; - it allows you to tell if the original process has died. otherwise you may get confused
|
||||
;; because there could be another process located at the exact same address.
|
||||
(deftype handle (uint64)
|
||||
((process (pointer process) :offset 0 :size 32) ;; additional level of indirection to support moving processes
|
||||
(pid int32 :offset 32 :size 32) ;; unique pid to check if it's the same process or not.
|
||||
(u64 uint64 :offset 0 :size 64)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x8
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
(defmethod inspect handle ((obj handle))
|
||||
(when (not obj)
|
||||
(return obj)
|
||||
)
|
||||
(format #t "[~8x] ~A~%" obj 'handle)
|
||||
(format #t "~1Tprocess: #x~X~%" (-> obj process))
|
||||
(format #t "~1Tpid: ~D~%" (-> obj pid))
|
||||
obj
|
||||
)
|
||||
|
||||
(defmacro handle->process (handle)
|
||||
"Convert a handle to a process. If the process no longer exists, returns #f."
|
||||
`(let ((the-handle (the-as handle ,handle)))
|
||||
(if (-> the-handle process) ;; if we don't point to a process, kernel sets this to #f
|
||||
(let ((proc (-> (-> the-handle process))))
|
||||
(if (= (-> the-handle pid) (-> proc pid)) ;; make sure it's the same process
|
||||
proc
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro ppointer->process (ppointer)
|
||||
"convert a (pointer process) to a process."
|
||||
;; this uses the self field, which seems to always just get set to the object.
|
||||
;; confirmed in Jak 1 that using self here is useless, not sure...
|
||||
`(let ((the-pp ,ppointer))
|
||||
(the process-tree (if the-pp (-> the-pp 0 self)))
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro process->ppointer (proc)
|
||||
"safely get a (pointer process) from a process, returning #f if invalid."
|
||||
`(let ((the-proc ,proc))
|
||||
(if the-proc (-> the-proc ppointer))
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro ppointer->handle (pproc)
|
||||
"convert a ppointer to a handle. assumes the ppointer is valid."
|
||||
`(let ((the-process (the-as (pointer process) ,pproc)))
|
||||
(new 'static 'handle :process the-process :pid (-> the-process 0 pid))
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro process->handle (proc)
|
||||
"convert a process to a handle. if proc is #f, returns a #f handle."
|
||||
`(ppointer->handle (process->ppointer ,proc))
|
||||
)
|
||||
|
||||
(defmethod print handle ((obj handle))
|
||||
(if (nonzero? obj)
|
||||
(format #t "#<handle :process ~A :pid ~D>" (handle->process obj) (-> obj pid))
|
||||
(format #t "#<handle :process 0 :pid 0>")
|
||||
)
|
||||
obj
|
||||
)
|
||||
|
||||
;; A "state" defines functions that a process should run when it is in that state.
|
||||
;; the "code" function is executed by the main thread and can suspend/resume.
|
||||
;; the "trans" function is executed before code is resumed
|
||||
;; the "post" function is executed after code is suspended
|
||||
;; the "enter" function is executed when the process first transitions to the state
|
||||
;; the "exit" function is executed when the process exits the state (or dies)
|
||||
;; the "event" function is executed when the process receives an event.
|
||||
;; See gstate.gc for a lot more details on how this all works.
|
||||
;; This type is just a container to hold those functions.
|
||||
(deftype state (protect-frame)
|
||||
((code function :offset-assert 16)
|
||||
(trans (function none) :offset-assert 20)
|
||||
(post function :offset-assert 24)
|
||||
(enter function :offset-assert 28)
|
||||
(event (function process int symbol event-message-block object) :offset-assert 32)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x24
|
||||
:flag-assert #x900000024
|
||||
(:methods
|
||||
(new (symbol
|
||||
type
|
||||
symbol
|
||||
function
|
||||
(function none)
|
||||
function
|
||||
(function none)
|
||||
(function process int symbol event-message-block object))
|
||||
_type_ 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; data contained in an "event" sent from one process to another
|
||||
;; in jak2, the events may be queued and sent at a later time, so the block
|
||||
;; contains handles, to see if the to/from processes are still alive.
|
||||
(deftype event-message-block (structure)
|
||||
((to-handle handle :offset-assert 0) ;; who to send to
|
||||
(to (pointer process) :offset 0)
|
||||
(form-handle handle :offset-assert 8) ;; who is doing the sending
|
||||
(from (pointer process) :offset 8)
|
||||
(param uint64 6 :offset-assert 16) ;; the data being sent
|
||||
(message symbol :offset-assert 64) ;; the message name
|
||||
(num-params int32 :offset-assert 68)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x48
|
||||
:flag-assert #x900000048
|
||||
)
|
||||
|
||||
;; a queue of messages.
|
||||
(deftype event-message-block-array (inline-array-class)
|
||||
((data event-message-block :inline :dynamic :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 10
|
||||
:size-assert #x10
|
||||
:flag-assert #xa00000010
|
||||
(:methods
|
||||
(send-all! (_type_) none 9)
|
||||
)
|
||||
)
|
||||
(set! (-> event-message-block-array heap-base) (the-as uint 80))
|
||||
|
||||
;; the type returned by the C Kernel, contains the result of a SQL Query.
|
||||
(deftype sql-result (basic)
|
||||
((len int32 :offset-assert 4)
|
||||
(allocated-length uint32 :offset-assert 8)
|
||||
(error symbol :offset-assert 12)
|
||||
(data symbol :dynamic :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
(:methods
|
||||
(new (symbol type uint) _type_ 0)
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod new sql-result ((allocation symbol) (type-to-make type) (arg0 uint))
|
||||
"Allocate a new sql-result with enough room for arg0 entries in data."
|
||||
(let ((v0-0 (object-new allocation type-to-make (the-as int (+ (-> type-to-make size) (* arg0 4))))))
|
||||
(set! (-> v0-0 allocated-length) arg0)
|
||||
(set! (-> v0-0 error) 'error)
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod print sql-result ((obj sql-result))
|
||||
"Print a sql-result as an array of symbols."
|
||||
(format #t "#(~A" (-> obj error))
|
||||
(dotimes (s5-0 (-> obj len))
|
||||
(format #t " ~A" (-> obj data s5-0))
|
||||
)
|
||||
(format #t ")")
|
||||
obj
|
||||
)
|
||||
|
||||
;; the result that the C Kernel will send us.
|
||||
(define *sql-result* (the-as sql-result #f))
|
||||
|
||||
(defmacro defbehavior (name process-type bindings &rest body)
|
||||
"define a new behavior. This is simply a function where self is bound to the process register,
|
||||
which is assumed to have type process-type."
|
||||
(if (and
|
||||
(> (length body) 1) ;; more than one thing in function
|
||||
(string? (first body)) ;; first thing is a string
|
||||
)
|
||||
;; then it's a docstring and we ignore it.
|
||||
`(define ,name (lambda :name ,name :behavior ,process-type ,bindings ,@(cdr body)))
|
||||
;; otherwise don't ignore it.
|
||||
`(define ,name (lambda :name ,name :behavior ,process-type ,bindings ,@body))
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro process-stack-used (proc)
|
||||
;; get how much stack the top thread of a process has used.
|
||||
`(- (the int (-> ,proc top-thread stack-top))
|
||||
(the int (-> ,proc top-thread sp))
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro process-stack-size (proc)
|
||||
;; get how much stack the top thread of a process has
|
||||
`(-> ,proc top-thread stack-size)
|
||||
)
|
||||
|
||||
(defmacro process-heap-used (proc)
|
||||
;; get how much heap a process has used.
|
||||
`(- (-> ,proc allocated-length)
|
||||
(- (the int (-> ,proc heap-top))
|
||||
(the int (-> ,proc heap-cur))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro process-heap-size (proc)
|
||||
;; get how much heap a process has
|
||||
`(the int (-> ,proc allocated-length))
|
||||
)
|
||||
|
||||
(defmacro break ()
|
||||
`(/ 0 0)
|
||||
)
|
||||
|
||||
(defmacro with-pp (&rest body)
|
||||
"execute the body with pp bound to the current process register."
|
||||
`(rlet ((pp :reg r13 :reset-here #t :type process))
|
||||
,@body)
|
||||
)
|
||||
|
||||
(defmacro process-mask? (mask enum-value)
|
||||
`(!= 0 (logand ,mask (process-mask ,enum-value)))
|
||||
)
|
||||
|
||||
(defmacro process-mask-set! (mask &rest enum-value)
|
||||
;; sets the given bits in the process mask (with or)
|
||||
`(set! ,mask (logior ,mask (process-mask ,@enum-value)))
|
||||
)
|
||||
|
||||
(defmacro process-mask-clear! (mask &rest enum-value)
|
||||
;; sets the given bits in the process mask (with or)
|
||||
`(set! ,mask (logand ,mask (lognot (process-mask ,@enum-value))))
|
||||
)
|
||||
|
||||
(defmacro suspend ()
|
||||
"suspend the current process, to be resumed on the next frame."
|
||||
`(rlet ((pp :reg r13 :reset-here #t))
|
||||
;; debug check for stack overflow here, where we can easily print the process name.
|
||||
(#when (or KERNEL_DEBUG)
|
||||
(rlet ((sp :reg rsp :reset-here #t :type int)
|
||||
(off :reg r15 :type uint))
|
||||
(let* ((sp-goal (- sp off))
|
||||
(stack-top-goal (-> (the process pp) top-thread stack-top))
|
||||
(stack-used (&- stack-top-goal sp-goal))
|
||||
(stack-size (-> (the process pp) top-thread stack-size))
|
||||
)
|
||||
(when (> stack-used stack-size)
|
||||
(format 0 "ERROR: suspend called without enough stack in proc:~%~A~%Stack: ~D/~D~%" pp stack-used stack-size)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
;; set to the current thread
|
||||
(set! pp (-> (the process pp) top-thread))
|
||||
;; call the suspend hook (put nothing as the argument)
|
||||
((-> (the cpu-thread pp) suspend-hook) (the cpu-thread 0))
|
||||
;; the kernel will set pp (possibly to a new value, if we've been relocated) on resume.
|
||||
)
|
||||
)
|
||||
+2330
-2
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,508 @@
|
||||
;;-*-Lisp-*-
|
||||
;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; name: gstate.gc
|
||||
;; name in dgo: gstate
|
||||
;; dgos: KERNEL
|
||||
|
||||
#|
|
||||
Summary of state system:
|
||||
|
||||
A process can be put into a state, using enter-state, or the go macro.
|
||||
This will set up the process to run the appropriate handler functions defined by the state.
|
||||
The state handlers are:
|
||||
- enter : gets run before trans on the first time the state is used. Can be #f. Must return.
|
||||
- trans : gets run before code each time the code is run. Can be #f. Must return.
|
||||
- code : main thread. Can suspend. If it returns, the process dies
|
||||
- exit : gets run when leaving a state. must return.
|
||||
- event : not sure of the details here yet.
|
||||
|
||||
You can use "go" to change the state of a process. This causes the process main thread execution to be abandoned.
|
||||
If the main thread has exits/protects on the stack frame, they will be run first to clean up.
|
||||
|
||||
There are several ways to "go"
|
||||
- go during init: when a process is being initialized with run-function-in-process, you can "go".
|
||||
this causes the run-function-in-process to return immediately, and the next time the process is dispatched
|
||||
it will go into the other state. This will automatically set the process to waiting-to-run,
|
||||
and shrink the process heap, if appropriate
|
||||
|
||||
- go from outside the process. You can temporarily set pp to another process, and have that
|
||||
process go to another state. The actual go will occur the next time the process is scheduled.
|
||||
Use the go-process macro to do this.
|
||||
|
||||
- go from a non-main thread in the right process. You can do a go from a temporary thread, like trans or post.
|
||||
If you do it from post, the go returns and the rest of the post runs. If you do it from any other thread, the temporary thread
|
||||
is immediately abandonded. Like the previous two, it will defer the actual go until the next time the
|
||||
process runs.
|
||||
|
||||
- go from the main thread of the main process. This causes the (-> pp state) to change, the stack frames
|
||||
to be cleaned up, and the old state's exit to be called. It will reset the stack, then run the code.
|
||||
Unlike the others, this means you "go" immediately.
|
||||
|
||||
The compiler has two special hooks related to states: go-hook and define-state-hook.
|
||||
These take care of doing a go and a state definition and properly checking types.
|
||||
|
||||
The define-state-hook takes a state object and handlers and defines a global symbol
|
||||
with the appropriate state type.
|
||||
|
||||
The go-hook calls enter state and sets (-> proc next-state) for the given process.
|
||||
It type checks the arguments for the entry function.
|
||||
|
||||
|#
|
||||
|
||||
(defmacro go (next-state &rest args)
|
||||
"Change the state of the current process.
|
||||
This will only return if this is called within the post thread.
|
||||
Otherwise, execution stops here and the kernel will run the next state next time."
|
||||
`(with-pp
|
||||
(go-hook pp ,next-state ,@args)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro go-virtual (state-name &key (proc self) &rest args)
|
||||
"Same as go, but use a virtual state."
|
||||
`(go (method-of-object ,proc ,state-name) ,@args)
|
||||
)
|
||||
|
||||
(defmacro go-process (proc next-state &rest args)
|
||||
"Make another process go."
|
||||
`(with-pp
|
||||
(protect (pp)
|
||||
(set! pp ,proc)
|
||||
(go-hook pp ,next-state ,@args)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; run the given function in a process right now.
|
||||
;; will return to here when:
|
||||
;; - you return
|
||||
;; - you deactivate
|
||||
;; - you go
|
||||
;; - you throw to 'initialize
|
||||
(defmacro run-now-in-process (proc func &rest args)
|
||||
"Run a function in another process right now."
|
||||
`((the (function _varargs_ object) run-function-in-process)
|
||||
,proc ,func ,@args
|
||||
)
|
||||
)
|
||||
|
||||
;; sets the main thread of the given process to run the given thing.
|
||||
;; this resets the main thread stack back to the top
|
||||
(defmacro run-next-time-in-process (proc func &rest args)
|
||||
"Set up a process to run a function the next time it is scheduled."
|
||||
`((the (function _varargs_ object) set-to-run)
|
||||
(-> ,proc main-thread) ,func ,@args
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro process-spawn-function (proc-type func &key (from *default-dead-pool*) &key (to *default-pool*) &key (name #f) &key (stack-size #x4000) &key (stack *scratch-memory-top*) &rest args)
|
||||
"Start a new process that runs a function on its main thread.
|
||||
Returns a pointer to the new process (or #f? on error)."
|
||||
|
||||
(with-gensyms (new-proc)
|
||||
`(let ((,new-proc (the-as ,proc-type (get-process ,from ,proc-type ,stack-size))))
|
||||
(when ,new-proc
|
||||
((method-of-type ,proc-type activate) ,new-proc ,to ,(if name name (symbol->string proc-type)) ,stack)
|
||||
(run-next-time-in-process ,new-proc ,func ,@args)
|
||||
(the (pointer ,proc-type) (-> ,new-proc ppointer))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro process-spawn (proc-type &key (init #f) &key (from *default-dead-pool*) &key (to *default-pool*) &key (name #f) &key (stack-size #x4000) &key (stack *scratch-memory-top*) &rest args)
|
||||
"Start a new process and run an init function on it.
|
||||
Returns a pointer to the new process, or #f (or is it 0?) if something goes wrong."
|
||||
|
||||
(with-gensyms (new-proc)
|
||||
`(let ((,new-proc (the-as ,proc-type (get-process ,from ,proc-type ,stack-size))))
|
||||
(when ,new-proc
|
||||
((method-of-type ,proc-type activate) ,new-proc ,to ,(if name name `(quote ,proc-type)) ,stack)
|
||||
(run-now-in-process ,new-proc ,(if init init (string->symbol (fmt #f "{}-init-by-other" proc-type))) ,@args)
|
||||
(the (pointer ,proc-type) (-> ,new-proc ppointer))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; display a listing of active processes.
|
||||
(defmacro ps (&key (detail #f))
|
||||
`(inspect-process-tree *active-pool* 0 0 ,detail)
|
||||
)
|
||||
|
||||
;; use a compile-time list to keep track of the type of an anonymous behavior.
|
||||
(seval (define *defstate-type-stack* '()))
|
||||
(desfun def-state-check-behavior (beh-form beh-type)
|
||||
"check if code block is an anonymous behavior. needed for anonymous behaviors on defstate."
|
||||
|
||||
(when (and (pair? beh-form) (eq? (first beh-form) 'behavior))
|
||||
(push! *defstate-type-stack* beh-type)
|
||||
)
|
||||
)
|
||||
(defmacro clear-def-state-stack ()
|
||||
(set! *defstate-type-stack* '())
|
||||
`(none)
|
||||
)
|
||||
;; *no-state* is just used for the compiler to know whether a handler was actually set or not
|
||||
(defmacro defstate (state-name parents
|
||||
&key (virtual #f)
|
||||
&key (event *no-state*)
|
||||
&key (enter *no-state*)
|
||||
&key (trans *no-state*)
|
||||
&key (exit *no-state*)
|
||||
&key (code *no-state*)
|
||||
&key (post *no-state*)
|
||||
)
|
||||
"Define a new state!"
|
||||
|
||||
(with-gensyms (new-state)
|
||||
(let ((defstate-type (first parents)))
|
||||
(when (not (null? *defstate-type-stack*))
|
||||
(fmt #t "*defstate-type-stack* leaked! An error probably happened in a previous defstate. stack is: {}"
|
||||
*defstate-type-stack*)
|
||||
)
|
||||
(set! *defstate-type-stack* '())
|
||||
;; check for default handlers
|
||||
(let ((default-handlers (assoc defstate-type *default-state-handlers*)))
|
||||
(when (not (null? default-handlers))
|
||||
;;(fmt #t "found default-handlers for {}: {}\n" defstate-type default-handlers)
|
||||
;; event
|
||||
(set! default-handlers (cadr default-handlers))
|
||||
(when (and (eq? event '*no-state*) (car default-handlers))
|
||||
(set! event (car default-handlers)))
|
||||
;; enter
|
||||
(set! default-handlers (cdr default-handlers))
|
||||
(when (and (eq? enter '*no-state*) (car default-handlers))
|
||||
(set! enter (car default-handlers)))
|
||||
;; trans
|
||||
(set! default-handlers (cdr default-handlers))
|
||||
(when (and (eq? trans '*no-state*) (car default-handlers))
|
||||
(set! trans (car default-handlers)))
|
||||
;; exit
|
||||
(set! default-handlers (cdr default-handlers))
|
||||
(when (and (eq? exit '*no-state*) (car default-handlers))
|
||||
(set! exit (car default-handlers)))
|
||||
;; code
|
||||
(set! default-handlers (cdr default-handlers))
|
||||
(when (and (eq? code '*no-state*) (car default-handlers))
|
||||
(set! code (car default-handlers)))
|
||||
;; post
|
||||
(set! default-handlers (cdr default-handlers))
|
||||
(when (and (eq? post '*no-state*) (car default-handlers))
|
||||
(set! post (car default-handlers)))
|
||||
|
||||
(set! default-handlers (cdr default-handlers))
|
||||
)
|
||||
)
|
||||
(def-state-check-behavior event defstate-type)
|
||||
(def-state-check-behavior enter defstate-type)
|
||||
(def-state-check-behavior trans defstate-type)
|
||||
(def-state-check-behavior exit defstate-type)
|
||||
(def-state-check-behavior code defstate-type)
|
||||
(def-state-check-behavior post defstate-type)
|
||||
`(let ((,new-state (new 'static 'state
|
||||
:name (quote ,state-name)
|
||||
:next #f
|
||||
:exit #f
|
||||
:code #f
|
||||
:trans #f
|
||||
:post #f
|
||||
:enter #f
|
||||
:event #f
|
||||
)
|
||||
))
|
||||
;; the compiler will set the fields of the given state and define the symbol.
|
||||
;; This way it can check the individual function types, make sure they make sense, and create
|
||||
;; a state with the appropriate type.
|
||||
,(if virtual
|
||||
`(define-virtual-state-hook ,state-name ,defstate-type ,new-state ,(eq? virtual 'override) :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
`(define-state-hook ,state-name ,defstate-type ,new-state :event ,event :enter ,enter :trans ,trans :exit ,exit :code ,code :post ,post)
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro behavior (bindings &rest body)
|
||||
"Define an anonymous behavior for a process state. This may only be used inside a defstate!"
|
||||
|
||||
(let ((behavior-type (first *defstate-type-stack*)))
|
||||
(pop! *defstate-type-stack*)
|
||||
`(lambda :behavior ,behavior-type ,bindings ,@body)
|
||||
)
|
||||
)
|
||||
|
||||
;; set the default handler functions for a process's state handlers
|
||||
(seval (define *default-state-handlers* '()))
|
||||
(defmacro defstatehandler (proc
|
||||
&key (event #f)
|
||||
&key (enter #f)
|
||||
&key (trans #f)
|
||||
&key (exit #f)
|
||||
&key (code #f)
|
||||
&key (post #f))
|
||||
(let ((old (assoc proc *default-state-handlers*))
|
||||
(new (list proc (list event enter trans exit code post))))
|
||||
(if (null? old)
|
||||
(append!! *default-state-handlers* new) ;; add new set of default handlers
|
||||
(dolist (hnd *default-state-handlers*) ;; replace old handlers with new ones
|
||||
(when (eq? (car hnd) old)
|
||||
(set-car! hnd new)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
`(none)
|
||||
)
|
||||
|
||||
(defmethod new state
|
||||
((allocation symbol)
|
||||
(type-to-make type)
|
||||
(name symbol)
|
||||
(code function)
|
||||
(trans (function none))
|
||||
(enter function)
|
||||
(exit (function none))
|
||||
(event (function process int symbol event-message-block object)))
|
||||
"Allocate a new state. It seems like this isn't really used much and most states are
|
||||
statically allocated and as a result don't have the constructor called."
|
||||
(let ((obj (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
|
||||
(set! (-> obj name) name)
|
||||
(set! (-> obj next) #f)
|
||||
(set! (-> obj exit) exit)
|
||||
(set! (-> obj code) code)
|
||||
(set! (-> obj trans) trans)
|
||||
(set! (-> obj post) #f)
|
||||
(set! (-> obj enter) enter)
|
||||
(set! (-> obj event) event)
|
||||
obj
|
||||
)
|
||||
)
|
||||
|
||||
(defun inherit-state ((child state) (parent state))
|
||||
"Copy handler functions from parent to child"
|
||||
(cond
|
||||
((nonzero? parent)
|
||||
(set! (-> child exit) (-> parent exit))
|
||||
(set! (-> child code) (-> parent code))
|
||||
(set! (-> child trans) (-> parent trans))
|
||||
(set! (-> child post) (-> parent post))
|
||||
(set! (-> child enter) (-> parent enter))
|
||||
(set! (-> child event) (-> parent event))
|
||||
)
|
||||
(else
|
||||
;; Note: this is added to let us defstate on a child before the parent.
|
||||
;; The child won't be usable like this, but it will prevent a crash.
|
||||
(format 0 "[STATE ERROR] inherit-state got a null parent state. Child is ~A~%" (-> child name))
|
||||
)
|
||||
)
|
||||
|
||||
child
|
||||
)
|
||||
|
||||
(defmethod print state ((obj state))
|
||||
"Print a state."
|
||||
(format '#t "#<~A ~A @ #x~X>" (-> obj type) (-> obj name) obj)
|
||||
obj
|
||||
)
|
||||
|
||||
(define-extern enter-state (function object object object object object object object))
|
||||
(defun enter-state (arg0 arg1 arg2 arg3 arg4 arg5)
|
||||
"Make the process stored in pp enter the state in pp next-state"
|
||||
(with-pp
|
||||
;; unsleep us
|
||||
(process-mask-clear! (-> pp mask) sleep sleep-code)
|
||||
;; mark as going
|
||||
(process-mask-set! (-> pp mask) going)
|
||||
(cond
|
||||
((= (-> pp status) 'initialize)
|
||||
;; did a go during initialize.
|
||||
;; remove the old trans hook, if there was one
|
||||
(set! (-> pp trans-hook) #f)
|
||||
;; set us up to run enter-state again, the next time we're scheduled.
|
||||
(set-to-run (-> pp main-thread) enter-state arg0 arg1 arg2 arg3 arg4 arg5)
|
||||
;; tell the kernel that we did a go during init
|
||||
(set! (-> pp status) 'initialize-go)
|
||||
;; abandon this thread, go back to what initialized us!
|
||||
(throw 'initialize #t)
|
||||
#t
|
||||
)
|
||||
((!= (-> *kernel-context* current-process) pp)
|
||||
;; we aren't actually in process pp right now.
|
||||
;; so set us up to go in the next run
|
||||
(let ((status-backup (-> pp status)))
|
||||
(set! (-> pp trans-hook) #f)
|
||||
;; will set waiting-to-run
|
||||
(set-to-run (-> pp main-thread) enter-state arg0 arg1 arg2 arg3 arg4 arg5)
|
||||
;; restore the old status.
|
||||
(set! (-> pp status) status-backup)
|
||||
#t
|
||||
)
|
||||
)
|
||||
((= (-> pp main-thread) (-> pp top-thread))
|
||||
;; we are in the right process, and in the main thread!
|
||||
;; we will do a nonlocal control transfer to the new state's code.
|
||||
;; the new state can then suspend and get back to the kernel dispatcher lambda
|
||||
;; like normal.
|
||||
|
||||
;; change state!
|
||||
(set! (-> pp state) (-> pp next-state))
|
||||
|
||||
;; do exits
|
||||
(let ((frame (-> pp stack-frame-top)))
|
||||
(while frame
|
||||
(case (-> frame type)
|
||||
((protect-frame state)
|
||||
((-> (the-as protect-frame frame) exit))
|
||||
)
|
||||
)
|
||||
(set! frame (-> frame next))
|
||||
)
|
||||
)
|
||||
|
||||
;; done with going, clear the mask
|
||||
(process-mask-clear! (-> pp mask) going)
|
||||
|
||||
;; now, update the process:
|
||||
(let ((new-state (-> pp state)))
|
||||
;; event hook from the current state
|
||||
(set! (-> pp event-hook) (-> new-state event))
|
||||
;; if we have an exit, push it onto the stack frame
|
||||
;; and also blow away the old stack frame
|
||||
(if (-> new-state exit)
|
||||
(set! (-> pp stack-frame-top) new-state)
|
||||
(set! (-> pp stack-frame-top) #f)
|
||||
)
|
||||
(set! (-> pp post-hook) (-> new-state post))
|
||||
(set! (-> pp trans-hook) (-> new-state trans))
|
||||
|
||||
|
||||
;; start up the new state. First run the enter function
|
||||
(let ((enter-func (-> new-state enter)))
|
||||
(if enter-func
|
||||
((the (function _varargs_ none) enter-func) arg0 arg1 arg2 arg3 arg4 arg5)
|
||||
)
|
||||
)
|
||||
|
||||
;; run the trans function before the code.
|
||||
(let ((trans-func (-> new-state trans)))
|
||||
(if trans-func
|
||||
(trans-func)
|
||||
)
|
||||
)
|
||||
;; now we run the code, but in a tricky way.
|
||||
;; we need to:
|
||||
;; - make sure that when this code returns, we do a deactivate
|
||||
;; - reset the stack to the top, so we can't just call the code.
|
||||
(rlet ((temp)
|
||||
(func)
|
||||
(sp :reg rsp :type uint)
|
||||
(off :reg r15 :type uint)
|
||||
(carg0 :reg rdi)
|
||||
(carg1 :reg rsi)
|
||||
(carg2 :reg rdx)
|
||||
(carg3 :reg rcx))
|
||||
;; prepare args
|
||||
;; compiler will likely have these on the stack, we need to get them in regs
|
||||
;; before messing with the stack.
|
||||
(.mov carg0 arg0)
|
||||
(.mov carg1 arg1)
|
||||
(.mov carg2 arg2)
|
||||
(.mov carg3 arg3)
|
||||
|
||||
;; get the main code as an x86-64 pointer
|
||||
(.mov func (-> new-state code))
|
||||
(.add func off)
|
||||
;; reset the stack (scary)
|
||||
(.mov sp (-> pp main-thread stack-top))
|
||||
(.add sp off)
|
||||
;; push the return trampoline for when code returns.
|
||||
(.mov temp return-from-thread-dead) ;; will deactivate
|
||||
(.add temp off)
|
||||
(.push temp)
|
||||
;; and call!
|
||||
(.jr func)
|
||||
;; stupid hack so the compiler doesn't throw away these registers.
|
||||
(.add carg0 carg1)
|
||||
(.add carg2 carg3)
|
||||
#f ;; can't get here
|
||||
)
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; not in the main-thread.
|
||||
;; so we set up the main thread to try again.
|
||||
(set! (-> pp trans-hook) #f)
|
||||
(set-to-run (-> pp main-thread)
|
||||
enter-state arg0 arg1 arg2 arg3 arg4 arg5)
|
||||
(when (!= (-> pp top-thread name) 'post)
|
||||
;; abandon this one too.
|
||||
;; NOTE - this is different from GOAL.
|
||||
;; GOAL installs this as the return address for this function and returns normally.
|
||||
;; but we don't because I don't have an easy way to find where to stick this.
|
||||
;; I can't see how this makes a difference, as all non-main threads seem
|
||||
;; temporary, but if this turns out to be false, we will need to change this.
|
||||
(rlet ((temp)
|
||||
(off :reg r15 :type uint :reset-here #t))
|
||||
(.mov temp return-from-thread) ;; could probably just call this...
|
||||
(.add temp off)
|
||||
(.push temp)
|
||||
(.ret)
|
||||
#f ;; can't get here
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(kmemopen global "event-queue")
|
||||
|
||||
(let ((v1-3 (new 'global 'event-message-block-array 64)))
|
||||
(set! (-> v1-3 length) 0)
|
||||
(define *event-queue* v1-3)
|
||||
)
|
||||
|
||||
(kmemclose)
|
||||
|
||||
(defun send-event-function ((arg0 process-tree) (arg1 event-message-block))
|
||||
(with-pp
|
||||
(when (and arg0 (!= (-> arg0 type) process-tree) (-> (the-as process arg0) event-hook) (-> arg1 from))
|
||||
(let ((gp-0 pp))
|
||||
(set! pp (the-as process arg0))
|
||||
(let ((v0-0 ((-> (the-as process arg0) event-hook) (-> arg1 from 0) (-> arg1 num-params) (-> arg1 message) arg1)))
|
||||
(set! pp gp-0)
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod send-all! event-message-block-array ((obj event-message-block-array))
|
||||
(dotimes (s5-0 (-> obj length))
|
||||
(let* ((a1-0 (-> obj data s5-0))
|
||||
(a0-2 (handle->process (-> a1-0 to-handle)))
|
||||
)
|
||||
(if (and a0-2 (handle->process (-> a1-0 form-handle)))
|
||||
(send-event-function a0-2 a1-0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(set! (-> obj length) 0)
|
||||
0
|
||||
(none)
|
||||
)
|
||||
|
||||
(defun looping-code ()
|
||||
(until #f
|
||||
(suspend)
|
||||
)
|
||||
#f
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,3 +5,10 @@
|
||||
;; name in dgo: gstring-h
|
||||
;; dgos: KERNEL
|
||||
|
||||
(define-extern *string-tmp-str* string)
|
||||
(define-extern *temp-string* string)
|
||||
(define-extern *stdcon0* string)
|
||||
(define-extern *stdcon1* string)
|
||||
(define-extern *stdcon* string)
|
||||
(define-extern *debug-draw-pauseable* symbol)
|
||||
(define-extern string= (function string string symbol))
|
||||
|
||||
@@ -5,3 +5,708 @@
|
||||
;; name in dgo: gstring
|
||||
;; dgos: KERNEL
|
||||
|
||||
(defmethod length string ((obj string))
|
||||
(let ((v1-0 (-> obj data)))
|
||||
(while (nonzero? (-> v1-0 0))
|
||||
(nop!)
|
||||
(nop!)
|
||||
(nop!)
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
)
|
||||
(&- v1-0 (the-as uint (-> obj data)))
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod asize-of string ((obj string))
|
||||
(+ (-> obj allocated-length) 1 (-> string size))
|
||||
)
|
||||
|
||||
(defun copy-string<-string ((arg0 string) (arg1 string))
|
||||
(let ((v1-0 (-> arg0 data)))
|
||||
(let ((a1-1 (-> arg1 data)))
|
||||
(while (nonzero? (-> a1-1 0))
|
||||
(set! (-> v1-0 0) (-> a1-1 0))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
(set! a1-1 (&-> a1-1 1))
|
||||
)
|
||||
)
|
||||
(set! (-> v1-0 0) (the-as uint 0))
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
(defmethod new string ((allocation symbol) (type-to-make type) (arg0 int) (arg1 string))
|
||||
(cond
|
||||
(arg1
|
||||
(let* ((s2-1 (max (length arg1) arg0))
|
||||
(a0-4 (object-new allocation type-to-make (+ s2-1 1 (-> type-to-make size))))
|
||||
)
|
||||
(set! (-> a0-4 allocated-length) s2-1)
|
||||
(copy-string<-string a0-4 arg1)
|
||||
)
|
||||
)
|
||||
(else
|
||||
(let ((v0-2 (object-new allocation type-to-make (+ arg0 1 (-> type-to-make size)))))
|
||||
(set! (-> v0-2 allocated-length) arg0)
|
||||
v0-2
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun string= ((arg0 string) (arg1 string))
|
||||
(let ((a2-0 (-> arg0 data))
|
||||
(v1-0 (-> arg1 data))
|
||||
)
|
||||
(if (or (zero? arg0) (zero? arg1))
|
||||
(return #f)
|
||||
)
|
||||
(while (and (nonzero? (-> a2-0 0)) (nonzero? (-> v1-0 0)))
|
||||
(if (!= (-> a2-0 0) (-> v1-0 0))
|
||||
(return #f)
|
||||
)
|
||||
(set! a2-0 (&-> a2-0 1))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
)
|
||||
(and (zero? (-> a2-0 0)) (zero? (-> v1-0 0)))
|
||||
)
|
||||
)
|
||||
|
||||
(defun string-prefix= ((arg0 string) (arg1 string))
|
||||
(let ((v1-0 (-> arg0 data)))
|
||||
(let ((a2-0 (-> arg1 data)))
|
||||
(if (or (zero? arg0) (zero? arg1))
|
||||
(return #f)
|
||||
)
|
||||
(while (and (nonzero? (-> v1-0 0)) (nonzero? (-> a2-0 0)))
|
||||
(if (!= (-> v1-0 0) (-> a2-0 0))
|
||||
(return #f)
|
||||
)
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
(set! a2-0 (&-> a2-0 1))
|
||||
)
|
||||
)
|
||||
(zero? (-> v1-0 0))
|
||||
)
|
||||
)
|
||||
|
||||
(defun charp-prefix= ((arg0 (pointer uint8)) (arg1 (pointer uint8)))
|
||||
(while (and (nonzero? (-> arg0 0)) (nonzero? (-> arg1 0)))
|
||||
(if (!= (-> arg0 0) (-> arg1 0))
|
||||
(return #f)
|
||||
)
|
||||
(set! arg0 (&-> arg0 1))
|
||||
(set! arg1 (&-> arg1 1))
|
||||
)
|
||||
(zero? (-> arg0 0))
|
||||
)
|
||||
|
||||
(defun string-suffix= ((arg0 string) (arg1 string))
|
||||
(let ((s5-0 (-> arg0 data))
|
||||
(gp-0 (-> arg1 data))
|
||||
)
|
||||
(if (or (zero? arg0) (zero? arg1))
|
||||
(return #f)
|
||||
)
|
||||
(let ((s4-0 (length arg0))
|
||||
(v1-5 (length arg1))
|
||||
)
|
||||
(if (< s4-0 v1-5)
|
||||
(return #f)
|
||||
)
|
||||
(let ((v1-7 (&+ s5-0 (- s4-0 v1-5))))
|
||||
(while (and (nonzero? (-> v1-7 0)) (nonzero? (-> gp-0 0)))
|
||||
(if (!= (-> v1-7 0) (-> gp-0 0))
|
||||
(return #f)
|
||||
)
|
||||
(set! v1-7 (&-> v1-7 1))
|
||||
(set! gp-0 (&-> gp-0 1))
|
||||
)
|
||||
(zero? (-> v1-7 0))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun string-position ((arg0 string) (arg1 string))
|
||||
(let ((s5-0 0)
|
||||
(s4-0 (-> arg1 data))
|
||||
)
|
||||
(while (nonzero? (-> s4-0 0))
|
||||
(if (charp-prefix= (-> arg0 data) s4-0)
|
||||
(return s5-0)
|
||||
)
|
||||
(+! s5-0 1)
|
||||
(set! s4-0 (&-> s4-0 1))
|
||||
)
|
||||
)
|
||||
-1
|
||||
)
|
||||
|
||||
(defun string-charp= ((arg0 string) (arg1 (pointer uint8)))
|
||||
(let ((v1-0 (-> arg0 data)))
|
||||
(while (and (nonzero? (-> v1-0 0)) (nonzero? (-> arg1 0)))
|
||||
(if (!= (-> v1-0 0) (-> arg1 0))
|
||||
(return #f)
|
||||
)
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
(set! arg1 (&-> arg1 1))
|
||||
)
|
||||
(and (zero? (-> v1-0 0)) (zero? (-> arg1 0)))
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function name=
|
||||
;; ERROR: function was not converted to expressions. Cannot decompile.
|
||||
|
||||
|
||||
(defun copyn-string<-charp ((arg0 string) (arg1 (pointer uint8)) (arg2 int))
|
||||
(let ((v1-0 (-> arg0 data)))
|
||||
(dotimes (a3-0 arg2)
|
||||
(set! (-> v1-0 0) (-> arg1 0))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
(set! arg1 (&-> arg1 1))
|
||||
)
|
||||
(set! (-> v1-0 0) (the-as uint 0))
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun string<-charp ((arg0 string) (arg1 (pointer uint8)))
|
||||
(let ((v1-0 (-> arg0 data)))
|
||||
(while (nonzero? (-> arg1 0))
|
||||
(set! (-> v1-0 0) (-> arg1 0))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
(set! arg1 (&-> arg1 1))
|
||||
)
|
||||
(set! (-> v1-0 0) (the-as uint 0))
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun charp<-string ((arg0 (pointer uint8)) (arg1 string))
|
||||
(let ((v1-0 (-> arg1 data)))
|
||||
(while (nonzero? (-> v1-0 0))
|
||||
(set! (-> arg0 0) (-> v1-0 0))
|
||||
(set! arg0 (&-> arg0 1))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
)
|
||||
)
|
||||
(set! (-> arg0 0) (the-as uint 0))
|
||||
0
|
||||
)
|
||||
|
||||
(defun copyn-charp<-string ((arg0 (pointer uint8)) (arg1 string) (arg2 int))
|
||||
(let ((v1-0 (-> arg1 data)))
|
||||
(while (and (nonzero? (-> v1-0 0)) (< 1 arg2))
|
||||
(set! (-> arg0 0) (-> v1-0 0))
|
||||
(set! arg0 (&-> arg0 1))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
(set! arg2 (+ arg2 -1))
|
||||
)
|
||||
)
|
||||
(while (> arg2 0)
|
||||
(set! (-> arg0 0) (the-as uint 0))
|
||||
(set! arg0 (&-> arg0 1))
|
||||
(set! arg2 (+ arg2 -1))
|
||||
)
|
||||
0
|
||||
(none)
|
||||
)
|
||||
|
||||
(defun copy-charp<-charp ((arg0 (pointer uint8)) (arg1 (pointer uint8)))
|
||||
(while (nonzero? (-> arg1 0))
|
||||
(set! (-> arg0 0) (-> arg1 0))
|
||||
(set! arg0 (&-> arg0 1))
|
||||
(set! arg1 (&-> arg1 1))
|
||||
)
|
||||
(set! (-> arg0 0) (the-as uint 0))
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun cat-string<-string ((arg0 string) (arg1 string))
|
||||
(let ((v1-0 (-> arg0 data)))
|
||||
(let ((a1-1 (-> arg1 data)))
|
||||
(while (nonzero? (-> v1-0 0))
|
||||
(nop!)
|
||||
(nop!)
|
||||
(nop!)
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
)
|
||||
(while (nonzero? (-> a1-1 0))
|
||||
(set! (-> v1-0 0) (-> a1-1 0))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
(set! a1-1 (&-> a1-1 1))
|
||||
)
|
||||
)
|
||||
(set! (-> v1-0 0) (the-as uint 0))
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun catn-string<-charp ((arg0 string) (arg1 (pointer uint8)) (arg2 int))
|
||||
(let ((v1-0 (-> arg0 data)))
|
||||
(while (nonzero? (-> v1-0 0))
|
||||
(nop!)
|
||||
(nop!)
|
||||
(nop!)
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
)
|
||||
(dotimes (a3-2 arg2)
|
||||
(set! (-> v1-0 0) (-> arg1 0))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
(set! arg1 (&-> arg1 1))
|
||||
)
|
||||
(set! (-> v1-0 0) (the-as uint 0))
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun cat-string<-string_to_charp ((arg0 string) (arg1 string) (arg2 (pointer uint8)))
|
||||
(let ((v1-0 (-> arg1 data))
|
||||
(v0-0 (-> arg0 data))
|
||||
)
|
||||
(while (nonzero? (-> v0-0 0))
|
||||
(nop!)
|
||||
(nop!)
|
||||
(nop!)
|
||||
(set! v0-0 (&-> v0-0 1))
|
||||
)
|
||||
(while (and (>= (the-as int arg2) (the-as int v1-0)) (nonzero? (-> v1-0 0)))
|
||||
(set! (-> v0-0 0) (-> v1-0 0))
|
||||
(set! v0-0 (&-> v0-0 1))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
)
|
||||
(set! (-> v0-0 0) (the-as uint 0))
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
|
||||
(defun append-character-to-string ((arg0 string) (arg1 uint8))
|
||||
(let ((v1-0 (-> arg0 data)))
|
||||
(while (nonzero? (-> v1-0 0))
|
||||
(nop!)
|
||||
(nop!)
|
||||
(nop!)
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
)
|
||||
(set! (-> v1-0 0) (the-as uint arg1))
|
||||
(set! (-> v1-0 1) (the-as uint 0))
|
||||
)
|
||||
0
|
||||
0
|
||||
)
|
||||
|
||||
(defun charp-basename ((arg0 (pointer uint8)))
|
||||
(let ((v1-0 arg0))
|
||||
(while (nonzero? (-> v1-0 0))
|
||||
(set! v1-0 (&-> v1-0 1))
|
||||
)
|
||||
(while (< (the-as int arg0) (the-as int v1-0))
|
||||
(set! v1-0 (&-> v1-0 -1))
|
||||
(if (or (= (-> v1-0 0) 47) (= (-> v1-0 0) 92))
|
||||
(return (&-> v1-0 1))
|
||||
)
|
||||
)
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun clear ((arg0 string))
|
||||
(set! (-> arg0 data 0) (the-as uint 0))
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun string<? ((arg0 string) (arg1 string))
|
||||
(let ((s4-1 (min (length arg0) (length arg1))))
|
||||
(dotimes (v1-4 s4-1)
|
||||
(cond
|
||||
((< (-> arg0 data v1-4) (-> arg1 data v1-4))
|
||||
(return #t)
|
||||
)
|
||||
((< (-> arg1 data v1-4) (-> arg0 data v1-4))
|
||||
(return #f)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
#f
|
||||
)
|
||||
|
||||
(defun string>? ((arg0 string) (arg1 string))
|
||||
(let ((s4-1 (min (length arg0) (length arg1))))
|
||||
(dotimes (v1-4 s4-1)
|
||||
(cond
|
||||
((< (-> arg0 data v1-4) (-> arg1 data v1-4))
|
||||
(return #f)
|
||||
)
|
||||
((< (-> arg1 data v1-4) (-> arg0 data v1-4))
|
||||
(return #t)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
#f
|
||||
)
|
||||
|
||||
(defun string<=? ((arg0 string) (arg1 string))
|
||||
(let ((s4-1 (min (length arg0) (length arg1))))
|
||||
(dotimes (v1-4 s4-1)
|
||||
(cond
|
||||
((< (-> arg0 data v1-4) (-> arg1 data v1-4))
|
||||
(return #t)
|
||||
)
|
||||
((< (-> arg1 data v1-4) (-> arg0 data v1-4))
|
||||
(return #f)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
#t
|
||||
)
|
||||
|
||||
(defun string>=? ((arg0 string) (arg1 string))
|
||||
(let ((s4-1 (min (length arg0) (length arg1))))
|
||||
(dotimes (v1-4 s4-1)
|
||||
(cond
|
||||
((< (-> arg0 data v1-4) (-> arg1 data v1-4))
|
||||
(return #f)
|
||||
)
|
||||
((< (-> arg1 data v1-4) (-> arg0 data v1-4))
|
||||
(return #t)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
#t
|
||||
)
|
||||
|
||||
(define *string-tmp-str* (new 'global 'string 128 (the-as string #f)))
|
||||
|
||||
(defun string-skip-to-char ((arg0 (pointer uint8)) (arg1 uint))
|
||||
(while (and (nonzero? (-> arg0 0)) (!= (-> arg0 0) arg1))
|
||||
(set! arg0 (&-> arg0 1))
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun string-cat-to-last-char ((arg0 string) (arg1 string) (arg2 uint))
|
||||
(let ((s4-0 (&-> (the-as (pointer uint8) arg1) 3)))
|
||||
(let ((v1-0 (string-skip-to-char (-> arg1 data) arg2)))
|
||||
(when (= (-> v1-0 0) arg2)
|
||||
(until (!= (-> v1-0 0) arg2)
|
||||
(set! s4-0 v1-0)
|
||||
(set! v1-0 (string-skip-to-char (&-> v1-0 1) arg2))
|
||||
)
|
||||
)
|
||||
)
|
||||
(cat-string<-string_to_charp arg0 arg1 s4-0)
|
||||
)
|
||||
)
|
||||
|
||||
(defun string-skip-whitespace ((arg0 (pointer uint8)))
|
||||
(while (and (nonzero? (-> arg0 0)) (or (= (-> arg0 0) 32) (= (-> arg0 0) 9) (= (-> arg0 0) 13) (= (-> arg0 0) 10)))
|
||||
(set! arg0 (&-> arg0 1))
|
||||
)
|
||||
arg0
|
||||
)
|
||||
|
||||
(defun string-suck-up! ((arg0 string) (arg1 (pointer uint8)))
|
||||
(when (!= arg1 (-> arg0 data))
|
||||
(let ((v1-2 (-> arg0 data)))
|
||||
(while (nonzero? (-> arg1 0))
|
||||
(set! (-> v1-2 0) (-> arg1 0))
|
||||
(set! v1-2 (&-> v1-2 1))
|
||||
(set! arg1 (&-> arg1 1))
|
||||
)
|
||||
(set! (-> v1-2 0) (the-as uint 0))
|
||||
)
|
||||
0
|
||||
)
|
||||
#f
|
||||
)
|
||||
|
||||
(defun string-strip-leading-whitespace! ((arg0 string))
|
||||
(let ((a1-0 (string-skip-whitespace (-> arg0 data))))
|
||||
(string-suck-up! arg0 a1-0)
|
||||
)
|
||||
#f
|
||||
)
|
||||
|
||||
(defun string-strip-trailing-whitespace! ((arg0 string))
|
||||
(when (nonzero? (length arg0))
|
||||
(let ((v1-6 (&+ (-> arg0 data) (+ (length arg0) -1))))
|
||||
(while (and (>= (the-as int v1-6) (the-as int (-> arg0 data)))
|
||||
(or (= (-> v1-6 0) 32) (= (-> v1-6 0) 9) (= (-> v1-6 0) 13) (= (-> v1-6 0) 10))
|
||||
)
|
||||
(set! v1-6 (&-> v1-6 -1))
|
||||
)
|
||||
(set! (-> v1-6 1) (the-as uint 0))
|
||||
)
|
||||
0
|
||||
)
|
||||
#f
|
||||
)
|
||||
|
||||
(defun string-strip-whitespace! ((arg0 string))
|
||||
(string-strip-trailing-whitespace! arg0)
|
||||
(string-strip-leading-whitespace! arg0)
|
||||
#f
|
||||
)
|
||||
|
||||
(defun string-upcase ((arg0 string) (arg1 string))
|
||||
(let* ((a0-1 (-> arg0 data))
|
||||
(a3-0 (-> a0-1 0))
|
||||
(a2-0 1)
|
||||
(v1-0 0)
|
||||
)
|
||||
(while (nonzero? a3-0)
|
||||
(if (and (>= a3-0 (the-as uint 97)) (>= (the-as uint 122) a3-0))
|
||||
(+! a3-0 -32)
|
||||
)
|
||||
(set! (-> arg1 data v1-0) a3-0)
|
||||
(set! a3-0 (-> a0-1 a2-0))
|
||||
(+! a2-0 1)
|
||||
(+! v1-0 1)
|
||||
)
|
||||
(set! (-> arg1 data v1-0) (the-as uint 0))
|
||||
)
|
||||
0
|
||||
(none)
|
||||
)
|
||||
|
||||
(defun string-get-arg!! ((arg0 string) (arg1 string))
|
||||
(let ((s4-0 (string-skip-whitespace (-> arg1 data))))
|
||||
(cond
|
||||
((= (-> s4-0 0) 34)
|
||||
(let ((s4-1 (&-> s4-0 1)))
|
||||
(let ((v1-3 s4-1))
|
||||
(while (and (nonzero? (-> s4-1 0)) (!= (-> s4-1 0) 34))
|
||||
(set! s4-1 (&-> s4-1 1))
|
||||
)
|
||||
(copyn-string<-charp arg0 v1-3 (&- s4-1 (the-as uint v1-3)))
|
||||
)
|
||||
(if (= (-> s4-1 0) 34)
|
||||
(set! s4-1 (&-> s4-1 1))
|
||||
)
|
||||
(let ((a1-3 (string-skip-whitespace s4-1)))
|
||||
(string-suck-up! arg1 a1-3)
|
||||
)
|
||||
)
|
||||
(return #t)
|
||||
)
|
||||
((nonzero? (-> s4-0 0))
|
||||
(let ((v1-11 s4-0))
|
||||
(while (and (nonzero? (-> s4-0 0)) (!= (-> s4-0 0) 32) (!= (-> s4-0 0) 9) (!= (-> s4-0 0) 13) (!= (-> s4-0 0) 10))
|
||||
(set! s4-0 (&-> s4-0 1))
|
||||
)
|
||||
(copyn-string<-charp arg0 v1-11 (&- s4-0 (the-as uint v1-11)))
|
||||
)
|
||||
(let ((a1-9 (string-skip-whitespace s4-0)))
|
||||
(string-suck-up! arg1 a1-9)
|
||||
)
|
||||
(return #t)
|
||||
)
|
||||
)
|
||||
)
|
||||
#f
|
||||
)
|
||||
|
||||
(defun string->int ((arg0 string))
|
||||
(let ((a0-1 (-> arg0 data))
|
||||
(v0-0 0)
|
||||
(v1-0 #f)
|
||||
)
|
||||
(cond
|
||||
((= (-> a0-1 0) 35)
|
||||
(let ((a0-2 (&-> a0-1 1)))
|
||||
(cond
|
||||
((or (= (-> a0-2 0) 120) (= (-> a0-2 0) 88))
|
||||
(let ((a0-3 (&-> a0-2 1)))
|
||||
(when (= (-> a0-3 1) 45)
|
||||
(set! v1-0 #t)
|
||||
(set! a0-3 (&-> a0-3 1))
|
||||
)
|
||||
(while (or (and (>= (-> a0-3 0) (the-as uint 48)) (>= (the-as uint 57) (-> a0-3 0)))
|
||||
(and (>= (-> a0-3 0) (the-as uint 65)) (>= (the-as uint 70) (-> a0-3 0)))
|
||||
(and (>= (-> a0-3 0) (the-as uint 97)) (>= (the-as uint 102) (-> a0-3 0)))
|
||||
)
|
||||
(cond
|
||||
((and (>= (-> a0-3 0) (the-as uint 65)) (>= (the-as uint 70) (-> a0-3 0)))
|
||||
(set! v0-0 (the-as int (+ (-> a0-3 0) -55 (* v0-0 16))))
|
||||
)
|
||||
((and (>= (-> a0-3 0) (the-as uint 97)) (>= (the-as uint 102) (-> a0-3 0)))
|
||||
(set! v0-0 (the-as int (+ (-> a0-3 0) -87 (* v0-0 16))))
|
||||
)
|
||||
(else
|
||||
(set! v0-0 (the-as int (+ (-> a0-3 0) -48 (* v0-0 16))))
|
||||
)
|
||||
)
|
||||
(set! a0-3 (&-> a0-3 1))
|
||||
)
|
||||
)
|
||||
)
|
||||
((or (= (-> a0-2 0) 98) (= (-> a0-2 0) 66))
|
||||
(let ((a0-4 (&-> a0-2 1)))
|
||||
(while (and (>= (-> a0-4 0) (the-as uint 48)) (>= (the-as uint 49) (-> a0-4 0)))
|
||||
(set! v0-0 (the-as int (+ (-> a0-4 0) -48 (* v0-0 2))))
|
||||
(set! a0-4 (&-> a0-4 1))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(else
|
||||
(when (= (-> a0-1 1) 45)
|
||||
(set! v1-0 #t)
|
||||
(set! a0-1 (&-> a0-1 1))
|
||||
)
|
||||
(while (and (>= (-> a0-1 0) (the-as uint 48)) (>= (the-as uint 57) (-> a0-1 0)))
|
||||
(set! v0-0 (the-as int (+ (-> a0-1 0) -48 (* 10 v0-0))))
|
||||
(set! a0-1 (&-> a0-1 1))
|
||||
)
|
||||
)
|
||||
)
|
||||
(cond
|
||||
(v1-0
|
||||
(- v0-0)
|
||||
)
|
||||
(else
|
||||
(empty)
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun string->float ((arg0 string))
|
||||
(let ((a0-1 (-> arg0 data))
|
||||
(f0-0 0.0)
|
||||
(v1-0 #f)
|
||||
)
|
||||
(when (= (-> a0-1 0) 45)
|
||||
(set! v1-0 #t)
|
||||
(set! a0-1 (&-> a0-1 1))
|
||||
)
|
||||
(while (and (>= (-> a0-1 0) (the-as uint 48)) (>= (the-as uint 57) (-> a0-1 0)))
|
||||
(set! f0-0 (+ (* 10.0 f0-0) (the float (+ (-> a0-1 0) -48))))
|
||||
(set! a0-1 (&-> a0-1 1))
|
||||
)
|
||||
(when (= (-> a0-1 0) 46)
|
||||
(set! a0-1 (&-> a0-1 1))
|
||||
(let ((a2-4 #xf4240)
|
||||
(a1-12 0)
|
||||
)
|
||||
(while (and (>= (-> a0-1 0) (the-as uint 48)) (>= (the-as uint 57) (-> a0-1 0)))
|
||||
(+! a1-12 (* (+ (-> a0-1 0) -48) (the-as uint a2-4)))
|
||||
(set! a2-4 (/ a2-4 10))
|
||||
(set! a0-1 (&-> a0-1 1))
|
||||
)
|
||||
(+! f0-0 (* 0.0000001 (the float a1-12)))
|
||||
)
|
||||
)
|
||||
(when (= (-> a0-1 0) 101)
|
||||
(let ((a1-16 (&-> a0-1 1))
|
||||
(f1-5 0.0)
|
||||
(a0-2 #f)
|
||||
)
|
||||
(cond
|
||||
((= (-> a1-16 0) 45)
|
||||
(set! a0-2 #t)
|
||||
(set! a1-16 (&-> a1-16 1))
|
||||
)
|
||||
((= (-> a1-16 0) 43)
|
||||
(set! a1-16 (&-> a1-16 1))
|
||||
)
|
||||
)
|
||||
(while (and (>= (-> a1-16 0) (the-as uint 48)) (>= (the-as uint 57) (-> a1-16 0)))
|
||||
(set! f1-5 (+ (* 10.0 f1-5) (the float (+ (-> a1-16 0) -48))))
|
||||
(set! a1-16 (&-> a1-16 1))
|
||||
)
|
||||
(when (!= f1-5 0.0)
|
||||
(let ((f2-6 1.0))
|
||||
(cond
|
||||
(a0-2
|
||||
(dotimes (a0-3 (the int f1-5))
|
||||
(set! f2-6 (* 0.1 f2-6))
|
||||
(nop!)
|
||||
(nop!)
|
||||
)
|
||||
)
|
||||
(else
|
||||
(dotimes (a0-6 (the int f1-5))
|
||||
(set! f2-6 (* 10.0 f2-6))
|
||||
(nop!)
|
||||
(nop!)
|
||||
)
|
||||
)
|
||||
)
|
||||
(set! f0-0 (* f0-0 f2-6))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(if v1-0
|
||||
(- f0-0)
|
||||
f0-0
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun string-get-int32!! ((arg0 (pointer int32)) (arg1 string))
|
||||
(cond
|
||||
((string-get-arg!! *string-tmp-str* arg1)
|
||||
(set! (-> arg0 0) (string->int *string-tmp-str*))
|
||||
#t
|
||||
)
|
||||
(else
|
||||
#f
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun string-get-float!! ((arg0 (pointer float)) (arg1 string))
|
||||
(cond
|
||||
((string-get-arg!! *string-tmp-str* arg1)
|
||||
(set! (-> arg0 0) (string->float *string-tmp-str*))
|
||||
#t
|
||||
)
|
||||
(else
|
||||
#f
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun string-get-flag!! ((arg0 (pointer symbol)) (arg1 string) (arg2 string) (arg3 string))
|
||||
(cond
|
||||
((string-get-arg!! *string-tmp-str* arg1)
|
||||
(cond
|
||||
((or (string= *string-tmp-str* arg2) (string= *string-tmp-str* arg3))
|
||||
(set! (-> arg0 0) (string= *string-tmp-str* arg2))
|
||||
#t
|
||||
)
|
||||
(else
|
||||
#f
|
||||
)
|
||||
)
|
||||
)
|
||||
(else
|
||||
#f
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(kmemopen global "gstring-globals")
|
||||
|
||||
(define *debug-draw-pauseable* #f)
|
||||
(define *stdcon0* (new 'global 'string #x4000 (the-as string #f)))
|
||||
(define *stdcon1* (new 'global 'string #x4000 (the-as string #f)))
|
||||
(define *stdcon* *stdcon0*)
|
||||
(define *temp-string* (new 'global 'string 2048 (the-as string #f)))
|
||||
|
||||
(kmemclose)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -220,6 +220,7 @@ class Compiler {
|
||||
bool is_structure(const TypeSpec& ts);
|
||||
bool is_bitfield(const TypeSpec& ts);
|
||||
bool is_pair(const TypeSpec& ts);
|
||||
bool is_symbol(const TypeSpec& ts);
|
||||
std::vector<goos::Object> get_list_as_vector(const goos::Object& o,
|
||||
goos::Object* rest_out = nullptr,
|
||||
int max_length = -1);
|
||||
|
||||
@@ -336,6 +336,10 @@ bool Compiler::is_pair(const TypeSpec& ts) {
|
||||
return m_ts.tc(m_ts.make_typespec("pair"), ts);
|
||||
}
|
||||
|
||||
bool Compiler::is_symbol(const TypeSpec& ts) {
|
||||
return m_ts.tc(m_ts.make_typespec("symbol"), ts);
|
||||
}
|
||||
|
||||
bool Compiler::get_true_or_false(const goos::Object& form, const goos::Object& boolean) {
|
||||
// todo try other things.
|
||||
if (boolean.is_symbol()) {
|
||||
|
||||
@@ -380,7 +380,7 @@ Val* Compiler::compile_get_symbol_value(const goos::Object& form,
|
||||
}
|
||||
|
||||
auto ts = existing_symbol->second;
|
||||
auto sext = m_ts.lookup_type(ts)->get_load_signed();
|
||||
auto sext = m_ts.lookup_type_allow_partial_def(ts)->get_load_signed();
|
||||
auto fe = env->function_env();
|
||||
auto sym = fe->alloc_val<SymbolVal>(name, m_ts.make_typespec("symbol"));
|
||||
auto re = fe->alloc_val<SymbolValueVal>(sym, ts, sext);
|
||||
|
||||
@@ -139,7 +139,8 @@ void Compiler::compile_static_structure_inline(const goos::Object& form,
|
||||
deref_info.sign_extend);
|
||||
}
|
||||
|
||||
} else if (is_structure(field_info.type) || is_pair(field_info.type)) {
|
||||
} else if (is_structure(field_info.type) || is_pair(field_info.type) ||
|
||||
is_symbol(field_info.type)) {
|
||||
if (is_pair(field_info.type)) {
|
||||
ASSERT(!field_info.field.is_inline());
|
||||
}
|
||||
|
||||
@@ -162,7 +162,8 @@ void Compiler::generate_field_description(const goos::Object& form,
|
||||
format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env));
|
||||
} else if (m_ts.tc(m_ts.make_typespec("basic"), f.type()) ||
|
||||
m_ts.tc(m_ts.make_typespec("binteger"), f.type()) ||
|
||||
m_ts.tc(m_ts.make_typespec("pair"), f.type())) {
|
||||
m_ts.tc(m_ts.make_typespec("pair"), f.type()) ||
|
||||
m_ts.tc(m_ts.make_typespec("symbol"), f.type())) {
|
||||
// basic, binteger, pair
|
||||
str_template += fmt::format("{}{}: ~A~%", tabs, f.name());
|
||||
format_args.push_back(get_field_of_structure(type, reg, f.name(), env)->to_gpr(form, env));
|
||||
|
||||
@@ -50,7 +50,7 @@ def main():
|
||||
file_stats = []
|
||||
total_gc_files = 0
|
||||
excluded_files = {"game_dgos.gc", "all_files.gc", "goal-lib.gc", "ocean-trans-tables.gc", "ocean-frames.gc",
|
||||
"ocean-tables.gc"}
|
||||
"ocean-tables.gc", "kernel-defs.gc", "compiler-setup.gc"}
|
||||
modified = set()
|
||||
|
||||
for fn in all_files:
|
||||
|
||||
@@ -961,6 +961,14 @@ TEST(Jak1TypeConsistency, TypeConsistency) {
|
||||
compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-all-code.gc");
|
||||
}
|
||||
|
||||
TEST(Jak2TypeConsistency, TypeConsistency) {
|
||||
Compiler compiler(GameVersion::Jak2);
|
||||
compiler.enable_throw_on_redefines();
|
||||
add_expected_type_mismatches(compiler);
|
||||
compiler.run_test_no_load("decompiler/config/jak2/all-types.gc");
|
||||
compiler.run_test_no_load("test/goalc/source_templates/with_game/test-build-all-code.gc");
|
||||
}
|
||||
|
||||
struct VectorFloatRegister {
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
|
||||
Reference in New Issue
Block a user