Calling C Functions from Forth and Vice Versa

Register Usage

Procedure Call Standard for the ARM Architecture AAPCS

https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/on-the-aapcs-with-an-application-to-efficient-parameter-passing

Register AAPCS Purpose Restore Contents MECRISP Forth Purpose ISR Stacking
xPSR Processor Status Register, Flags N Flags 1
r0 Argument, result, scratch register 1 N Scratch 2
r1 Argument, result, scratch register 2 N Scratch 3
r2 Argument, scratch register 3 N Scratch 4
r3 Argument, scratch register 4 Y Scratch 5
r4 Variable register 1 Y DO Index  
r5 Variable register 2 Y DO Limit  
r6 Variable register 3 Y Top Of Stack TOS  
r7 Variable register 4 Y Data stack pointer SPS  
r8 Variable register 5 Y unused  
r9 Platform register (usage defined by platform in use) Y unused  
r10 Variable register 7 Y unused  
r11 Variable register 8 Y unused  
r12 Intra-procedure-call scratch register N unused 6
r13 Stack pointer (SP) y Stack pointer (SP)  
r14 Link register (LR) N Link register (LR) 7
r15 Program counter (PC) N Program counter (PC) 0

VFP Register Usage

The VFP-v2 co-processor has 32 single-precision registers, s0-s31, which may also be accessed as 16 double-precision registers, d0-d15 (with d0 overlapping s0, s1; d1 overlapping s2, s3; etc).

Calling C Functions from Forth

Word osDelay from rtos.s

// -----------------------------------------------------------------------------
	Wortbirne Flag_visible, "osDelay"
	@ ( u -- n ) Wait for Timeout (Time Delay).
/// \param[in]     ticks         \ref CMSIS_RTOS_TimeOutValue "time ticks" value
/// \return status code that indicates the execution status of the function.
// osStatus_t osDelay (uint32_t ticks);
// -----------------------------------------------------------------------------
rtos_osDelay:
	push	{r0-r3, lr}
	movs	r0, tos		// ticks
	bl	osDelay
	movs	tos, r0
	pop	{r0-r3, pc}

If the C function itself calls Forth words the Data Stack Pointer SPS and Top Of Stack TOS registers have to be passed to the Forth words. See below.

Calling Forth Words from C Functions

Data Stack Pointer SPS is in R1 and Top Of Stack TOS is in R0 (first parameter).

C function FS_include() from fs.c calls the Forth words FS_type and FS_evaluate.

/**
 *  @brief
 *      Interprets the content of the file.
 *  @param[in]
 *      forth_stack   TOS (lower word) and SPS (higher word)
 *  @param[in]
 *      str   filename (w/ or w/o null termination)
 *  @param[in]
 *      count string length
 *  @return
 *      TOS (lower word) and SPS (higer word)
 */
uint64_t FS_include(uint64_t forth_stack, uint8_t *str, int count) {
	FIL fil;        /* File object */
	FRESULT fr;     /* FatFs return code */

	uint64_t stack;
	stack = forth_stack;

	memcpy(path, str, count);
	line[count] = 0;

	/* Open a text file */
	fr = f_open(&fil, path, FA_READ);
	if (fr) {
		// open failed
		strcpy(line, "Err: file not found");
		stack = FS_type(stack, (uint8_t*)line, strlen(line));
	}

	/* Read every line and interprets it */
	while (f_gets(line, sizeof line, &fil)) {
		// line without \n
		stack = FS_evaluate(stack, (uint8_t*)line, strlen(line)-1);
	}

	/* Close the file */
	f_close(&fil);

	return stack;
}

Word include from fs.s calls the C function FS_include().

@ -----------------------------------------------------------------------------
		Wortbirne Flag_visible, "include"
		@  ( any "filename" -- any ) Interprets the content of the file.
// uint64_t FS_include  (uint64_t forth_stack, uint8_t *str, int count);
@ -----------------------------------------------------------------------------
include:
	push	{lr}
	bl	token		@ ( -- c-addr len )
incl:
	movs	r3, tos		// len -> count
	drop
	movs	r2, tos		// c-addr -> str
	drop
	movs	r0, tos		// get tos
	movs	r1, psp		// get psp
	bl	FS_include
	movs	tos, r0		// update tos
	movs	psp, r1		// update psp
	pop	{pc}

The C function FS_include() from fs.c calls the Forth word evaluate by the FS_evaluate() function.

// uint64_t FS_evaluate(uint64_t forth_stack, uint8_t* str, int count);
.global		FS_evaluate
FS_evaluate:
	push 	{r4-r7, lr}
	movs	tos, r0		// get tos
	movs	psp, r1		// get psp
	pushdatos
	movs	tos, r2		// str
	pushdatos
	movs	tos, r3		// count
	bl	evaluate
	movs	r0, tos		// update tos
	movs	r1, psp		// update psp
	pop	{r4-r7, pc}

-- Peter Schmid - 2020-07-13

Creative Commons License
This work by Peter Schmid is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Edit | Attach | Watch | Print version | History: r7 < r6 < r5 < r4 < r3 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r7 - 2021-01-28 - PeterSchmid
 
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2024 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback