! T3X/0 back-end for the Raspberry Pi 1 (bare metal)
! Nils M Holm, 2024
! In the Public Domain / 0BSD License

! To do:
! maybe implement in asm: memcomp, memcopy, memfill, memscan, gpio

module cg;

 public const	BPW = 4;
 public const	ALIGN = BPW;

 public const	GPOOL_SIZE = 31;

 public const	BUFLEN = 512;

 public const	SYMTBL_SIZE = 2048;
 public const	LABEL_SIZE = 4096;
 public const	NLIST_SIZE = 6144;

 public const	LOCAL_LIMIT = 32760;

 public binary() return %1;

 public suffix() return ".bin";

 public modpath() return [
	"library/",
	"/usr/local/t3x/0/raspi1/",
	"/usr/local/t3x/0/",
	"",
	0 ];

 hex(c)	ie ('0' <= c /\ c <= '9')
		return c-'0';
	else
		return c-'a'+10;

 byte(s) return 16*hex(s::0) + hex(s::1);

 hexwrite(s)
	while (s::0) do
		emit(byte(s));
		s := s + 2;
	end

 emitd(v) do
	emit(v);
	emit(v >> 8);
	emit(v >> 16);
	emit(v >> 24);
 end

 const	HEADER_SIZE = 0x54;
 const	PAGE_SIZE = 4096;

 public header(tsize) do
	hexwrite("7f454c46");		! magic
	hexwrite("01");			! 32-bit
	hexwrite("01");			! little endian
	hexwrite("01");			! header version
	hexwrite("00");			! ABI (none)
	hexwrite("0000000000000000");	! padding
	hexwrite("0200");		! executable
	hexwrite("2800");		! ARMv7 / AArch32
	emitd(1);			! version
	hexwrite("54800000");		! initial entry point
	emitd(34);			! program header offset
	emitd(0);			! no header segments
	emitd(0);			! flags
	hexwrite("5400");		! header size
	hexwrite("2000");		! program header size
	hexwrite("0100");		! number of program headers
	hexwrite("2800");		! segment header size (unused)
	hexwrite("0000");		! number of segment headers
	hexwrite("0000");		! string index (unused)
	! text segment description
	emitd(1);			! loadable segment
	emitd(HEADER_SIZE);		! offset in file
	hexwrite("00800000");		! virtual load address
	hexwrite("00800000");		! physical load address
	emitd(tsize-HEADER_SIZE);	! size in file
	emitd(tsize-HEADER_SIZE);	! size in memory
	emitd(7);			! flags := read, write, execute
	emitd(PAGE_SIZE);		! alignment (page)
	return 0x4000 << 1 | HEADER_SIZE;
 end

 public codefrags() return [
	[ CG_NULL,	""					],
	[ CG_PUSH,	"01002de9"				],
	[ CG_CLEAR,	"000020e0"				],
	[ CG_DROP,	"0200bde8"				],
	[ CG_LDVAL,	"00009fe5000000ea,w"			],
	[ CG_LDADDR,	"00009fe5000000ea,w"			],
	[ CG_LDLREF,	"00109fe5000000ea,w01008be0"		],
	[ CG_LDGLOB,	"00109fe5000000ea,w000091e5"		],
	[ CG_LDLOCL,	"00109fe5000000ea,w01008be0000090e5"	],
	[ CG_STGLOB,	"00109fe5000000ea,w000081e5"		],
	[ CG_STLOCL,	"00109fe5000000ea,w01108be0000081e5"	],
	[ CG_STINDR,	"0200bde8000081e5"			],
	[ CG_STINDB,	"0200bde80000c1e5"			],
	[ CG_INCGLOB,
	  "00109fe5000000ea,w000091e5010080e2000081e5"		],
	[ CG_INCLOCL,
	  "00109fe5000000ea,w01108be0000091e5010080e2000081e5"	],
	[ CG_INCR,	"00109fe5000000ea,w010080e0"		],
	[ CG_STACK,	"00109fe5000000ea,w01d08de0"		],
	[ CG_UNSTACK,	"00109fe5000000ea,w01d08de0"		],
	[ CG_LOCLVEC,	"0d10a0e102002de9"			],
	[ CG_GLOBVEC,	"00109fe5000000ea,w00d081e5"		],
	[ CG_INDEX,	"0200bde8000181e0"			],
	[ CG_DEREF,	"000090e5"				],
	[ CG_INDXB,	"0200bde8000081e0"			],
	[ CG_DREFB,	"0000d0e5"				],
	[ CG_CALL,	",Reb"					],
	[ CG_CALR,	"30ff2fe1"				],
	[ CG_JUMP,	",Rea"					],
	[ CG_RJUMP,	",Rea"					],
	[ CG_JMPFALSE,	"000050e3,R0a"				],
	[ CG_JMPTRUE,	"000050e3,R1a"				],
	[ CG_FOR,	"0200bde8000051e1,Raa"			],
	[ CG_FORDOWN,	"0200bde8010050e1,Raa"			],
	[ CG_MKFRAME,	"00082de90db0a0e1"			],
	[ CG_DELFRAME,	"0008bde8"				],
	[ CG_RET,	"0080bde8"				],
	[ CG_HALT,	"feffffea"				],
	[ CG_NEG,	"000060e2"				],
	[ CG_INV,	"0000e0e1"				],
	[ CG_LOGNOT,	"000050e3000020e001004002"		],
	[ CG_ADD,	"0200bde8000081e0"			],
	[ CG_SUB,	"0200bde8000041e0"			],
	[ CG_MUL,	"0200bde8910000e0"			],
	[ CG_DIV,	"0010a0e10100bde8,>088000eb"		],
	[ CG_MOD,	"0010a0e10100bde8,>048000eb0100a0e1"	],
	[ CG_AND,	"0200bde8000001e0"			],
	[ CG_OR,	"0200bde8000081e1"			],
	[ CG_XOR,	"0200bde8000021e0"			],
	[ CG_SHL,	"0200bde81100a0e1"			],
	[ CG_SHR,	"0200bde83100a0e1"			],
	[ CG_EQ,	"0200bde8000051e1000020e001004002"	],
	[ CG_NE,	"0200bde8000051e1000020e001004012"	],
	[ CG_LT,	"0200bde8000051e1000020e0010040b2"	],
	[ CG_GT,	"0200bde8000051e1000020e0010040c2"	],
	[ CG_LE,	"0200bde8000051e1000020e0010040d2"	],
	[ CG_GE,	"0200bde8000051e1000020e0010040a2"	],
	[ CG_UMUL,	"0200bde8910000e0"			],
	[ CG_UDIV,	"0010a0e10100bde8,>048000eb"		],
	[ CG_ULT,	"0200bde8000051e1000020e001004032"	],
	[ CG_UGT,	"0200bde8000051e1000020e001004082"	],
	[ CG_ULE,	"0200bde8000051e1000020e001004092"	],
	[ CG_UGE,	"0200bde8000051e1000020e001004022"	],
	[ CG_JMPEQ,	"0200bde8000051e1,R0a"			],
	[ CG_JMPNE,	"0200bde8000051e1,R1a"			],
	[ CG_JMPLT,	"0200bde8000051e1,Rba"			],
	[ CG_JMPGT,	"0200bde8000051e1,Rca"			],
	[ CG_JMPLE,	"0200bde8000051e1,Rda"			],
	[ CG_JMPGE,	"0200bde8000051e1,Raa"			],
	[ CG_JMPULT,	"0200bde8000051e1,R3a"			],
	[ CG_JMPUGT,	"0200bde8000051e1,R8a"			],
	[ CG_JMPULE,	"0200bde8000051e1,R9a"			],
	[ CG_JMPUGE,	"0200bde8000051e1,R2a"			],
	[ CG_SKIP,	",Rea"					],
	[ CG_CALN,	""					],
	[ CG_LDNAM,	""					],
	[ CG_ENTER,	"00402de9"				],
	[ %1,		[0]					] ];

 public optimizations() return [
	[ CG_EQ,	0,	CG_JMPFALSE,	CG_JMPNE	],
	[ CG_NE,	0,	CG_JMPFALSE,	CG_JMPEQ	],
	[ CG_LT,	0,	CG_JMPFALSE,	CG_JMPGE	],
	[ CG_GT,	0,	CG_JMPFALSE,	CG_JMPLE	],
	[ CG_LE,	0,	CG_JMPFALSE,	CG_JMPGT	],
	[ CG_GE,	0,	CG_JMPFALSE,	CG_JMPLT	],
	[ CG_EQ,	0,	CG_JMPTRUE,	CG_JMPEQ	],
	[ CG_NE,	0,	CG_JMPTRUE,	CG_JMPNE	],
	[ CG_LT,	0,	CG_JMPTRUE,	CG_JMPLT	],
	[ CG_GT,	0,	CG_JMPTRUE,	CG_JMPGT	],
	[ CG_LE,	0,	CG_JMPTRUE,	CG_JMPLE	],
	[ CG_GE,	0,	CG_JMPTRUE,	CG_JMPGE	],
	[ CG_LOGNOT,	0,	CG_JMPFALSE,	CG_JMPTRUE	],
	[ CG_DROP,	0,	CG_PUSH,	CG_NULL		],
	[ %1,		%1,	%1,		%1		],
	[ CG_LDVAL,	0,	CG_INDEX,	CG_DROP		],
	[ CG_LDVAL,	0,	CG_INDXB,	CG_DROP		],
	[ CG_LDVAL,	0,	CG_ADD,		CG_DROP		],
	%1 ];

 public library() return [
	488,
	packed [
	  0x01, 0x00, 0x00, 0xea,	! b       init
	  0x69, 0x00, 0x00, 0xea,	! b       sdiv
	  0x04, 0x00, 0x00, 0xea,	! b       udiv
	  				! init:
	  0x00, 0x00, 0x9f, 0xe5,	! ldr     r0, [pc, #0]
	  0x00, 0x00, 0x00, 0xea,	! b       .+8
	  0x00, 0x00, 0x40, 0x00,	! .word   0x00400000
	  0x00, 0xd0, 0xa0, 0xe1,	! mov     sp, r0
	  0x71, 0x00, 0x00, 0xea,	! b       start
	  				! udiv:
	  0x00, 0x20, 0x61, 0xe2,	! rsb     r2, r1, #0
	  0x00, 0x10, 0xa0, 0xe3,	! mov     r1, #0
	  0x00, 0x00, 0x90, 0xe0,	! adds    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x81, 0x10, 0xb2, 0xe0,	! adcs    r1, r2, r1, lsl #1
	  0x02, 0x10, 0x41, 0x30,	! subcc   r1, r1, r2
	  0x00, 0x00, 0xb0, 0xe0,	! adcs    r0, r0, r0
	  0x0e, 0xf0, 0xa0, 0xe1,	! mov     pc, lr
	  				! sdiv:
	  0x00, 0x40, 0x2d, 0xe9,	! push    {lr}
	  0x01, 0x30, 0x20, 0xe0,	! eor     r3, r0, r1
	  0xc3, 0x3f, 0xa0, 0xe1,	! asr     r3, r3, #31
	  0x00, 0x00, 0x51, 0xe3,	! cmp     r1, #0
	  0x06, 0x00, 0x00, 0x0a,	! beq     divz
	  0x00, 0x10, 0x61, 0x42,	! rsbmi   r1, r1, #0
	  0x00, 0x00, 0x50, 0xe3,	! cmp     r0, #0
	  0x00, 0x00, 0x60, 0x42,	! rsbmi   r0, r0, #0
	  0x92, 0xff, 0xff, 0xeb,	! bl      udiv
	  0x00, 0x00, 0x53, 0xe3,	! cmp     r3, #0
	  0x00, 0x00, 0x60, 0x12,	! rsbne   r0, r0, #0
	  0x00, 0x80, 0xbd, 0xe8,	! pop     {pc}
	  				! divz:
	  0x00, 0x00, 0x20, 0xe0,	! eor     r0, r0, r0
	  0x00, 0x80, 0xbd, 0xe8 ],	! pop     {pc}
	  				! start:
	0 ];

end
