<commit_before>;
; Initialize the kernel's runtime state.  We have no execution steps to
; complete, and we are working with a statically allocated step queue of
; 128 elements.  Base address is configured in the file "forth-config.i".
;
; kernInit()
;
		align 8
stpqbase:	dword	stepQueue
kernInit:	auipc	gp, 0
		ld	a0, stpqbase-kernInit(gp)
		sd	a0, zpStepQ(x0)
		sh	x0, zpStepHead(x0)
		sh	x0, zpStepTail(x0)
		addi	a0, x0, 128
		sh	a0, zpStepQSize(x0)
		jalr	x0, 0(rt)

;
; Perform a single iteration of the kernel's main event loop.
;
; kernEventCycle()
;

kernEventCycle:
		addi	rp, rp, -8
		sd	rt, 0(rp)

		jal	rt, kernStepsPending
		beq	a0, x0, kEC_bored

		ld	a1, zpStepQ(x0)
		lhu	a0, zpStepHead(x0)
		slli	a0, a0, 4		; 16 byte queue entry
		add	a1, a1, a0
		jal	rt, kernNextHead
		sh	a0, zpStepHead(x0)
		ld	a0, 0(a1)
		ld	a1, 8(a1)
		jalr	rt, 0(a0)

kEC_bored:	ld	rt, 0(rp)
		addi	rp, rp, 8
		jalr	x0, 0(rt)

;
; Enqueue something to do for later.  We need to provide a callback for the
; kernel to invoke, along with some callback-specific data.
;
; ok = kernToDo(proc, data)
; A0             A0    A1
;
; kernToDo returns non-zero if successful; or, zero if the step queue is full.
;
; The callback procedure takes two parameters in CPU registers A0 and A1,
; like so:
;
;	callback(self, data)
;		  A0    A1
;
; The callback returns nothing (or, more precisely, the kernel ignores
; whatever you may return).
;
; The callback receives a pointer to itself in register A0.  This is useful
; if you have a table of entry points, all of which refer to a common
; procedure, like so:
;
; _footab:	jal	x0, foo
;		jal	x0, foo
;		jal	x0, foo
;		jal	x0, foo
;
; footab:	dword	_footab
; foo:		; use A0 to calculate which entrypoint dispatched foo.
;		auipc	gp, 0
;		ld	a3, footab-foo(gp)
;		sub	a0, a0, a3
;		srli	a0, a0, 2
;		; 0 <= A0 < 4, providing an index into _footab.
;
; Register A1 is used to pass arbitrary data; the kernel does not interpret
; this value in any way.

kernToDo:	addi	rp, rp, -24
		sd	rt, 0(rp)
		sd	a0, 8(rp)
		sd	a1, 16(rp)

		jal	rt, kernStepQFull
		bne	a0, x0, kTD_full

		ld	a0, zpStepQ(x0)
		lhu	a1, zpStepTail(x0)
		slli	a1, a1, 4		; 16 byte queue entry
		add	a0, a0, a1

		ld	a1, 8(rp)
		sd	a1, 0(a0)
		ld	a1, 16(rp)
		sd	a1, 8(a0)

		jal	rt, kernNextTail
		sh	a0, zpStepTail(x0)
		addi	a0, a0, 1
		jal	x0, kTD_rfs

kTD_full:	addi	a0, x0, 0
kTD_rfs:	ld	rt, 0(rp)
		addi	rp, rp, 24
		jalr	x0, 0(rt)

;
; Answer true if no further steps can be added to the kernel's queue.
;
; full = kernStepQFull()
;  A0
;

kernStepQFull:	addi	rp, rp, -8
		sd	rt, 0(rp)

		jal	rt, kernNextTail
		lhu	a1, zpStepHead(x0)
		bne	a0, a1, kSQ_notFull
		addi	a0, x0, 1
kSQ_rfs:	ld	rt, 0(rp)
		addi	rp, rp, 8
		jalr	x0, 0(rt)

kSQ_notFull:	addi	a0, x0, 0
		jal	x0, kSQ_rfs

; Determine the number of steps pending in the kernel's queue.
;
; nevt = kernStepsPending()
;  A0

kernStepsPending:
		addi	rp, rp, -8
		sd	rt, 0(rp)

		; There are two cases here.  In the most obvious case,
		; the tail exceeds the head in memory, like so:
		;
		;                   |
		; | |#|#|#|#|#| | | |
		;    H         T    |
		;
		; In this case, the number of items in the queue is
		; obviously T-H.  When the reverse is true, however,
		; we have the following situation:
		;<commit_msg>Improve docs further<commit_after>;
; Initialize the kernel's runtime state.  We have no execution steps to
; complete, and we are working with a statically allocated step queue of
; 128 elements.  Base address is configured in the file "forth-config.i".
;
; kernInit()
;
; Destroys: A0
;
		align 8
stpqbase:	dword	stepQueue
kernInit:	auipc	gp, 0
		ld	a0, stpqbase-kernInit(gp)
		sd	a0, zpStepQ(x0)
		sh	x0, zpStepHead(x0)
		sh	x0, zpStepTail(x0)
		addi	a0, x0, 128
		sh	a0, zpStepQSize(x0)
		jalr	x0, 0(rt)

;
; Perform a single iteration of the kernel's main event loop.
;
; If the step queue is not empty, pop the queue and invoke the
; callback with its associated context.  Otherwise, take no action.
;
; kernEventCycle()
;
; Destroys: A0, A1, plus any registers destroyed by the callback.
;

kernEventCycle:
		addi	rp, rp, -8
		sd	rt, 0(rp)

		jal	rt, kernStepsPending
		beq	a0, x0, kEC_bored

		ld	a1, zpStepQ(x0)
		lhu	a0, zpStepHead(x0)
		slli	a0, a0, 4		; 16 byte queue entry
		add	a1, a1, a0
		jal	rt, kernNextHead
		sh	a0, zpStepHead(x0)
		ld	a0, 0(a1)
		ld	a1, 8(a1)
		jalr	rt, 0(a0)

kEC_bored:	ld	rt, 0(rp)
		addi	rp, rp, 8
		jalr	x0, 0(rt)

;
; Enqueue something to do for later.  We need to provide a callback for the
; kernel to invoke, along with some callback-specific data.
;
; ok = kernToDo(proc, data)
; A0             A0    A1
;
; kernToDo returns non-zero if successful; or, zero if the step queue is full.
;
; kernToDo will not allocate memory; it's safe to call from an interrupt
; handler.
;
; The callback procedure takes two parameters in CPU registers A0 and A1,
; like so:
;
;	callback(self, data)
;		  A0    A1
;
; The callback returns nothing (or, more precisely, the kernel ignores
; whatever you may return).
;
; The callback receives a pointer to itself in register A0.  This is useful
; if you have a table of entry points, all of which refer to a common
; procedure, like so:
;
; _footab:	jal	x0, foo
;		jal	x0, foo
;		jal	x0, foo
;		jal	x0, foo
;
; footab:	dword	_footab
; foo:		; use A0 to calculate which entrypoint dispatched foo.
;		auipc	gp, 0
;		ld	a3, footab-foo(gp)
;		sub	a0, a0, a3
;		srli	a0, a0, 2
;		; 0 <= A0 < 4, providing an index into _footab.
;
; This technique most often finds use in interpreted languages where large
; jump tables are more burdensome to implement than alternative control flows.
;
; Register A1 is used to pass arbitrary data; the kernel does not interpret
; this value in any way.
;
; Destroys: A1
;

kernToDo:	addi	rp, rp, -24
		sd	rt, 0(rp)
		sd	a0, 8(rp)
		sd	a1, 16(rp)

		jal	rt, kernStepQFull
		bne	a0, x0, kTD_full

		ld	a0, zpStepQ(x0)
		lhu	a1, zpStepTail(x0)
		slli	a1, a1, 4		; 16 byte queue entry
		add	a0, a0, a1

		ld	a1, 8(rp)
		sd	a1, 0(a0)
		ld	a1, 16(rp)
		sd	a1, 8(a0)

		jal	rt, kernNextTail
		sh	a0, zpStepTail(x0)
		addi	a0, a0, 1
		jal	x0, kTD_rfs

kTD_full:	addi	a0, x0, 0
kTD_rfs:	ld	rt, 0(rp)
		addi	rp, rp, 24
		jalr	x0, 0(rt)

;
; Answer true if no further steps can be added to the kernel's queue.
;
; full = kernStepQFull()
;  A0
;
; Destroys: A1
;

kernStepQFull:	addi	rp, rp, -8
		sd	rt, 0(rp)

		jal	rt, kernNextTail
		lhu	a1, zpStepHead(x0)
		bne	a0, a1, kSQ_notFull
		addi	a0, x0, 1
kSQ_rfs:	ld	rt, 0(rp)
		addi	rp, rp, 8
		jalr	x0, 0(rt)

kSQ_notFull:	addi	a0, x0, 0
		jal	x0, kSQ_rfs

;
; Determine the number of steps pending in the kernel's queue.
;
; nevt = kernStepsPending()
;  A0
;
; Destroys: A1 A2
;

kernStepsPending:
		addi	rp, rp, -8
		sd	rt, 0(rp)

		; There are two cases here.  In the most obvious case,
		; the tail exceeds the head in memory, like so:
		;
		;                   |
		; | |#|#|#|#|#| | | |
		;    H         T    |
		;
		; In this case, the number of items in the queue is
		; obviously T-H.  When the reverse is true, however,
		; we have the following situation:
		;
{'fraction_non_alphanumeric': 0.10029581631215664, 'fraction_numerical': 0.04155514861248063, 'mean_word_length': 2.9910061832490165, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5283434', 'n_tokens_mistral': 3411, 'n_tokens_neox': 3143, 'n_words': 1094}