BASIC inline ASM / assembler

Questions about the BASICtools and MakeItC
Post Reply
basicchip
Posts: 905
Joined: Fri Oct 19, 2012 2:39 am
Location: Lake Tahoe, CA
Contact:

BASIC inline ASM / assembler

Post by basicchip » Sun Jan 06, 2019 7:38 pm

BASIC has always supported a rudimentary inline assembler using __ASM__(code_value). It would place that code_value into the compiled hex for the BASIC program. Code_value is typically a 2 byte value, but if the number exceeds &HFFFF then 2 instructions will be inserted into the hex.

PC relative constants for ARM must be word aligned, so to support that __ASM32__ (32 bit constant) has been added. It will word align that constant and insert it into the code.

This supported simple needs for inline assembly. Recently for multi-tasking a set of #define macros were written for a wide assortment of ARM assembly instructions was built. This gave another level of abstraction for inline assembly.

For instance

Code: Select all

    ASM_MOVI(1,98)    ' loads R1 with 98
this is accomplished with this macro

Code: Select all

#define ASM_MOVI(Rdest,Imm)			__ASM__(&H2000 + (Rdest<<8) + ((Imm) and &HFF))
This is part of the ASMinlineBASIC.bas file. Feel free to extend it or tweak the syntax (please repost here, TIA)

Code: Select all


'crude inline ASM for BASIC

#ifndef ASM_INLINE

#define ASM_INLINE

'	first cut	- bte	Jan 5 2019			-- feel free to expand it  -- or CORRECT it

#define REG_SP	13
#define REG_LR	14
#define REG_PC	15

' 	note to Bruce  the destination register is on the left !! -- too many years in Motorola land

#define ASM_ADDRRR(Rdest,R1,R2)		__ASM__(&H1800 + Rdest + (R1<<6) + (R2<<3))
#define ASM_SUBRRR(Rdest,R1,R2)		__ASM__(&H1A00 + Rdest + (R1<<6) + (R2<<3))		' Rdesr = R1 - R2

#define ASM_ADDRRI(Rdest,R1,Imm)	__ASM__(&H1C00 + Rdest + (R1<<3) + ((Imm)<<6))
#define ASM_SUBRRI(Rdest,R1,Imm)	__ASM__(&H1E00 + Rdest + (R1<<3) + ((Imm)<<6))	' Rdesr = R1 - Imm


#define ASM_MOVI(Rdest,Imm)			__ASM__(&H2000 + (Rdest<<8) + ((Imm) and &HFF))
#define ASM_CMPI(Rdest,Imm)			__ASM__(&H2800 + (Rdest<<8) + ((Imm) and &HFF))
#define ASM_ADDI(Rdest,Imm)			__ASM__(&H3000 + (Rdest<<8) + ((Imm) and &HFF))
#define ASM_SUBI(Rdest,Imm)			__ASM__(&H3800 + (Rdest<<8) + ((Imm) and &HFF))

'	register ALU ops -- r0-7

#define ASM_AND(Rdest,Rsrc)			__ASM__(&H4000 + (Rsrc<<3) + Rdest)
#define ASM_EOR(Rdest,Rsrc)			__ASM__(&H4040 + (Rsrc<<3) + Rdest)
#define ASM_LSL(Rdest,Rsrc)			__ASM__(&H4080 + (Rsrc<<3) + Rdest)
#define ASM_LSR(Rdest,Rsrc)			__ASM__(&H40C0 + (Rsrc<<3) + Rdest)
#define ASM_ASR(Rdest,Rsrc)			__ASM__(&H4100 + (Rsrc<<3) + Rdest)
#define ASM_ADC(Rdest,Rsrc)			__ASM__(&H4140 + (Rsrc<<3) + Rdest)
#define ASM_SBC(Rdest,Rsrc)			__ASM__(&H4180 + (Rsrc<<3) + Rdest)
#define ASM_ROR(Rdest,Rsrc)			__ASM__(&H41C0 + (Rsrc<<3) + Rdest)
#define ASM_TST(Rdest,Rsrc)			__ASM__(&H4200 + (Rsrc<<3) + Rdest)
#define ASM_NEG(Rdest,Rsrc)			__ASM__(&H4240 + (Rsrc<<3) + Rdest)
#define ASM_CMP(Rdest,Rsrc)			__ASM__(&H4280 + (Rsrc<<3) + Rdest)
#define ASM_CMN(Rdest,Rsrc)			__ASM__(&H42C0 + (Rsrc<<3) + Rdest)
#define ASM_ORR(Rdest,Rsrc)			__ASM__(&H4300 + (Rsrc<<3) + Rdest)
#define ASM_MUL(Rdest,Rsrc)			__ASM__(&H4340 + (Rsrc<<3) + Rdest)
#define ASM_BIC(Rdest,Rsrc)			__ASM__(&H4380 + (Rsrc<<3) + Rdest)
#define ASM_MVN(Rdest,Rsrc)			__ASM__(&H43C0 + (Rsrc<<3) + Rdest)
	
'	there are more combinations, but these seem most useful

#define ASM_MOVRloRhi(Rdest,RhiSrc)	__ASM__(&H4640 + ((RhiSrc and 7)<<3) + Rdest)
#define ASM_MOVRhiRlo(RhiDst,Rsrc)	__ASM__(&H4680 + (Rsrc<<3) + (RhiDst and 7))

' 	these are limited to r0-r7

#define ASM_STR(Rsrc,Rbase,Roff) 	__ASM__(&H5000 + Rsrc + (Rbase<<3) + (Roff<<6))
#define ASM_LDR(Rdest,Rbase,Roff) 	__ASM__(&H5800 + Rdest + (Rbase<<3) + (Roff<<6))

#define ASM_STRB(Rsrc,Rbase,Roff) 	__ASM__(&H5400 + Rsrc + (Rbase<<3) + (Roff<<6))
#define ASM_LDRB(Rdest,Rbase,Roff) 	__ASM__(&H5C00 + Rdest + (Rbase<<3) + (Roff<<6))

#define ASM_STRoff(Rsrc,Rbase,off) 	__ASM__(&H6000 + Rsrc + (Rbase<<3) + (((off) and &H7C00)<<4))
#define ASM_LDRoff(Rdst,Rbase,off)	__ASM__(&H6800 + Rdst + (Rbase<<3) + (((off) and &H7C00)<<4))

#define ASM_STRBoff(Rsrc,Rbase,off)	__ASM__(&H7000 + Rsrc + (Rbase<<3) + ((off)<<6))
#define ASM_LDRBoff(Rdst,Rbase,off) __ASM__(&H7800 + Rdst + (Rbase<<3) + ((off)<<6))

' 	SP relative

#define ASM_STR_SPI(Rdest,off)		__ASM__(&H9000 + (Rdest<<8) + (off >> 2))
#define ASM_LDR_SPI(Rdest,off)		__ASM__(&H9800 + (Rdest<<8) + (off >> 2))


' 	SP and PC calculate address

#define ASM_LDR_PC(Rdest,off)		__ASM__(&HA000 + (Rdest<<8) + ((off-4) >> 2))
#define ASM_LDR_SP(Rdest,off)		__ASM__(&HA800 + (Rdest<<8) + (off >> 2))

#define LIST_R0	1
#define LIST_R1	2
#define LIST_R2	4
#define LIST_R3	8
#define LIST_R4	16
#define LIST_R5	32
#define LIST_R6	64
#define LIST_R7 128

'	PUSH POP

#define LIST_LR	256			'push	
#define LIST_PC	256			'pop

#define ASM_PUSH(RegList) 			__ASM__(&HB400 + RegList)
#define ASM_POP(RegList) 			__ASM__(&HBC00 + RegList)
	
' 	multiple load/store

#define ASM_STMIA(Rbase,RegList) 	__ASM__(&HC000 + (Rbase<<8) + RegList)
#define ASM_LDMIA(Rbase,RegList) 	__ASM__(&HC800 + (Rbase<<8) + RegList)


'	remember the PC 4 byte offset included  -- probably only need a few of the following

#define ASM_BEQ(HWoff)				__ASM__(&HD000 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BNE(HWoff)				__ASM__(&HD100 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BCS(HWoff)				__ASM__(&HD200 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BCC(HWoff)				__ASM__(&HD300 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BMI(HWoff)				__ASM__(&HD400 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BPL(HWoff)				__ASM__(&HD500 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BVS(HWoff)				__ASM__(&HD600 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BVC(HWoff)				__ASM__(&HD700 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BHI(HWoff)				__ASM__(&HD800 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BLS(HWoff)				__ASM__(&HD900 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BGE(HWoff)				__ASM__(&HDA00 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BLT(HWoff)				__ASM__(&HDB00 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BGT(HWoff)				__ASM__(&HDC00 + (((HWoff-4)>>1) AND &HFF))
#define ASM_BLE(HWoff)				__ASM__(&HDD00 + (((HWoff-4)>>1) AND &HFF))

#define ASM_BR(HWoff)				__ASM__(&HE000 + (((HWoff-4)>>1) AND &H7FF))

#endif



basicchip
Posts: 905
Joined: Fri Oct 19, 2012 2:39 am
Location: Lake Tahoe, CA
Contact:

Re: BASIC inline ASM / assembler

Post by basicchip » Sun Jan 06, 2019 7:40 pm

I know one user wanted a more robust assembler and has linked the gcc assembler into BASICtools.

Look forward to more details.

olzeke51
Posts: 333
Joined: Sat May 17, 2014 4:22 pm
Location: South Carolina
Contact:

Re: BASIC inline ASM / assembler

Post by olzeke51 » Mon Jan 07, 2019 10:41 pm

I love your comment ::
' note to Bruce the destination register is on the left !! -- too many years in Motorola land
'
I too have had confusion/forgetfulness trying to work with the ASsembler printouts for ARM
'
Thanks for posting the basic-simple test and this 'macro assembly' type file.

basicchip
Posts: 905
Joined: Fri Oct 19, 2012 2:39 am
Location: Lake Tahoe, CA
Contact:

Re: BASIC inline ASM / assembler

Post by basicchip » Thu Jan 10, 2019 9:39 pm

I was thinking about assembly branches in BASIC. Thinking other __ASM__ macros might be needed. But you can mix BASIC GOTO's with assembly. The following is an example of a conditional ASM branch around a GOTO in BASIC.

Code: Select all

#include "ASMinlineBASIC.bas"

ASM_BEQ(6)
goto somewhere
x=5
main:
somewhere:
The BASIC compiler uses long branches as they are not resolved immediately. So the ASM_BEQ(offset) has an offset of 6, 2 bytes for this instruction plus 4 more for the long branch. The ASM_BEQ macro adjusts for the PC pipeline (in Cortex PC usually points 4 bytes ahead). And here is the disassembled code

Code: Select all

0x00008004 D001      BEQ           0x0000800A
0x00008006 F000F804  BL.W          0x00008012
0x0000800A 2705      MOVS          r7,#0x05
0x0000800C 606F      STR           r7,[r5,#0x04]
So you can use BASIC for long branches in looping or the like in assembly and not need to count bytes, just use conditionals to jump around those BASIC GOTOs.

TodWulff
Posts: 47
Joined: Fri Oct 19, 2012 4:03 am
Location: The Mitten State - Shores of Lake Huron

Re: BASIC inline ASM / assembler

Post by TodWulff » Tue Jan 15, 2019 2:17 am

basicchip wrote:
Sun Jan 06, 2019 7:40 pm
I know one user wanted a more robust assembler and has linked the gcc assembler into BASICtools...Look forward to more details.
:) Details will be posted shortly. Thanks for the gentle nudge, kind sir.

Post Reply