Merge in VideoCore IV code generator.

--HG--
branch : default-branch
This commit is contained in:
David Given 2016-03-13 21:39:05 +01:00
commit 436db46f48
85 changed files with 4750 additions and 22 deletions

3
.distr
View file

@ -48,6 +48,7 @@ mach/i80
mach/i86
mach/i386
mach/m68020
mach/vc4
plat
plat/cpm
@ -55,5 +56,7 @@ plat/pc86
plat/linux
plat/linux386
plat/linux68k
plat/rpi
examples
man

View file

@ -54,6 +54,8 @@ CFLAGS += \
LDFLAGS +=
ACKFLAGS = -Ih
all: installables
.DELETE_ON_ERROR:
@ -101,6 +103,7 @@ include mach/i386/build.mk
include mach/i86/build.mk
include mach/m68020/build.mk
# include mach/powerpc/build.mk
include mach/vc4/build.mk
include plat/build.mk
include plat/pc86/build.mk
@ -108,6 +111,7 @@ include plat/cpm/build.mk
include plat/linux386/build.mk
include plat/linux68k/build.mk
# include plat/linuxppc/build.mk
include plat/rpi/build.mk
.PHONY: installables
installables: $(INSTALLABLES)

3
README
View file

@ -32,6 +32,7 @@ pc86 produces bootable floppy disk images for 8086 PCs
linux386 produces ELF executables for PC Linux systems
linux68k produces ELF executables for m68020 Linux systems
cpm produces i80 CP/M .COM files
rpi produces Raspberry Pi GPU binaries
INSTALLATION
@ -128,7 +129,7 @@ GOTCHAS
There are some things you should be aware of.
- Look at plat/<PLATFORMNAME>/README for information about the two supported
- Look at plat/<PLATFORMNAME>/README for information about the supported
platforms.
- The library support is fairly limited; for C, it's at roughly the ANSI C

View file

@ -3,6 +3,7 @@ define reset
$(eval o :=)
$(eval s :=)
$(eval cflags :=)
$(eval ackflags :=)
$(eval ldflags :=)
$(eval objdir :=)
endef

View file

@ -64,6 +64,7 @@ struct outname {
#define RELO4 3 /* 4 bytes */
#define RELOPPC 4 /* PowerPC 26-bit address */
#define RELOH2 5 /* write top 2 bytes of 4 byte word */
#define RELOVC4 6 /* VideoCore IV address in 32-bit instruction */
#define RELPC 0x08 /* pc relative */
#define RELBR 0x10 /* High order byte lowest address. */

View file

@ -16,6 +16,7 @@ define build-libcc-ansi-headers-impl
float.h \
limits.h \
math.h \
malloc.h \
setjmp.h \
signal.h \
stdarg.h \

View file

@ -20,3 +20,4 @@ stdbool.h
fcntl.h
tgmath.h
locale.h
malloc.h

View file

@ -0,0 +1,66 @@
/*
* stdlib.h - standard library
*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Id$ */
#ifndef _STDLIB_H
#define _STDLIB_H
#include <stddef.h>
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
#define RAND_MAX 32767
#define MB_CUR_MAX sizeof(wchar_t)
typedef struct { int quot, rem; } div_t;
typedef struct { long quot, rem; } ldiv_t;
extern double atof(const char *_nptr);
extern int atoi(const char *_nptr);
extern long atol(const char *_nptr);
extern double strtod(const char *_nptr, char **_endptr);
extern long strtol(const char *_nptr, char **_endptr, int _base);
extern unsigned long strtoul(const char *_nptr, char **_endptr, int _base);
extern int rand(void);
extern void srand(unsigned int _seed);
extern void* calloc(size_t _nmemb, size_t _size);
extern void free(void *_ptr);
extern void* malloc(size_t _size);
extern void* realloc(void *_ptr, size_t _size);
extern void abort(void);
extern int atexit(void (*_func)(void));
extern void exit(int _status);
extern void _Exit(int _status);
extern char* getenv(const char *_name);
extern int setenv(const char *_name, const char *_value, int _overwrite);
extern int unsetenv(const char *_name);
extern int putenv(char *_string);
extern int system(const char *_string);
extern void* bsearch(const void *_key, const void *_base,
size_t _nmemb, size_t _size,
int (*_compar)(const void *, const void *));
extern void qsort(void *_base, size_t _nmemb, size_t _size,
int (*_compar)(const void *, const void *));
extern int abs(int _j);
extern div_t div(int _numer, int _denom);
extern long labs(long _j);
extern ldiv_t ldiv(long _numer, long _denom);
extern int mblen(const char *_s, size_t _n);
extern int mbtowc(wchar_t *_pwc, const char *_s, size_t _n);
extern int wctomb(char *_s, wchar_t _wchar);
extern size_t mbstowcs(wchar_t *_pwcs, const char *_s, size_t _n);
extern size_t wcstombs(char *_s, const wchar_t *_pwcs, size_t _n);
/* Extensions (not part of the standard) */
#define atof(n) strtod(n, (char **)NULL)
#define atoi(n) ((int)strtol(n, (char **)NULL, 10))
#define atol(n) strtol(n, (char **)NULL, 10)
#define atoll(n) strtoll(n, (char **)NULL, 10)
#define mblen(s, n) mbtowc((wchar_t *)0, s, n)
#endif

View file

@ -26,7 +26,7 @@ typedef unsigned short uint16_t;
#if _EM_WSIZE == 4
typedef signed int int32_t;
typedef unsigned short uint32_t;
typedef unsigned int uint32_t;
#else
typedef signed long int32_t;
typedef unsigned long uint32_t;

View file

@ -39,6 +39,7 @@ rewind.c
scanf.c
setbuf.c
setvbuf.c
snprintf.c
sprintf.c
sscanf.c
tmpfile.c
@ -47,3 +48,4 @@ ungetc.c
vfprintf.c
vprintf.c
vsprintf.c
vsnprintf.c

View file

@ -17,6 +17,7 @@ mbstowcs.c
mbtowc.c
qsort.c
rand.c
setenv.c
strtod.c
strtol.c
system.c

View file

@ -9,6 +9,7 @@ strcmp.c
strcoll.c
strcpy.c
strcspn.c
strdup.c
strerror.c
strlen.c
strncat.c

View file

@ -84,7 +84,7 @@ name cem
-DEM_SSIZE={s} -DEM_LSIZE={l} -DEM_FSIZE={f} -DEM_DSIZE={d}) \
-D_EM_WSIZE={w} -D_EM_PSIZE={p} \
-D_EM_SSIZE={s} -D_EM_LSIZE={l} -D_EM_FSIZE={f} -D_EM_DSIZE={d} \
-Vw{w}.{w}i{w}.{w}p{p}.{w}f{f}.{w}s{s}.{s}l{l}.{w}d{d}.{w} \
-Vw{w}.{wa}i{w}.{wa}p{p}.{pa}f{f}.{fa}s{s}.{sa}l{l}.{la}d{d}.{da}x{x}.{xa} \
{CC_ALIGN?} \
{CEM_F?} {LFLAG?} < >
callname acc

View file

@ -25,6 +25,7 @@ s2650
sun3
sun2
vax4
vc4
xenix3
z80
z8000

View file

@ -26,7 +26,9 @@ define build-as-impl
$(eval CLEANABLES += $(OBJDIR)/$D/preprocessed-comm2.y)
$(OBJDIR)/$D/preprocessed-comm2.y: mach/proto/as/comm2.y $(CPPANSI) \
mach/$(ARCH)/as/mach1.c \
mach/$(ARCH)/as/mach2.c \
mach/$(ARCH)/as/mach3.c \
mach/$(ARCH)/as/mach4.c
@echo PREPROCESS $$@
@mkdir -p $$(dir $$@)
@ -39,6 +41,10 @@ $(OBJDIR)/$D/preprocessed-comm2.y: mach/proto/as/comm2.y $(CPPANSI) \
$(call rawfile, $(LIBOBJECT))
$(call cprogram, $(BINDIR)/$(PLATFORM)/as)
$(call installto, $(PLATDEP)/$(PLATFORM)/as)
$(call reset)
$(call file, man/$(ARCH)_as.6)
$(call installto, $(INSDIR)/share/man/man6/$(ARCH)_as.6)
endef
build-as = $(eval $(build-as-impl))

View file

@ -82,6 +82,8 @@ extern char em_flag[];
extern short em_ptyp[];
extern double atof();
void prolog(full nlocals);
/* Own version of atol that continues computing on overflow.
We don't know that about the ANSI C one.
*/

5
mach/vc4/.distr Normal file
View file

@ -0,0 +1,5 @@
build.mk
as
ncg
libem
libend

7
mach/vc4/as/.distr Normal file
View file

@ -0,0 +1,7 @@
mach0.c
mach1.c
mach2.c
mach3.c
mach4.c
mach5.c
binary.h

34
mach/vc4/as/binary.h Normal file
View file

@ -0,0 +1,34 @@
/*
* VideoCore IV assembler for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef BINARY_H
#define BINARY_H
/* This grotesque nonsense allows us to use binary constants from C. */
#define HEX__(n) 0x##n##LU
#define B8__(x) \
((x&0x0000000FLU)?1:0) \
+((x&0x000000F0LU)?2:0) \
+((x&0x00000F00LU)?4:0) \
+((x&0x0000F000LU)?8:0) \
+((x&0x000F0000LU)?16:0) \
+((x&0x00F00000LU)?32:0) \
+((x&0x0F000000LU)?64:0) \
+((x&0xF0000000LU)?128:0)
#define B8(d) \
((unsigned char)B8__(HEX__(d)))
#define B16(dmsb,dlsb) \
(((unsigned short)B8(dmsb)<<8) + B8(dlsb))
#define B32(dmsb,db2,db3,dlsb) \
(((unsigned long)B8(dmsb)<<24) \
+ ((unsigned long)B8(db2)<<16) \
+ ((unsigned long)B8(db3)<<8) \
+ B8(dlsb))
#endif

32
mach/vc4/as/mach0.c Normal file
View file

@ -0,0 +1,32 @@
/*
* VideoCore IV assembler for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#define THREE_PASS /* branch and offset optimization */
#define LISTING /* enable listing facilities */
#define RELOCATION /* generate relocatable code */
#define DEBUG 0
#undef valu_t
#define valu_t long
#undef ADDR_T
#define ADDR_T long
#undef word_t
#define word_t long
typedef unsigned long quad;
#undef ALIGNWORD
#define ALIGNWORD 4
#undef ALIGNSECT
#define ALIGNSECT 4
#undef VALWIDTH
#define VALWIDTH 8

28
mach/vc4/as/mach1.c Normal file
View file

@ -0,0 +1,28 @@
/*
* VideoCore IV assembler for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include "binary.h"
#define ALWAYS 14
extern void alu_instr_reg(quad opcode, int cc, int rd, int ra, int rb);
extern void alu_instr_lit(quad opcode, int cc, int rd, int ra, long value);
extern void misc_instr_reg(quad opcode, int cc, int rd, int ra, int rb);
extern void misc_instr_lit(quad opcode, int cc, int rd, int ra, quad value);
extern void branch_instr(int bl, int cc, struct expr_t* expr);
extern void stack_instr(quad opcode, int loreg, int hireg, int extrareg);
extern void mem_instr(quad opcode, int cc, int rd, long offset, int rs);
extern void mem_offset_instr(quad opcode, int cc, int rd, int qa, int rb);
extern void mem_postincr_instr(quad opcode, int cc, int rd, int rs);
extern void mem_address_instr(quad opcode, int rd, struct expr_t* expr);
extern void branch_addcmp_reg_reg_instr(int cc, int rd, int ra, int rs, struct expr_t* expr);
extern void branch_addcmp_lit_reg_instr(int cc, int rd, long va, int rs, struct expr_t* expr);
extern void branch_addcmp_reg_lit_instr(int cc, int rd, int ra, long vs, struct expr_t* expr);
extern void branch_addcmp_lit_lit_instr(int cc, int rd, long va, long vs, struct expr_t* expr);
extern void lea_stack_instr(int rd, long va, int rs);
extern void lea_address_instr(int rd, struct expr_t* expr);
extern void fltcnv_instr(quad opcode, int cc, int rd, int ra, quad shift);

24
mach/vc4/as/mach2.c Normal file
View file

@ -0,0 +1,24 @@
/*
* VideoCore IV assembler for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
%token <y_word> GPR
%token <y_word> CC
%token <y_word> OP
%token <y_word> OP_BRANCH OP_BRANCHLINK OP_ADDCMPB
%token <y_word> OP_ONEREG
%token <y_word> OP_ONELREG
%token <y_word> OP_ALU
%token <y_word> OP_FPU
%token <y_word> OP_MEM
%token <y_word> OP_MISC
%token <y_word> OP_MISCL
%token <y_word> OP_FLTCNV
%token <y_word> OP_STACK
%token <y_word> OP_LEA

153
mach/vc4/as/mach3.c Normal file
View file

@ -0,0 +1,153 @@
/*
* VideoCore IV assembler for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
/* Integer registers */
0, GPR, 0, "r0",
0, GPR, 1, "r1",
0, GPR, 2, "r2",
0, GPR, 3, "r3",
0, GPR, 4, "r4",
0, GPR, 5, "r5",
0, GPR, 6, "r6",
0, GPR, 7, "r7",
0, GPR, 8, "r8",
0, GPR, 9, "r9",
0, GPR, 10, "r10",
0, GPR, 11, "r11",
0, GPR, 12, "r12",
0, GPR, 13, "r13",
0, GPR, 14, "r14",
0, GPR, 15, "r15",
0, GPR, 16, "r16",
0, GPR, 17, "r17",
0, GPR, 18, "r18",
0, GPR, 19, "r19",
0, GPR, 20, "r20",
0, GPR, 21, "r21",
0, GPR, 22, "r22",
0, GPR, 23, "r23",
0, GPR, 24, "r24",
0, GPR, 24, "fp",
0, GPR, 25, "r25",
0, GPR, 25, "sp",
0, GPR, 26, "r26",
0, GPR, 26, "lr",
0, GPR, 27, "r27",
0, GPR, 28, "r28",
0, GPR, 29, "r29",
0, GPR, 30, "r30",
0, GPR, 30, "sr",
0, GPR, 31, "r31",
0, GPR, 31, "pc",
/* Condition codes */
0, CC, 0, ".eq",
0, CC, 1, ".ne",
0, CC, 2, ".cs",
0, CC, 2, ".lo",
0, CC, 3, ".cc",
0, CC, 3, ".hs",
0, CC, 4, ".mi",
0, CC, 5, ".pl",
0, CC, 6, ".vs",
0, CC, 7, ".vc",
0, CC, 8, ".hi",
0, CC, 9, ".ls",
0, CC, 10, ".ge",
0, CC, 11, ".lt",
0, CC, 12, ".gt",
0, CC, 13, ".le",
0, CC, 15, ".f",
/* Special instructions */
0, OP, B16(00000000,00000001), "nop",
0, OP, B16(00000000,00001010), "rti",
0, OP_BRANCH, 0, "b",
0, OP_BRANCHLINK, 0, "bl",
0, OP_ADDCMPB, 0, "addcmpb",
0, OP_ONELREG, B16(00000000,10000000), "tbb",
0, OP_ONELREG, B16(00000000,10100000), "tbs",
0, OP_ALU, B8(00000000), "mov",
0, OP_ALU, B8(00000001), "cmn",
0, OP_ALU, B8(00000010), "add",
0, OP_ALU, B8(00000011), "bic",
0, OP_ALU, B8(00000100), "mul",
0, OP_ALU, B8(00000101), "eor",
0, OP_ALU, B8(00000110), "sub",
0, OP_ALU, B8(00000111), "and",
0, OP_ALU, B8(00001000), "mvn",
0, OP_ALU, B8(00001001), "ror",
0, OP_ALU, B8(00001010), "cmp",
0, OP_ALU, B8(00001011), "rsb",
0, OP_ALU, B8(00001100), "btst",
0, OP_ALU, B8(00001101), "or",
0, OP_ALU, B8(00001110), "extu",
0, OP_ALU, B8(00001111), "max",
0, OP_ALU, B8(00010000), "bset",
0, OP_ALU, B8(00010001), "min",
0, OP_ALU, B8(00010010), "bclr",
0, OP_ALU, B8(00010011), "adds2",
0, OP_ALU, B8(00010100), "bchg",
0, OP_ALU, B8(00010101), "adds4",
0, OP_ALU, B8(00010110), "adds8",
0, OP_ALU, B8(00010111), "adds16",
0, OP_ALU, B8(00011000), "exts",
0, OP_ALU, B8(00011001), "neg",
0, OP_ALU, B8(00011010), "lsr",
0, OP_ALU, B8(00011011), "log2",
0, OP_ALU, B8(00011100), "lsl",
0, OP_ALU, B8(00011101), "brev",
0, OP_ALU, B8(00011110), "asr",
0, OP_ALU, B8(00011111), "abs",
0, OP_MISC, B16(11001000,00000000), "fadd",
0, OP_MISC, B16(11001000,00100000), "fsub",
0, OP_MISC, B16(11001000,01000000), "fmul",
0, OP_MISC, B16(11001000,01100000), "fdiv",
0, OP_MISC, B16(11001000,10000000), "fcmp",
0, OP_MISC, B16(11001000,10100000), "fabs",
0, OP_MISC, B16(11001000,11000000), "frsb",
0, OP_MISC, B16(11001000,11100000), "fmax",
0, OP_MISC, B16(11001001,00000000), "frcp",
0, OP_MISC, B16(11001001,00100000), "frsqrt",
0, OP_MISC, B16(11001001,01000000), "fnmul",
0, OP_MISC, B16(11001001,01100000), "fmin",
0, OP_MISC, B16(11001001,10000000), "fld1",
0, OP_MISC, B16(11001001,10100000), "fld0",
0, OP_MISC, B16(11001001,11000000), "log2",
0, OP_MISC, B16(11001001,11100000), "exp2",
0, OP_MISC, B16(11000101,11100000), "adds256",
0, OP_FLTCNV, B16(11001010,00000000), "ftrunc",
0, OP_FLTCNV, B16(11001010,00100000), "floor",
0, OP_FLTCNV, B16(11001010,01000000), "flts",
0, OP_FLTCNV, B16(11001010,01100000), "fltu",
0, OP_MISCL, B16(11000100,10000000), "divs",
0, OP_MISCL, B16(11000100,11100000), "divu",
0, OP_STACK, B16(00000010,10000000), "push",
0, OP_STACK, B16(00000010,00000000), "pop",
0, OP_MEM, B8(00000000), "ld",
0, OP_MEM, B8(00000001), "st",
0, OP_MEM, B8(00000010), "ldh",
0, OP_MEM, B8(00000011), "sth",
0, OP_MEM, B8(00000100), "ldb",
0, OP_MEM, B8(00000101), "stb",
0, OP_MEM, B8(00000110), "ldhs",
0, OP_MEM, B8(00000111), "sths",
0, OP_LEA, 0, "lea",

87
mach/vc4/as/mach4.c Normal file
View file

@ -0,0 +1,87 @@
/*
* VideoCore IV assembler for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
operation
: OP { emit2($1); }
| OP_BRANCH GPR { emit2(B16(00000000,01000000) | ($2<<0)); }
| OP_BRANCHLINK GPR { emit2(B16(00000000,01100000) | ($2<<0)); }
| OP_BRANCH expr { branch_instr(0, ALWAYS, &$2); }
| OP_BRANCHLINK expr { branch_instr(1, ALWAYS, &$2); }
| OP_BRANCH CC expr { branch_instr(0, $2, &$3); }
| OP_BRANCHLINK CC expr { branch_instr(1, $2, &$3); }
| OP_BRANCH GPR ',' GPR ',' expr { branch_addcmp_lit_reg_instr(ALWAYS, $2, 0, $4, &$6); }
| OP_BRANCH CC GPR ',' GPR ',' expr { branch_addcmp_lit_reg_instr($2, $3, 0, $5, &$7); }
| OP_BRANCH GPR ',' '#' absexp ',' expr { branch_addcmp_lit_lit_instr(ALWAYS, $2, 0, $5, &$7); }
| OP_BRANCH CC GPR ',' '#' absexp ',' expr { branch_addcmp_lit_lit_instr($2, $3, 0, $6, &$8); }
| OP_ADDCMPB GPR ',' GPR ',' GPR ',' expr { branch_addcmp_reg_reg_instr(ALWAYS, $2, $4, $6, &$8); }
| OP_ADDCMPB CC GPR ',' GPR ',' GPR ',' expr { branch_addcmp_reg_reg_instr($2, $3, $5, $7, &$9); }
| OP_ADDCMPB GPR ',' '#' absexp ',' GPR ',' expr { branch_addcmp_lit_reg_instr(ALWAYS, $2, $5, $7, &$9); }
| OP_ADDCMPB CC GPR ',' '#' absexp ',' GPR ',' expr { branch_addcmp_lit_reg_instr($2, $3, $6, $8, &$10); }
| OP_ADDCMPB GPR ',' GPR ',' '#' absexp ',' expr { branch_addcmp_reg_lit_instr(ALWAYS, $2, $4, $7, &$9); }
| OP_ADDCMPB CC GPR ',' GPR ',' '#' absexp ',' expr { branch_addcmp_reg_lit_instr($2, $3, $5, $8, &$10); }
| OP_ADDCMPB GPR ',' '#' absexp ',' '#' absexp ',' expr { branch_addcmp_lit_lit_instr(ALWAYS, $2, $5, $8, &$10); }
| OP_ADDCMPB CC GPR ',' '#' absexp ',' '#' absexp ',' expr { branch_addcmp_lit_lit_instr($2, $3, $6, $9, &$11); }
| OP_ONELREG GPR
{
if ($2 >= 0x10)
serror("cannot use r16+ here");
emit2($1 | ($2<<0));
}
| OP_ALU GPR ',' GPR { alu_instr_reg($1, ALWAYS, $2, $2, $4); }
| OP_ALU GPR ',' GPR ',' GPR { alu_instr_reg($1, ALWAYS, $2, $4, $6); }
| OP_ALU CC GPR ',' GPR { alu_instr_reg($1, $2, $3, $3, $5); }
| OP_ALU CC GPR ',' GPR ',' GPR { alu_instr_reg($1, $2, $3, $5, $7); }
| OP_ALU GPR ',' '#' absexp { alu_instr_lit($1, ALWAYS, $2, $2, $5); }
| OP_ALU GPR ',' GPR ',' '#' absexp { alu_instr_lit($1, ALWAYS, $2, $4, $7); }
| OP_ALU CC GPR ',' '#' absexp { alu_instr_lit($1, $2, $3, $3, $6); }
| OP_ALU CC GPR ',' GPR ',' '#' absexp { alu_instr_lit($1, $2, $3, $5, $8); }
| OP_MISC GPR ',' GPR ',' GPR { misc_instr_reg($1, ALWAYS, $2, $4, $6); }
| OP_MISC CC GPR ',' GPR ',' GPR { misc_instr_reg($1, $2, $3, $5, $7); }
| OP_MISCL GPR ',' GPR ',' GPR { misc_instr_reg($1, ALWAYS, $2, $4, $6); }
| OP_MISCL CC GPR ',' GPR ',' GPR { misc_instr_reg($1, $2, $3, $5, $7); }
| OP_MISCL GPR ',' GPR ',' '#' absexp { misc_instr_lit($1, ALWAYS, $2, $4, $7); }
| OP_MISCL CC GPR ',' GPR ',' '#' absexp { misc_instr_lit($1, $2, $3, $5, $8); }
| OP_STACK GPR { stack_instr($1, $2, $2, -1); }
| OP_STACK GPR ',' GPR { stack_instr($1, $2, $2, $4); }
| OP_STACK GPR '-' GPR { stack_instr($1, $2, $4, -1); }
| OP_STACK GPR '-' GPR ',' GPR { stack_instr($1, $2, $4, $6); }
| OP_MEM GPR ',' '(' GPR ')' { mem_instr($1, ALWAYS, $2, 0, $5); }
| OP_MEM CC GPR ',' '(' GPR ')' { mem_instr($1, $2, $3, 0, $6); }
| OP_MEM GPR ',' absexp '(' GPR ')' { mem_instr($1, ALWAYS, $2, $4, $6); }
| OP_MEM CC GPR ',' absexp '(' GPR ')' { mem_instr($1, $2, $3, $5, $7); }
| OP_MEM GPR ',' '(' GPR ',' GPR ')' { mem_offset_instr($1, ALWAYS, $2, $5, $7); }
| OP_MEM CC GPR ',' '(' GPR ',' GPR ')' { mem_offset_instr($1, $2, $3, $6, $8); }
| OP_MEM GPR ',' '(' GPR ')' '+' '+' { mem_postincr_instr($1, ALWAYS, $2, $5); }
| OP_MEM CC GPR ',' '(' GPR ')' '+' '+' { mem_postincr_instr($1, $2, $3, $6); }
| OP_MEM GPR ',' expr { mem_address_instr($1, $2, &$4); }
| OP_LEA GPR ',' absexp '(' GPR ')' { lea_stack_instr($2, $4, $6); }
| OP_LEA GPR ',' expr { lea_address_instr($2, &$4); }
| OP_FLTCNV GPR ',' GPR { fltcnv_instr($1, ALWAYS, $2, $4, 0); }
| OP_FLTCNV CC GPR ',' GPR { fltcnv_instr($1, $2, $3, $5, 0); }
| OP_FLTCNV GPR ',' GPR ',' shift '#' absexp { fltcnv_instr($1, ALWAYS, $2, $4, $8); }
| OP_FLTCNV CC GPR ',' GPR ',' shift '#' absexp { fltcnv_instr($1, $2, $3, $5, $9); }
;
shift
: 'l' 's' 'r'
| 'l' 's' 'l';

501
mach/vc4/as/mach5.c Normal file
View file

@ -0,0 +1,501 @@
/*
* VideoCore IV assembler for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdint.h>
#define maskx(v, x) (v & ((1<<(x))-1))
static void toobig(void)
{
serror("offset too big to encode into instruction");
}
/* Assemble an ALU instruction where rb is a register. */
void alu_instr_reg(quad op, int cc, int rd, int ra, int rb)
{
/* Can we use short form? */
if ((cc == ALWAYS) && (ra == rd) && (ra < 0x10) && (rb < 0x10))
{
emit2(B16(01000000,00000000) | (op<<8) | (rb<<4) | (rd<<0));
return;
}
/* Long form, then. */
emit2(B16(11000000,00000000) | (op<<5) | (rd<<0));
emit2(B16(00000000,00000000) | (ra<<11) | (cc<<7) | (rb<<0));
}
/* Assemble an ALU instruction where rb is a literal. */
void alu_instr_lit(quad op, int cc, int rd, int ra, long value)
{
/* 16 bit short form? */
if ((cc == ALWAYS) && !(op & 1) && (value >= 0) && (value <= 0x1f) &&
(ra == rd) && (ra < 0x10))
{
emit2(B16(01100000,00000000) | (op<<8) | (value<<4) | (rd<<0));
return;
}
/* 32 bit medium form? */
if ((value >= 0) && (value <= 0x1f))
{
emit2(B16(11000000,00000000) | (op<<5) | (rd<<0));
emit2(B16(00000000,01000000) | (ra<<11) | (cc<<7) | (value<<0));
return;
}
/* Long form, then. */
if (cc != ALWAYS)
serror("cannot use condition codes with ALU literals this big");
/* add is special. */
if (op == B8(00000010))
emit2(B16(11101100,00000000) | (ra<<5) | (rd<<0));
else
{
if (ra != rd)
serror("can only use 2op form of ALU instructions with literals this big");
emit2(B16(11101000,00000000) | (op<<5) | (rd<<0));
}
emit4(value);
}
/* Miscellaneous instructions with three registers and a cc. */
void misc_instr_reg(quad op, int cc, int rd, int ra, int rb)
{
emit2(op | (rd<<0));
emit2(B16(00000000,00000000) | (ra<<11) | (cc<<7) | (rb<<0));
}
/* Miscellaneous instructions with two registers, a literal, and a cc. */
void misc_instr_lit(quad op, int cc, int rd, int ra, quad value)
{
if (value < 0x1f)
serror("only constants from 0..31 can be used here");
emit2(op | (rd<<0));
emit2(B16(00000000,01000000) | (ra<<11) | (cc<<7) | (value<<0));
}
/* Assemble a branch instruction. This may be a near branch into this
* object file, or a far branch which requires a fixup. */
void branch_instr(int bl, int cc, struct expr_t* expr)
{
quad pc = DOTVAL;
quad type = expr->typ & S_TYP;
int d;
/* Sanity checking. */
if (bl && (cc != ALWAYS))
serror("can't use condition codes with bl");
if (type == S_ABS)
serror("can't use absolute addresses here");
/* The VC4 branch instructions express distance in 2-byte
* words. */
d = (int32_t)expr->val - (int32_t)pc;
if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
d -= DOTGAIN;
d /= 2;
/* If this is a reference to code within this section, and it's
* close enough to the program counter, we can use a short-
* form instruction. */
if (small(!bl && (type == DOTTYP) && fitx(d, 7), 2))
{
emit2(B16(00011000,00000000) | (cc<<7) | (d&0x7f));
return;
}
/* Absolute addresses and references to other sections
* need the full 32 bits. */
newrelo(expr->typ, RELOVC4|RELPC);
if (bl)
{
quad v, hiv, lov;
if (!fitx(d, 27))
toobig();
v = maskx(d, 27);
hiv = v >> 23;
lov = v & 0x007fffff;
emit2(B16(10010000,10000000) | (lov>>16) | (hiv<<8));
emit2(B16(00000000,00000000) | (lov&0xffff));
}
else
{
quad v;
if (!fitx(d, 23))
toobig();
v = maskx(d, 23);
emit2(B16(10010000,00000000) | (cc<<8) | (v>>16));
emit2(B16(00000000,00000000) | (v&0xffff));
}
}
/* Push/pop. */
void stack_instr(quad opcode, int loreg, int hireg, int extrareg)
{
int b;
int m;
switch (loreg)
{
case 0: b = 0; break;
case 6: b = 1; break;
case 16: b = 2; break;
case 24: b = 3; break;
case 26: /* lr */
extrareg = 26;
hireg = loreg = -1;
break;
case 31: /* pc */
extrareg = 31;
hireg = loreg = -1;
break;
default:
serror("base register for push or pop may be only r0, r6, r16, r24, lr or pc");
}
if (opcode & 0x0080)
{
/* Push */
if (extrareg == 31)
serror("cannot push pc");
}
else
{
/* Pop */
if (extrareg == 26)
serror("cannot pop lr");
}
if (hireg < loreg)
serror("invalid register range");
if (hireg == -1)
{
b = 3;
m = 15;
}
else
m = hireg - loreg;
emit2(opcode | (b<<5) | (m<<0) | ((extrareg != -1) ? 0x0100 : 0));
}
/* Memory operations where the offset is a fixed value (including zero). */
void mem_instr(quad opcode, int cc, int rd, long offset, int rs)
{
quad uoffset = (quad) offset;
int multiple4 = !(offset & 3);
int intonly = ((opcode & B8(00000110)) == 0);
/* If no CC, there are some special forms we can use. */
if (cc == ALWAYS)
{
/* Very short form, special for stack offsets. */
if (intonly && (rs == 25) && multiple4 && fitx(offset, 7) && (rd < 0x10))
{
quad o = maskx(offset, 7) / 4;
emit2(B16(00000100,00000000) | (opcode<<9) | (o<<4) | (rd<<0));
return;
}
/* Slightly longer form for directly dereferencing via a register. */
if ((rs < 0x10) && (rd < 0x10) && (offset == 0))
{
emit2(B16(00001000,00000000) | (opcode<<8) | (rs<<4) | (rd<<0));
return;
}
/* Integer only, but a limited offset. */
if (intonly && (uoffset <= 0x3f) && (rs < 0x10) && (rd < 0x10))
{
quad o = uoffset / 4;
emit2(B16(00100000,00000000) | (opcode<<12) | (o<<8) |
(rs<<4) | (rd<<0));
return;
}
/* Certain registers support 16-bit offsets. */
if (fitx(offset, 16))
{
switch (rs)
{
case 0: opcode = B16(10101011,00000000) | (opcode<<5); goto specialreg;
case 24: opcode = B16(10101000,00000000) | (opcode<<5); goto specialreg;
case 25: opcode = B16(10101001,00000000) | (opcode<<5); goto specialreg;
case 31: opcode = B16(10101010,00000000) | (opcode<<5); goto specialreg;
default: break;
specialreg:
{
quad o = maskx(offset, 16);
emit2(opcode | (rd<<0));
emit2(o);
return;
}
}
}
/* 12-bit displacements. */
if (fitx(offset, 12))
{
quad looffset = maskx(offset, 11);
quad hioffset = (offset >> 11) & 1;
emit2(B16(10100010,00000000) | (opcode<<5) | (rd<<0) | (hioffset<<8));
emit2(B16(00000000,00000000) | (rs<<11) | (looffset<<0));
return;
}
/* Everything else uses Very Long Form. */
if (!fitx(offset, 27))
serror("offset will not fit into load/store instruction");
if (rs == 31)
opcode = B16(11100111,00000000) | (opcode<<5);
else
opcode = B16(11100110,00000000) | (opcode<<5);
emit2(opcode | (rd<<0));
emit4((rs<<27) | maskx(offset, 27));
return;
}
/* Now we're on to load/store instructions with ccs. */
if (uoffset <= 0x1f)
{
emit2(B16(10100000,00000000) | (opcode<<5) | (rd<<0));
emit2(B16(00000000,01000000) | (rs<<11) | (cc<<7) | (uoffset<<0));
return;
}
/* No encoding for this instruction. */
serror("invalid load/store instruction");
}
/* Memory operations where the destination address is a sum of two
* registers. */
void mem_offset_instr(quad opcode, int cc, int rd, int ra, int rb)
{
emit2(B16(10100000,00000000) | (opcode<<5) | (rd<<0));
emit2(B16(00000000,00000000) | (ra<<11) | (cc<<7) | (rb<<0));
}
/* Memory operations with postincrement. */
void mem_postincr_instr(quad opcode, int cc, int rd, int rs)
{
emit2(B16(10100101,00000000) | (opcode<<5) | (rd<<0));
emit2(B16(00000000,00000000) | (rs<<11) | (cc<<7));
}
/* Memory operations where the destination is an address literal. */
void mem_address_instr(quad opcode, int rd, struct expr_t* expr)
{
static const char sizes[] = {4, 4, 2, 2, 1, 1, 2, 2};
int size = sizes[opcode];
quad type = expr->typ & S_TYP;
int d, scaledd;
/* Sanity checking. */
if (type == S_ABS)
serror("can't use absolute addresses here");
d = expr->val - DOTVAL;
if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
d -= DOTGAIN;
scaledd = d/size;
/* If this is a reference to an address within this section, and
* it's close enough to the program counter, we can use a
* shorter instruction. */
if (small((type==DOTTYP) && fitx(scaledd, 16), 2))
{
emit2(B16(10101010,00000000) | (opcode<<5) | (rd<<0));
emit2(scaledd);
return;
}
/* Otherwise we need the full 48 bits. */
newrelo(expr->typ, RELOVC4|RELPC);
/* VC4 relocations store the PC-relative delta into the
* destination section in the instruction data. The linker will
* massage this, and scale it appropriately. */
if (!fitx(d, 27))
toobig();
emit2(B16(11100111,00000000) | (opcode<<5) | (rd<<0));
emit4((31<<27) | maskx(d, 27));
}
/* Common code for handling addcmp: merge in as much of expr as will fit to
* the second pair of the addcmp opcode. */
static void branch_addcmp_common(quad opcode, int bits, struct expr_t* expr)
{
quad type = expr->typ & S_TYP;
int d;
if ((pass>0) && (type != DOTTYP))
serror("can't use this type of branch to jump outside the section");
/* The VC4 branch instructions express distance in 2-byte
* words. */
d = (expr->val - DOTVAL-2 + 4);
if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
d -= DOTGAIN;
d /= 2;
if ((pass == 2) && !fitx(d, bits))
serror("target of branch is too far away");
emit2(opcode | maskx(d, bits));
}
void branch_addcmp_reg_reg_instr(int cc, int rd, int ra, int rs, struct expr_t* expr)
{
if ((rd >= 0x10) || (ra >= 0x10) || (rs >= 0x10))
serror("can only use r0-r15 in this instruction");
emit2(B16(10000000,00000000) | (cc<<8) | (ra<<4) | (rd<<0));
branch_addcmp_common(B16(00000000,00000000) | (rs<<10), 10, expr);
}
void branch_addcmp_lit_reg_instr(int cc, int rd, long va, int rs, struct expr_t* expr)
{
if ((rd >= 0x10) || (rs >= 0x10))
serror("can only use r0-r15 in this instruction");
if (!fitx(va, 4))
serror("value too big to encode into instruction");
va = maskx(va, 4);
emit2(B16(10000000,00000000) | (cc<<8) | (va<<4) | (rd<<0));
branch_addcmp_common(B16(01000000,00000000) | (rs<<10), 10, expr);
}
void branch_addcmp_reg_lit_instr(int cc, int rd, int ra, long vs, struct expr_t* expr)
{
if ((rd >= 0x10) || (ra >= 0x10))
serror("can only use r0-r15 in this instruction");
if (!fitx(vs, 6))
serror("value too big to encode into instruction");
vs = maskx(vs, 6);
emit2(B16(10000000,00000000) | (cc<<8) | (ra<<4) | (rd<<0));
branch_addcmp_common(B16(10000000,00000000) | (vs<<8), 8, expr);
}
void branch_addcmp_lit_lit_instr(int cc, int rd, long va, long vs, struct expr_t* expr)
{
if (rd >= 0x10)
serror("can only use r0-r15 in this instruction");
if (!fitx(va, 4) || !fitx(vs, 6))
serror("value too big to encode into instruction");
va = maskx(va, 4);
vs = maskx(vs, 6);
emit2(B16(10000000,00000000) | (cc<<8) | (va<<4) | (rd<<0));
branch_addcmp_common(B16(11000000,00000000) | (vs<<8), 8, expr);
}
/* lea, where the source is relative to the stack. */
void lea_stack_instr(int rd, long va, int rs)
{
if (rs != 25)
serror("source register must be sp");
va /= 4;
if (!fitx(va, 6))
serror("offset too big to encode in instruction");
va = maskx(va, 6);
emit2(B16(00010000,00000000) | (rd<<0) | (va<<5));
}
/* lea, where the source is an address. */
void lea_address_instr(int rd, struct expr_t* expr)
{
quad pc = DOTVAL;
quad type = expr->typ & S_TYP;
int d = expr->val - pc;
if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
d -= DOTGAIN;
if (type == S_ABS)
serror("can't use absolute addresses here");
newrelo(expr->typ, RELOVC4|RELPC);
/* VC4 relocations store the PC-relative delta into the
* destination section in the instruction data. The linker will
* massage this, and scale it appropriately. */
emit2(B16(11100101,00000000) | (rd<<0));
emit4(expr->val - pc);
}
/* Floating point conversion opcodes (ftrunc, floor, flts, fltu). */
void fltcnv_instr(quad opcode, int cc, int rd, int ra, quad shift)
{
fitx(shift, 6);
emit2(opcode | (rd<<0));
emit2(B16(00000000,01000000) | (ra<<11) | (cc<<7) | shift);
}

11
mach/vc4/build.mk Normal file
View file

@ -0,0 +1,11 @@
arch-libem-vc4 := \
csa.s \
csb.s
arch-libend-vc4 = \
edata.s \
em_end.s \
end.s \
etext.s

3
mach/vc4/libem/.distr Normal file
View file

@ -0,0 +1,3 @@
csa.s
csb.s
videocore.h

36
mach/vc4/libem/csa.s Normal file
View file

@ -0,0 +1,36 @@
#
/*
* VideoCore IV support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include "videocore.h"
.define .csa
.sect .data
.csa:
! on entry:
! r0 = un-fixed-up descriptor
! r1 = value
add r0, gp
ld r2, 4 (r0) ! check lower bound
b.lo r1, r2, default ! jump to default if r1 < r2
sub r1, r2 ! adjust value to be 0-based
ld r2, 8 (r0) ! check upper bound
b.hi r1, r2, default ! jump to default if r1 > r2
add r1, #3
go:
ld r1, (r0, r1) ! load destination address
add r1, gp
b r1 ! ...and go
default:
mov r1, #0 ! index of default value
b go

33
mach/vc4/libem/csb.s Normal file
View file

@ -0,0 +1,33 @@
#
/*
* VideoCore IV support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include "videocore.h"
.define .csb
.sect .data
.csb:
! on entry:
! r0 = un-fixed-up descriptor
! r1 = value
add r0, gp ! r0 = fixed up descriptor
adds8 r2, r0, #1 ! r2 = moving pointer
ld r3, 4 (r0) ! r3 = count
adds8 r3, r0, r3 ! r3 = end ptr
loop:
ld r4, (r2)++
b.eq r4, r1, matched ! r2 points at matching addr
addcmpb.le r2, #4, r3, loop
notmatched:
mov r2, r0 ! r2 points at default jump
matched:
ld r2, (r2) ! load destination address
add r2, gp ! fix up r2
b r2 ! ...and go

View file

@ -0,0 +1,17 @@
#
/*
* VideoCore IV support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
#define gp r15

4
mach/vc4/libend/.distr Normal file
View file

@ -0,0 +1,4 @@
edata.s
em_end.s
end.s
etext.s

15
mach/vc4/libend/edata.s Normal file
View file

@ -0,0 +1,15 @@
#
/*
* VideoCore IV support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
.sect .text
.sect .rom
.sect .data
.sect .bss
.define _edata
.sect .data
_edata:

24
mach/vc4/libend/em_end.s Normal file
View file

@ -0,0 +1,24 @@
#
/*
* VideoCore IV support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .end ! only for declaration of _end, __end and endbss.
.define endtext, endrom, enddata, endbss, __end
.sect .text
endtext:
.sect .rom
endrom:
.sect .data
enddata:
.sect .end
__end:
endbss:

15
mach/vc4/libend/end.s Normal file
View file

@ -0,0 +1,15 @@
#
/*
* VideoCore IV support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
.sect .text
.sect .rom
.sect .data
.sect .bss
.define _end
.sect .end ! only for declaration of _end, __end and endbss.
_end:

15
mach/vc4/libend/etext.s Normal file
View file

@ -0,0 +1,15 @@
#
/*
* VideoCore IV support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
.sect .text
.sect .rom
.sect .data
.sect .bss
.define _etext
.sect .text
_etext:

3
mach/vc4/ncg/.distr Normal file
View file

@ -0,0 +1,3 @@
mach.c
mach.h
table

86
mach/vc4/ncg/mach.c Normal file
View file

@ -0,0 +1,86 @@
/*
* VideoCore IV code generator for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <limits.h>
int framesize;
/* Write out a constant data section. */
con_part(int sz, word w)
{
while (part_size % sz)
part_size++;
if (part_size == TEM_WSIZE)
part_flush();
if (sz == 1 || sz == 2) {
w &= (sz == 1 ? 0xFF : 0xFFFF);
w <<= 8 * part_size;
part_word |= w;
} else {
assert(sz == 4);
part_word = w;
}
part_size += sz;
}
con_mult(word sz)
{
if (argval != 4)
fatal("bad icon/ucon size");
fprintf(codefile,".data4 %s\n", str);
}
#define CODE_GENERATOR
#define IEEEFLOAT
#define FL_MSL_AT_LOW_ADDRESS 0
#define FL_MSW_AT_LOW_ADDRESS 0
#define FL_MSB_AT_LOW_ADDRESS 0
#include <con_float>
void prolog(full nlocals)
{
int ss = nlocals + 8;
fprintf(codefile, "push fp, lr\n");
fprintf(codefile, "mov fp, sp\n");
if (nlocals > 0)
fprintf(codefile, "sub sp, #%d\n", nlocals);
framesize = nlocals;
}
mes(word type)
{
int argt ;
switch ( (int)type ) {
case ms_ext :
for (;;) {
switch ( argt=getarg(
ptyp(sp_cend)|ptyp(sp_pnam)|sym_ptyp) ) {
case sp_cend :
return ;
default:
strarg(argt) ;
fprintf(codefile,".define %s\n",argstr) ;
break ;
}
}
default :
while ( getarg(any_ptyp) != sp_cend ) ;
break ;
}
}
char *segname[] = {
".sect .text",
".sect .data",
".sect .rom",
".sect .bss"
};

32
mach/vc4/ncg/mach.h Normal file
View file

@ -0,0 +1,32 @@
/*
* VideoCore IV code generator for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#define ex_ap(y) fprintf(codefile,".extern %s\n",y)
#define in_ap(y) /* nothing */
#define newilb(x) fprintf(codefile,"%s:\n",x)
#define newdlb(x) fprintf(codefile,"%s:\n",x)
#define dlbdlb(x,y) fprintf(codefile,"%s = %s\n",x,y)
#define newlbss(l,x) fprintf(codefile,".comm %s,%u\n",l,x);
#define cst_fmt "%d"
#define off_fmt "%d"
#define ilb_fmt "I%x_%x"
#define dlb_fmt "_%d"
#define hol_fmt "hol%d"
#define hol_off "%ld+hol%d"
#define con_cst(x) fprintf(codefile,".data4\t%ld\n",x)
#define con_ilb(x) fprintf(codefile,".data4\t%s\n",x)
#define con_dlb(x) fprintf(codefile,".data4\t%s\n",x)
#define fmt_id(sf, st) sprintf(st,"_%s",sf)
#define modhead ".sect .text; .sect .rom; .sect .data; .sect .bss\n"
#define BSS_INIT 0

1560
mach/vc4/ncg/table Normal file

File diff suppressed because it is too large Load diff

362
mach/vc4/test/opcodes.s Normal file
View file

@ -0,0 +1,362 @@
#
/*
* VideoCore IV assembler test file
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
main:
nop
rti
b r0
b r31
bl r0
bl r31
tbb r0
tbb r15
tbs r0
tbs r15
nop
mov r0, r1
cmn r0, r1
add r0, r1
bic r0, r1
mul r0, r1
eor r0, r1
sub r0, r1
and r0, r1
mvn r0, r1
ror r0, r1
cmp r0, r1
rsb r0, r1
btst r0, r1
or r0, r1
extu r0, r1
max r0, r1
bset r0, r1
min r0, r1
bclr r0, r1
adds2 r0, r1
bchg r0, r1
adds4 r0, r1
adds8 r0, r1
adds16 r0, r1
exts r0, r1
neg r0, r1
lsr r0, r1
clz r0, r1
lsl r0, r1
brev r0, r1
asr r0, r1
abs r0, r1
nop
mov.f r0, r1
cmn.f r0, r1
add.f r0, r1
bic.f r0, r1
mul.f r0, r1
eor.f r0, r1
sub.f r0, r1
and.f r0, r1
mvn.f r0, r1
ror.f r0, r1
cmp.f r0, r1
rsb.f r0, r1
btst.f r0, r1
or.f r0, r1
extu.f r0, r1
max.f r0, r1
bset.f r0, r1
min.f r0, r1
bclr.f r0, r1
adds2.f r0, r1
bchg.f r0, r1
adds4.f r0, r1
adds8.f r0, r1
adds16.f r0, r1
exts.f r0, r1
neg.f r0, r1
lsr.f r0, r1
clz.f r0, r1
lsl.f r0, r1
brev.f r0, r1
asr.f r0, r1
abs.f r0, r1
nop
mov r0, r1, r2
cmn r0, r1, r2
add r0, r1, r2
bic r0, r1, r2
mul r0, r1, r2
eor r0, r1, r2
sub r0, r1, r2
and r0, r1, r2
mvn r0, r1, r2
ror r0, r1, r2
cmp r0, r1, r2
rsb r0, r1, r2
btst r0, r1, r2
or r0, r1, r2
extu r0, r1, r2
max r0, r1, r2
bset r0, r1, r2
min r0, r1, r2
bclr r0, r1, r2
adds2 r0, r1, r2
bchg r0, r1, r2
adds4 r0, r1, r2
adds8 r0, r1, r2
adds16 r0, r1, r2
exts r0, r1, r2
neg r0, r1, r2
lsr r0, r1, r2
clz r0, r1, r2
lsl r0, r1, r2
brev r0, r1, r2
asr r0, r1, r2
abs r0, r1, r2
nop
mov r0, #0x1f
cmn r0, #0x1f
add r0, #0x1f
bic r0, #0x1f
mul r0, #0x1f
eor r0, #0x1f
sub r0, #0x1f
and r0, #0x1f
mvn r0, #0x1f
ror r0, #0x1f
cmp r0, #0x1f
rsb r0, #0x1f
btst r0, #0x1f
or r0, #0x1f
extu r0, #0x1f
max r0, #0x1f
bset r0, #0x1f
min r0, #0x1f
bclr r0, #0x1f
adds2 r0, #0x1f
bchg r0, #0x1f
adds4 r0, #0x1f
adds8 r0, #0x1f
adds16 r0, #0x1f
exts r0, #0x1f
neg r0, #0x1f
lsr r0, #0x1f
clz r0, #0x1f
lsl r0, #0x1f
brev r0, #0x1f
asr r0, #0x1f
abs r0, #0x1f
nop
mov.f r0, #0x1f
cmn.f r0, #0x1f
add.f r0, #0x1f
bic.f r0, #0x1f
mul.f r0, #0x1f
eor.f r0, #0x1f
sub.f r0, #0x1f
and.f r0, #0x1f
mvn.f r0, #0x1f
ror.f r0, #0x1f
cmp.f r0, #0x1f
rsb.f r0, #0x1f
btst.f r0, #0x1f
or.f r0, #0x1f
extu.f r0, #0x1f
max.f r0, #0x1f
bset.f r0, #0x1f
min.f r0, #0x1f
bclr.f r0, #0x1f
adds2.f r0, #0x1f
bchg.f r0, #0x1f
adds4.f r0, #0x1f
adds8.f r0, #0x1f
adds16.f r0, #0x1f
exts.f r0, #0x1f
neg.f r0, #0x1f
lsr.f r0, #0x1f
clz.f r0, #0x1f
lsl.f r0, #0x1f
brev.f r0, #0x1f
asr.f r0, #0x1f
abs.f r0, #0x1f
add r0, #0x12345678
add r0, r1, #0x12345678
sub r0, #0x12345678
nop
fadd r0, r1, r2
fsub r0, r1, r2
fmul r0, r1, r2
fdiv r0, r1, r2
fcmp r0, r1, r2
fabs r0, r1, r2
frsb r0, r1, r2
fmax r0, r1, r2
frcp r0, r1, r2
frsqrt r0, r1, r2
fnmul r0, r1, r2
fmin r0, r1, r2
fld1 r0, r1, r2
fld0 r0, r1, r2
log2 r0, r1, r2
exp2 r0, r1, r2
divs r0, r1, r2
divu r0, r1, r2
divs r0, r1, #31
divu r0, r1, #31
adds256 r0, r1, r2
nop
fadd.f r0, r1, r2
fsub.f r0, r1, r2
fmul.f r0, r1, r2
fdiv.f r0, r1, r2
fcmp.f r0, r1, r2
fabs.f r0, r1, r2
frsb.f r0, r1, r2
fmax.f r0, r1, r2
frcp.f r0, r1, r2
frsqrt.f r0, r1, r2
fnmul.f r0, r1, r2
fmin.f r0, r1, r2
fld1.f r0, r1, r2
fld0.f r0, r1, r2
log2.f r0, r1, r2
exp2.f r0, r1, r2
divs.f r0, r1, r2
divu.f r0, r1, r2
divs.f r0, r1, #31
divu.f r0, r1, #31
adds256.f r0, r1, r2
label:
b label
b forward
b label
b main
b.f label
b.f forward
b.f main
bl label
bl forward
bl main
forward:
push r0
push r0, lr
push r0-r5
push r0-r5, lr
push r6
push r16
push r24
push lr
pop r0
pop r0, pc
pop r0-r5
pop r0-r5, pc
pop r6
pop r16
pop r24
pop pc
nop
ld r0, (sp)
st r0, (sp)
ld r0, 4(sp)
st r0, 4(sp)
ld r0, -4(sp)
st r0, -4(sp)
ld r0, 5(sp)
st r0, 5(sp)
ld r0, -5(sp)
st r0, -5(sp)
ld r0, (r1)
st r0, (r1)
ld r16, (r1)
st r16, (r1)
ldh r0, (r1)
sth r0, (r1)
ldb r0, (r1)
stb r0, (r1)
ldhs r0, (r1)
sths r0, (r1)
ldh r16, (r1)
sth r16, (r1)
ldb r16, (r1)
stb r16, (r1)
ldhs r16, (r1)
sths r16, (r1)
ld r0, 0x3c (r1)
st r0, 0x3c (r1)
ld r0, 0xfff (r1)
st r0, 0xfff (r1)
ld r1, 0xffff (r0)
st r1, 0xffff (r0)
ld r0, -1 (r1)
st r0, -1 (r1)
ld r16, 0x3c (r1)
st r16, 0x3c (r1)
ld r16, 0xfff (r1)
st r16, 0xfff (r1)
ld r16, 0xffff (r0)
st r16, 0xffff (r0)
ld r16, -1 (r1)
st r16, -1 (r1)
ld.f r0, (r1)
st.f r0, (r1)
ld.f r0, 8 (r1)
st.f r0, 8 (r1)
ld r0, (r1, r2)
st r0, (r1, r2)
ld.f r0, (pc, pc)
st.f r0, (pc, pc)
near:
ld r0, (r1)++
st r0, (r1)++
ld.f pc, (pc)++
st.f pc, (pc)++
ld r0, near
ld r0, main
st r0, near
st r0, main
ldb r0, near
ldb r0, main
stb r0, near
stb r0, main
b.eq r0, r1, near
b r0, r1, near
addcmpb r0, r1, r2, .
addcmpb r0, #1, r2, .
addcmpb r0, r1, #1, .
addcmpb r0, #1, #2, .

View file

@ -1,14 +1,8 @@
6500_as.6
6800_as.6
6805_as.6
6809_as.6
8080_as.6
z8000_as.6
i80_as.6
i86_as.6
i386_as.6
m68k2_as.6
ns_as.6
pdp_as.6
m68020_as.6
vc4_as.6
z80_as.6
em_cg.6
em_ncg.6
@ -17,4 +11,3 @@ libpc.7
head
pc_prlib.7
uni_ass.6
proto.make

45
man/vc4_as.6 Normal file
View file

@ -0,0 +1,45 @@
.\" $Header$
.TH VC4_AS 1
.ad
.SH NAME
vc4_as \- assembler for Broadcom VideoCore IV
.SH SYNOPSIS
/usr/em/lib/vc4_as [options] argument ...
.SH DESCRIPTION
This assembler is made with the general framework
described in \fIuni_ass\fP(6).
.SH SYNTAX
The assembler uses a modified version of the syntax described in
https://github.com/hermanhermitage/videocoreiv/wiki/VideoCore-IV-Programmers-Manual:
condition codes must be prefixed with a full stop. Vector instructions are not
yet supported.
.SH "SEE ALSO"
uni_ass(6),
ack(1),
.br
https://github.com/hermanhermitage/videocoreiv
.SH EXAMPLE
.nf
.ta 8n 16n 24n 32n 40n 48n
An example of VideoCore IV assembly language:
ldb r0, __uart_status
b.eq r0, #0, 1b
! receive 1 byte (returned in r0)
mov r1, #AUX_MU_LSR_REG
mov r2, #AUX_MU_IO_REG
! loop until char available
recvwait:
ld r3, (r1)
and r3, #0x1
b.ne r3, #0x1, recvwait
ldb r0, (r2)
1:
b lr
.fi

View file

@ -3,11 +3,19 @@
# $Revision$
var w=2
var wa=1
var p=2
var pa=1
var s=2
var sa=1
var l=4
var la=1
var f=4
var fa=1
var d=8
var da=1
var x=8
var xa=1
var ARCH=i80
var PLATFORM=cpm
var PLATFORMDIR={EM}/share/ack/{PLATFORM}

View file

@ -3,11 +3,19 @@
# $Revision$
var w=4
var p=4
var wa=4
var p={w}
var pa={w}
var s=2
var l=4
var f=4
var sa={s}
var l={w}
var la={w}
var f={w}
var fa={w}
var d=8
var da={d}
var x=8
var xa={x}
var ARCH=i386
var PLATFORM=linux386
var PLATFORMDIR={EM}/share/ack/{PLATFORM}

View file

@ -3,11 +3,19 @@
# $Revision: 1.1 $
var w=4
var p=4
var wa=4
var p={w}
var pa={w}
var s=2
var l=4
var f=4
var sa={s}
var l={w}
var la={w}
var f={w}
var fa={w}
var d=8
var da={d}
var x=8
var xa={x}
var ARCH=m68020
var PLATFORM=linux68k
var PLATFORMDIR={EM}/share/ack/{PLATFORM}

View file

@ -3,11 +3,19 @@
# $Revision: 1.1 $
var w=4
var p=4
var wa=4
var p={w}
var pa={w}
var s=2
var l=4
var f=4
var sa={s}
var l={w}
var la={w}
var f={w}
var fa={w}
var d=8
var da={d}
var x=8
var xa={x}
var ARCH=powerpc
var PLATFORM=linuxppc
var PLATFORMDIR={EM}/share/ack/{PLATFORM}

View file

@ -3,11 +3,19 @@
# $Revision$
var w=2
var wa=1
var p=2
var pa=1
var s=2
var sa=1
var l=4
var la=1
var f=4
var fa=1
var d=8
var da=1
var x=8
var xa=1
var ARCH=i86
var PLATFORM=pc86
var PLATFORMDIR={EM}/share/ack/{PLATFORM}

31
plat/rpi/.distr Normal file
View file

@ -0,0 +1,31 @@
descr
boot.s
build.mk
README
include/ack/config.h
include/sys/select.h
include/unistd.h
include/pi.h
include/termios.h
libsys/brk.c
libsys/close.c
libsys/creat.c
libsys/errno.s
libsys/getpid.c
libsys/_hol0.s
libsys/isatty.c
libsys/kill.c
libsys/libsysasm.h
libsys/libsys.h
libsys/lseek.c
libsys/open.c
libsys/pi_phys_to_user.s
libsys/pi_uart.s
libsys/pi_user_to_phys.s
libsys/read.c
libsys/select.c
libsys/signal.c
libsys/tcgetattr.c
libsys/tcsetattr.c
libsys/time.c
libsys/write.c

69
plat/rpi/README Normal file
View file

@ -0,0 +1,69 @@
VideoCore IV support in the ACK
===============================
This is a fairly crude port of the ACK to produce VideoCore IV machine
code, suitable for use on the Raspberry Pi. It produces terrible but
working code. The resulting binaries can be used either bare metal or
loaded as a GPU kernel and executed using a modified mailbox.c (see below).
Currently floating point support is present but incomplete; and as the
VideoCore IV does not have double-precision float support, the C compiler
treats doubles as single precision.
As much of the standard C library as is relevant works; if
you're running in bare-metal mode, you can hook stdin/stdout up to the
mini UART. (Obviously, in kernel mode you can't.)
Important note! The malloc heap expects your program to be loaded into a
chunk of memory that's 128kB large. You must make sure that this is the case,
or Bad Stuff will happen.
Output binaries are fully PIC and can be loaded anywhere (this is one of the
things that makes the code so terrible). You must use the pi_user_to_phys()
and pi_phys_to_user() to translate pointers from physical to user and vice
versa. If you don't, Bad Stuff will happen.
Bare metal mode
---------------
To run a binary bare metal, compile it:
ack -mrpi -O program.c -o bootcode.bin
...and copy the bootcode.bin file to the root of an SD card. Boot the Pi.
Your program will run.
To use the UART, #include <pi.h> and call pi_init_uart() at the top of your
program. This will set it up and connect it to stdin/stdout. It's 115200 8n1.
Kernel mode
-----------
This will require some hacking at your end.
Go here, and follow the instructions.
https://github.com/hermanhermitage/videocoreiv/wiki/VideoCore-IV-Kernels-under-Linux
Now compile your program:
ack -mrpi -O program.c -o alpha.bin
MAKE SURE YOU AREN'T USING ANY MEMORY ALLOCATION. Copy the alpha.bin onto
the Pi, and run it with mailbox.c.
To get data in and out, #include <pi.h> and look at the pi_kernel_parameters
variable. It's a structure that is initialised with the data that's passed in
from mailbox.c (currently four pointers and two integers).
If you want to use malloc() and friends, you'll need to hack mailbox.c so
that the buffer containing the code is at least 128kB, or you're likely to
corrupt the VideoCore's workspace and crash it.
David Given <dg@cowlark.com>
2013-06-06

120
plat/rpi/boot.s Normal file
View file

@ -0,0 +1,120 @@
#
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#define gp r15
#define STACKSIZE 1*1024
! MAIN ENTRY POINT
begtext:
! This empty space is required by the boot loader.
kernel_start:
! When running as a kernel, we need to preserve all registers. We save
! them onto the default stack.
push r0-r24
b baremetal_start
.space 506 ! first 512 bytes are ignored by the boot loader
baremetal_start:
! Wipe the bss (including the new stack).
lea r6, begbss
lea r7, endbss
mov r8, #0
_1:
stb r8, (r6)
addcmpb.lt r6, #1, r7, _1
! Save system registers.
st fp, .returnfp
st sp, .returnsp
st lr, .returnlr
lea gp, begtext
lea sp, .stack + STACKSIZE
! Save the kernel parameters.
sub r0, gp ! fix up pointer
sub r1, gp ! fix up pointer
sub r2, gp ! fix up pointer
sub r3, gp ! fix up pointer
push r0-r5
sub r0, sp, gp
st r0, _pi_kernel_parameters
! Push standard parameters onto the stack and go.
mov r0, #0
push r0 ! envp
push r0 ! argv
push r0 ! argc
! Call the language startup code.
bl __m_a_i_n
! Fall through to __exit if this returns.
.define __exit
__exit:
! It only makes sense to get here if we're in kernel mode. If we're in
! bare-metal mode, we'll just crash, but that's fine.
st r0, _pi_kernel_parameters ! save return value
mov r0, sr
ld fp, .returnfp
ld sp, .returnsp
ld lr, .returnlr
pop r0-r24
ld r0, _pi_kernel_parameters ! restore return value
b lr
! Define symbols at the beginning of our various segments, so that we can find
! them. (Except .text, which has already been done.)
.define begtext, begdata, begbss
.sect .data; begdata:
.sect .rom; begrom:
.sect .bss; begbss:
! Some magic data. All EM systems need these.
.define .trppc, .ignmask, _errno
.comm .trppc, 4
.comm .ignmask, 4
.comm _errno, 4
! We store the stack pointer and return address on entry so that we can
! cleanly exit.
.comm .returnfp, 4
.comm .returnsp, 4
.comm .returnlr, 4
.define _pi_kernel_parameters
.comm _pi_kernel_parameters, 4
.define .linenumber, .filename
.comm .linenumber, 4 ! current linenumber (used for debugging)
.comm .filename, 4 ! ptr to current filename (used for debugging)
! User stack.
.comm .stack, STACKSIZE

52
plat/rpi/build.mk Normal file
View file

@ -0,0 +1,52 @@
# Build script for Raspberry Pi bare-metal executables (using the
# VideoCore IV processor, not the ARM).
#
# © 2013 David Given
# This file is redistributable under the terms of the 3-clause BSD license.
# See the file 'Copying' in the root of the distribution for the full text.
ARCH := vc4
PLATFORM := rpi
OPTIMISATION := -O
D := plat/rpi/
platform-headers := \
unistd.h \
termios.h \
pi.h \
ack/config.h
platform-libsys := \
_hol0.s \
errno.s \
pi_phys_to_user.s \
pi_user_to_phys.s \
pi_uart.s \
pi_fast_mode.s \
creat.c \
close.c \
open.c \
read.c \
write.c \
isatty.c \
brk.c \
getpid.c \
kill.c \
lseek.c \
time.c \
signal.c \
tcgetattr.c \
tcsetattr.c \
select.c
$(eval $(call build-platform))
define build-rpi-boot-impl
$(call reset)
$(call ackfile, $D/boot.s)
$(call installto, $(PLATIND)/$(PLATFORM)/boot.o)
endef
$(eval $(build-rpi-boot-impl))

77
plat/rpi/descr Normal file
View file

@ -0,0 +1,77 @@
# $Source$
# $State$
# $Revision$
var w=4
var wa=4
var p={w}
var pa={w}
var s=2
var sa={s}
var l={w}
var la={w}
var f={w}
var fa={w}
var d={w}
var da={w}
var x={w}
var xa={w}
var ARCH=vc4
var PLATFORM=rpi
var PLATFORMDIR={EM}/share/ack/{PLATFORM}
var CPP_F=-D__unix
var ALIGN=-a0:2 -a1:4 -a2:4 -a3:4
var MACHOPT_F=-m8
# Override the setting in fe so that files compiled for this platform can see
# the platform-specific headers.
var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi
name be
from .m.g
to .s
program {EM}/lib/ack/{PLATFORM}/ncg
args <
stdout
need .e
end
name as
from .s.so
to .o
program {EM}/lib/ack/{PLATFORM}/as
args - -o > <
prep cond
end
name led
from .o.a
to .out
program {EM}/lib/ack/em_led
mapflag -l* LNAME={PLATFORMDIR}/lib*
mapflag -i SEPID=-b1:0
mapflag -fp FLOATS={EM}/{ILIB}fp
args {ALIGN} {SEPID?} \
(.e:{HEAD}={PLATFORMDIR}/boot.o) \
({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
({RTS}:.mod={PLATFORMDIR}/modula2.o) \
({RTS}:.p={PLATFORMDIR}/pascal.o) \
-o > < \
(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
{FLOATS?} \
(.e:{TAIL}={PLATFORMDIR}/libem.a \
{PLATFORMDIR}/libsys.a \
{PLATFORMDIR}/libend.a)
linker
end
name cv
from .out
to .img
program {EM}/bin/aslod
args < >
outfile raspberrypi.bin
end

View file

@ -0,0 +1,11 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef _ACK_CONFIG_H
#define _ACK_CONFIG_H
#endif

48
plat/rpi/include/pi.h Normal file
View file

@ -0,0 +1,48 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef PI_H
#define PI_H
/* When running in kernel mode, this structure gets the incoming parameters.
* In bare metal mode, it's gibberish. */
struct pi_kernel_parameters
{
int r5;
int r4;
void* r3;
void* r2;
void* r1;
void* r0;
};
extern struct pi_kernel_parameters* pi_kernel_parameters;
/* Initialise the mini UART (only do this if running on bare metal! */
extern void pi_init_uart(void);
/* Converts a pointer from a physical address to a user address. */
extern void* pi_phys_to_user(void* ptr);
/* Converts a pointer from a user address to a physical address. */
extern void* pi_user_to_phys(void* ptr);
/* Change the clock speed from 19.2MHz to 250MHz. Must be called *before*
* pi_init_uart(). */
extern void pi_fast_mode(void);
/* Initialise the RAM. */
extern void pi_init_ram(void);
/* The current clock speed (used by pi_init_uart to calculate the correct
* UART settings). */
extern int pi_clock_speed;
#endif

View file

@ -0,0 +1,13 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef _SYS_SELECT_H
#define _SYS_SELECT_H
#include <unistd.h>
#endif

View file

@ -0,0 +1,47 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef _TERMIOS_H
#define _TERMIOS_H
typedef unsigned char tcflag_t;
struct termios
{
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_lflag;
tcflag_t c_cflag;
};
#define ONLCR 1
#define ECHO 2
#define INLCR 4
/* Dummied parameters for compatibility --- only the ones above are
* honoured. */
#define BRKINT 0
#define ICRNL 0
#define INPCK 0
#define ISTRIP 0
#define IXON 0
#define CS8 0
#define ICANON 0
#define IEXTEN 0
#define ISIG 0
#define OPOST ONLCR
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
extern int tcgetattr(int fd, struct termios* t);
extern int tcsetattr(int fd, int actions, struct termios* t);
#endif

105
plat/rpi/include/unistd.h Normal file
View file

@ -0,0 +1,105 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef _UNISTD_H
#define _UNISTD_H
#include <stddef.h>
#include <time.h>
/* Types */
typedef int pid_t;
typedef int mode_t;
typedef long suseconds_t;
/* Time handling. */
struct timeval
{
time_t tv_sec;
suseconds_t tv_usec;
};
struct timezone
{
int tz_minuteswest;
int tz_dsttime;
}; /* obsolete, unused */
extern int gettimeofday(struct timeval* tv, struct timezone* tz);
extern int settimeofday(const struct timeval* tv, const struct timezone* tz);
/* Constants for file access (open and friends) */
enum
{
O_ACCMODE = 0x3,
O_RDONLY = 0,
O_WRONLY = 1,
O_RDWR = 2,
O_CREAT = 0100,
O_TRUNC = 01000,
O_APPEND = 02000,
O_NONBLOCK = 04000
};
/* Special variables */
extern char** environ;
/* Implemented system calls */
extern void _exit(int);
extern pid_t getpid(void);
extern void* sbrk(intptr_t increment);
extern int isatty(int d);
extern off_t lseek(int fildes, off_t offset, int whence);
extern int close(int d);
extern int open(const char* path, int access, ...);
extern int creat(const char* path, mode_t mode);
extern int read(int fd, void* buffer, size_t count);
extern int write(int fd, void* buffer, size_t count);
/* Unimplemented system calls (these are just prototypes to let the library
* compile). */
extern int fcntl(int fd, int op, ...);
/* Signal handling */
typedef int sig_atomic_t;
#define SIG_ERR ((sighandler_t) -1) /* Error return. */
#define SIG_DFL ((sighandler_t) 0) /* Default action. */
#define SIG_IGN ((sighandler_t) 1) /* Ignore signal. */
#define SIGABRT 6 /* Abort (ANSI) */
#define SIGILL 11 /* Illegal instruction */
#define _NSIG 32 /* Biggest signal number + 1
(not including real-time signals). */
typedef void (*sighandler_t)(int);
extern sighandler_t signal(int signum, sighandler_t handler);
extern int raise(int signum);
/* Select */
typedef uint32_t fd_set;
extern int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
#define FD_ZERO(set) do { *set = 0; } while (0)
#define FD_SET(fd, set) do { *set |= (1<<fd); } while (0);
#define FD_CLR(fd, set) do { *set &= ~(1<<fd); } while (0);
#define FD_ISSET(fd, set) (*set | (1<<fd))
#endif

22
plat/rpi/libsys/_hol0.s Normal file
View file

@ -0,0 +1,22 @@
#
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .bss
! This data block is used to store information about the current line number
! and file.
.define hol0
.comm hol0, 8

45
plat/rpi/libsys/brk.c Normal file
View file

@ -0,0 +1,45 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <pi.h>
#define OUT_OF_MEMORY (void*)(-1) /* sbrk returns this on failure */
#define STACK_BUFFER 1024 /* number of bytes to leave for stack */
extern char _end[1];
static char* current = _end;
/* Top of heap: we assume that the block of memory the binary is loaded in
* is 256kB long. Because user pointers are always relative to the beginning
* of the block, this makes the end address easy to calculate. */
static char* max = (char*) (128*1024);
int brk(void* newend)
{
if ((newend >= (void*)max) || (newend < (void*)_end))
return -1;
current = newend;
return 0;
}
void* sbrk(intptr_t increment)
{
char* old;
if (increment == 0)
return current;
old = current;
if (brk(old + increment) < 0)
return OUT_OF_MEMORY;
return old;
}

16
plat/rpi/libsys/close.c Normal file
View file

@ -0,0 +1,16 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int close(int fd)
{
errno = EBADF;
return -1;
}

17
plat/rpi/libsys/creat.c Normal file
View file

@ -0,0 +1,17 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include "libsys.h"
int open(const char* path, int access, ...)
{
errno = EACCES;
return -1;
}

31
plat/rpi/libsys/errno.s Normal file
View file

@ -0,0 +1,31 @@
#
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
#define D(e) .define e; e
.sect .data
! Define various ACK error numbers. Note that these are *not* ANSI C
! errnos, and are used for different purposes.
D(ERANGE) = 1
D(ESET) = 2
D(EIDIVZ) = 6
D(EHEAP) = 17
D(EILLINS) = 18
D(EODDZ) = 19
D(ECASE) = 20
D(EBADMON) = 25

15
plat/rpi/libsys/getpid.c Normal file
View file

@ -0,0 +1,15 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
pid_t getpid(void)
{
return 0;
}

15
plat/rpi/libsys/isatty.c Normal file
View file

@ -0,0 +1,15 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int isatty(int fd)
{
return 1;
}

16
plat/rpi/libsys/kill.c Normal file
View file

@ -0,0 +1,16 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int kill(pid_t pid, int sig)
{
errno = EINVAL;
return -1;
}

19
plat/rpi/libsys/libsys.h Normal file
View file

@ -0,0 +1,19 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef LIBSYS_H
#define LIBSYS_H
extern void _sys_rawwrite(unsigned char b);
extern unsigned char _sys_rawread(void);
extern int _sys_rawpoll(void);
extern void _sys_write_tty(char c);
extern int _sys_ttyflags;
#endif

View file

@ -0,0 +1,20 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#ifndef LIBSYSASM_H
#define LIBSYSASM_H
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
#define gp r15
#endif

16
plat/rpi/libsys/lseek.c Normal file
View file

@ -0,0 +1,16 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence)
{
errno = EINVAL;
return -1;
}

16
plat/rpi/libsys/open.c Normal file
View file

@ -0,0 +1,16 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include "libsys.h"
int creat(const char* path, int mode)
{
return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
}

View file

@ -0,0 +1,70 @@
#
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include "libsysasm.h"
.sect .text
#define PASSWD 0x5a000000
#define PLLC 5
#define OSC 1
#define A2W 0x7e102000
#define A2W_PLLC_MULT 0x7e102020
#define A2W_PLLC_MULT2 0x7e102120
#define A2W_PLLC_MULT_FRACT 0x7e102220
#define A2W_PLLx_DIV 0x7e102620
#define CM 0x7e101000
#define CM_VPU_CTL 0x7e101008
#define CM_VPU_DIV 0x7e10100c
#define CM_TIME_DIV 0x7e1010ec
#define CM_TIME_CTL 0x7e1010e8
#define hash #
#define copy(A) A
#define poke(A, V) \
mov r0, copy(hash) V; mov r1, copy(hash) A; st r0, (r1)
! Changes the clock speed to 250MHz.
.define _pi_fast_mode
_pi_fast_mode:
poke(A2W + 0x190, 0x5a000001)
poke(A2W_PLLC_MULT_FRACT, PASSWD | 87380)
poke(A2W_PLLC_MULT2, PASSWD | 52 | 0x1000)
poke(A2W + 0x3c, 0x5a000100)
poke(A2W + 0x38, 0x5a000000)
poke(A2W + 0x34, 0x5a144000)
poke(A2W + 0x30, 0x5a000000)
poke(CM + 0x108, 0x5a000200)
poke(CM + 0x108, 0x5a0002aa)
poke(A2W + 0x2c, 0x5a000000)
poke(A2W + 0x28, 0x5a400000)
poke(A2W + 0x24, 0x5a000005)
poke(A2W_PLLC_MULT, PASSWD | 52 | 0x555000)
poke(A2W_PLLC_MULT2, PASSWD | 52 | 0x21000)
poke(A2W + 0x2c, 0x5a000042)
poke(A2W + 0x28, 0x5a500401)
poke(A2W + 0x24, 0x5a004005)
poke(A2W_PLLC_MULT, PASSWD | 52 | 0x555000)
poke(A2W_PLLx_DIV, PASSWD | 2)
poke(CM + 0x108, 0x5a0002ab)
poke(CM + 0x108, 0x5a0002aa)
poke(CM + 0x108, 0x5a0002a8)
poke(CM_VPU_CTL, PASSWD | 0x200 | OSC | 0x40)
poke(CM_VPU_DIV, PASSWD | [4 << 12])
poke(CM_VPU_CTL, PASSWD | PLLC | 0x40)
poke(CM_VPU_CTL, PASSWD | PLLC | 0x50)
poke(CM_TIME_DIV, PASSWD | [19 << 12] | 819)
poke(CM_TIME_CTL, PASSWD | OSC | 0x10)
mov r0, #250000000
st r0, _pi_clock_speed
b lr

View file

@ -0,0 +1,20 @@
#
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include "libsysasm.h"
.sect .text
! Transforms a physical address into a user address.
.define _pi_phys_to_user
_pi_phys_to_user:
ld r0, 0 (sp)
sub r0, gp
b lr

185
plat/rpi/libsys/pi_uart.s Normal file
View file

@ -0,0 +1,185 @@
#
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include "libsysasm.h"
.sect .text
! Because of the low system clock rate, this baud rate might be inaccurate
! So be careful with your serial/terminal, some adjustment may be necessary.
TARGET_BAUD_RATE = 115200
GPFSEL1 = 0x7e200004
GPSET0 = 0x7e20001C
GPCLR0 = 0x7e200028
GPPUD = 0x7e200094
GPPUDCLK0 = 0x7e200098
AUX_ENABLES = 0x7e215004
AUX_MU_IO_REG = 0x7e215040
AUX_MU_IER_REG = 0x7e215044
AUX_MU_IIR_REG = 0x7e215048
AUX_MU_LCR_REG = 0x7e21504C
AUX_MU_MCR_REG = 0x7e215050
AUX_MU_LSR_REG = 0x7e215054
AUX_MU_MSR_REG = 0x7e215058
AUX_MU_SCRATCH = 0x7e21505C
AUX_MU_CNTL_REG = 0x7e215060
AUX_MU_STAT_REG = 0x7e215064
AUX_MU_BAUD_REG = 0x7e215068
! Sets up the mini UART for use as a console.
.define _pi_init_uart
_pi_init_uart:
! Configure TX and RX GPIO pins for Mini Uart function.
mov r1, #GPFSEL1
ld r0, (r1)
and r0, #~[7<<12]
or r0, #2<<12
and r0, #~[7<<15]
or r0, #2<<15
st r0, (r1)
mov r1, #GPPUD
mov r0, #0
st r0, (r1)
delay1:
add r0, #1
cmp r0, #150
b.ne delay1
mov r1, #GPPUDCLK0
mov r0, #[1<<14]|[1<<15]
st r0, (r1)
mov r0, #0
delay2:
add r0, #1
cmp r0, #150
b.ne delay2
mov r1, #GPPUDCLK0
mov r0, #0
st r0, (r1)
! Set up serial port
mov r1, #AUX_ENABLES
mov r0, #1
st r0, (r1)
mov r1, #AUX_MU_IER_REG
mov r0, #0
st r0, (r1)
mov r1, #AUX_MU_CNTL_REG
mov r0, #0
st r0, (r1)
mov r1, #AUX_MU_LCR_REG
mov r0, #3
st r0, (r1)
mov r1, #AUX_MU_MCR_REG
mov r0, #0
st r0, (r1)
mov r1, #AUX_MU_IER_REG
mov r0, #0
st r0, (r1)
mov r1, #AUX_MU_IIR_REG
mov r0, #0xC6
st r0, (r1)
mov r1, #AUX_MU_BAUD_REG
ld r0, _pi_clock_speed
mov r2, #TARGET_BAUD_RATE*8
divu r0, r0, r2
sub r0, #1
st r0, (r1)
mov r1, #AUX_MU_LCR_REG
mov r0, #3
st r0, (r1)
mov r1, #AUX_MU_CNTL_REG
mov r0, #3
st r0, (r1)
! Mark the uart as being initialised.
mov r0, #1
stb r0, __uart_status
b lr
! Send a single byte.
.define __sys_rawwrite
__sys_rawwrite:
ldb r0, __uart_status
b.eq r0, #0, 1f
ld r0, (sp)
mov r1, #AUX_MU_LSR_REG
! loop until space available in Tx buffer
sendwait:
ld r2, (r1)
and r2, #0x20
cmp r2, #0x20
b.ne sendwait
mov r1, #AUX_MU_IO_REG
stb r0, (r1)
1:
b lr
! Poll to see if there's incoming data available.
.define __sys_rawpoll
.define __sys_rawpoll
__sys_rawpoll:
ldb r0, __uart_status
b.eq r0, #0, 1b
mov r1, #AUX_MU_LSR_REG
ld r0, (r1)
and r0, #0x1 ! 0 if no data, 1 if data
1:
b lr
! Receive a single byte.
.define __sys_rawread
__sys_rawread:
ldb r0, __uart_status
b.eq r0, #0, 1b
! receive 1 byte (returned in r0)
mov r1, #AUX_MU_LSR_REG
mov r2, #AUX_MU_IO_REG
! loop until char available
recvwait:
ld r3, (r1)
and r3, #0x1
b.ne r3, #0x1, recvwait
ldb r0, (r2)
1:
b lr
.comm __uart_status, 1
.sect .data
.define _pi_clock_speed
! System clock is running directly off the 19.2MHz crystal at initial reset
_pi_clock_speed:
.data4 19200000

View file

@ -0,0 +1,20 @@
#
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include "libsysasm.h"
.sect .text
! Transforms a user address into a physical address.
.define _pi_user_to_phys
_pi_user_to_phys:
ld r0, 0 (sp)
add r0, gp
b lr

41
plat/rpi/libsys/read.c Normal file
View file

@ -0,0 +1,41 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include "libsys.h"
int read(int fd, void* buffer, size_t count)
{
char i;
/* We're only allowed to read from fd 0, 1 or 2. */
if ((fd < 0) || (fd > 2))
{
errno = EBADF;
return -1;
}
/* Empty buffer? */
if (count == 0)
return 0;
/* Read one byte. */
i = _sys_rawread();
if ((i == '\r') && !(_sys_ttyflags & INLCR))
i = '\n';
if (_sys_ttyflags & ECHO)
_sys_write_tty(i);
*(char*)buffer = i;
return 1;
}

65
plat/rpi/libsys/select.c Normal file
View file

@ -0,0 +1,65 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <pi.h>
#include "libsys.h"
#define TICKS_PER_SEC 1000000
typedef int condition_t(void);
static int nop_condition(void)
{
return 0;
}
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout)
{
int result = 0;
condition_t* condition = nop_condition;
if (FD_ISSET(0, readfds))
condition = _sys_rawpoll;
FD_ZERO(readfds);
FD_ZERO(writefds);
FD_ZERO(exceptfds);
if (timeout)
{
/* Wait for a specified amount of time. */
uint32_t ticks = (timeout->tv_sec * TICKS_PER_SEC) +
(timeout->tv_usec * (TICKS_PER_SEC/1000000));
uint32_t* timer_clo = pi_phys_to_user((void*) 0x7e003004);
uint32_t ra = *timer_clo;
while (!condition() && ((*timer_clo - ra) < ticks))
;
}
else
{
/* Wait forever. */
while (!condition())
;
}
if ((condition == _sys_rawpoll) && condition())
{
FD_SET(0, readfds);
result = 1;
}
return result;
}

17
plat/rpi/libsys/signal.c Normal file
View file

@ -0,0 +1,17 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include "libsys.h"
sighandler_t signal(int signum, sighandler_t handler)
{
return SIG_DFL;
}

View file

@ -0,0 +1,22 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include "libsys.h"
int tcgetattr(int fd, struct termios* t)
{
t->c_iflag = _sys_ttyflags & INLCR;
t->c_oflag = _sys_ttyflags & ONLCR;
t->c_lflag = _sys_ttyflags & ECHO;
t->c_cflag = 0;
return 0;
}

View file

@ -0,0 +1,19 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include "libsys.h"
int tcsetattr(int fd, int actions, struct termios* t)
{
_sys_ttyflags = t->c_iflag | t->c_oflag | t->c_lflag;
return 0;
}

19
plat/rpi/libsys/time.c Normal file
View file

@ -0,0 +1,19 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include "libsys.h"
time_t time(time_t* t)
{
if (t)
*t = 0;
return 0;
}

49
plat/rpi/libsys/write.c Normal file
View file

@ -0,0 +1,49 @@
/*
* Raspberry Pi support library for the ACK
* © 2013 David Given
* This file is redistributable under the terms of the 3-clause BSD license.
* See the file 'Copying' in the root of the distribution for the full text.
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include "libsys.h"
int _sys_ttyflags = ONLCR | INLCR | ECHO;
void _sys_write_tty(char c)
{
_sys_rawwrite(c);
if ((c == '\n') && (_sys_ttyflags & ONLCR))
_sys_rawwrite('\r');
}
int write(int fd, void* buffer, size_t count)
{
int i;
char* p = buffer;
/* We're only allowed to write to fd 0, 1 or 2. */
if ((fd < 0) || (fd > 2))
{
errno = EBADF;
return -1;
}
/* Write all data. */
i = 0;
while (i < count)
{
_sys_write_tty(*p++);
i++;
}
/* No failures. */
return count;
}

View file

@ -143,6 +143,9 @@ showrelo()
case RELOH2:
printf("\ttop 2 bytes of a 4 byte word\n");
break;
case RELOVC4:
printf("\tVideoCore IV address in 32-bit instruction\n");
break;
default:
printf("\tunknown relocation type %d\n", relrec.or_type & RELSZ);
break;

View file

@ -164,6 +164,7 @@ struct outrelo {
#define RELO4 0x03 /* 4 bytes */
#define RELOPPC 0x04 /* 26-bit PowerPC address */
#define RELOH2 0x05 /* write top 2 bytes of 4 byte word */
#define RELOVC4 0x06 /* VideoCore IV address in 32-bit insruction */
#define RELPC 0x08 /* pc relative */
#define RELBR 0x10 /* High order byte lowest address. */
#define RELWR 0x20 /* High order word lowest address. */

View file

@ -8,6 +8,8 @@ static char rcsid[] = "$Id$";
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include "out.h"
#include "const.h"
#include "debug.h"
@ -43,6 +45,65 @@ static long read4(char* addr, int type)
return ((long)word1 << (2 * WIDTH)) + word0;
}
/* VideoCore 4 fixups are complex as we need to patch the instruction in
* one of several different ways (depending on what the instruction is).
*/
static long get_vc4_valu(char* addr)
{
uint16_t opcode = read2(addr, 0);
if ((opcode & 0xff00) == 0xe700)
{
/* ld<w> rd, $+o: [1110 0111 ww 0 d:5] [11111 o:27]
* st<w> rd, $+o: [1110 0111 ww 1 d:5] [11111 o:27]
*/
int32_t value = read4(addr+2, 0);
value &= 0x07ffffff;
value = value<<5>>5;
return value;
}
if ((opcode & 0xf080) == 0x9000)
{
/* b<cc> $+o*2: [1001 cccc 0ooo oooo] [oooo oooo oooo oooo]
* Yes, big-endian (the first 16 bits is the MSB).
*/
uint32_t value = read4(addr, RELWR);
value &= 0x007fffff;
value = value<<9>>9;
value *= 2;
return value;
}
if ((opcode & 0xf080) == 0x9080)
{
/* bl $+o*2: [1001 oooo 1ooo oooo] [oooo oooo oooo oooo]
* Yes, big-endian (the first 16 bits is the MSB).
* (Note that o is split.)
*/
int32_t value = read4(addr, RELWR);
int32_t lov = value & 0x007fffff;
int32_t hiv = value & 0x0f000000;
value = lov | (hiv>>1);
value = value<<5>>5;
value *= 2;
return value;
}
if ((opcode & 0xffe0) == 0xe500)
{
/* lea: [1110 0101 000 d:5] [o:32] */
return read4(addr+2, 0);
}
assert(0 && "unrecognised VC4 instruction");
}
/*
* The bits in type indicate how many bytes the value occupies and what
* significance should be attributed to each byte.
@ -63,6 +124,8 @@ getvalu(addr, type)
return read4(addr, type) & 0x03FFFFFD;
case RELOH2:
return read2(addr, type) << 16;
case RELOVC4:
return get_vc4_valu(addr);
default:
fatal("bad relocation size");
}
@ -106,6 +169,60 @@ static void write4(long valu, char* addr, int type)
}
}
/* VideoCore 4 fixups are complex as we need to patch the instruction in
* one of several different ways (depending on what the instruction is).
*/
static void put_vc4_valu(char* addr, long value)
{
uint16_t opcode = read2(addr, 0);
if ((opcode & 0xff00) == 0xe700)
{
/* ld<w> rd, o, (pc): [1110 0111 ww 0 d:5] [11111 o:27]
* st<w> rd, o, (pc): [1110 0111 ww 1 d:5] [11111 o:27]
*/
uint32_t v = read4(addr+2, 0);
v &= 0xf8000000;
v |= value & 0x07ffffff;
write4(v, addr+2, 0);
}
else if ((opcode & 0xf080) == 0x9000)
{
/* b<cc> dest: [1001 cccc 0ooo oooo] [oooo oooo oooo oooo]
* Yes, big-endian (the first 16 bits is the MSB).
*/
uint32_t v = read4(addr, RELWR);
v &= 0xff800000;
v |= (value/2) & 0x007fffff;
write4(v, addr, RELWR);
}
else if ((opcode & 0xf080) == 0x9080)
{
/* bl dest: [1001 oooo 1ooo oooo] [oooo oooo oooo oooo]
* Yes, big-endian (the first 16 bits is the MSB).
* (Note that o is split.)
*/
uint32_t v = read4(addr, RELWR);
uint32_t lovalue = (value/2) & 0x007fffff;
uint32_t hivalue = (value/2) & 0x07800000;
v &= 0xf0800000;
v |= lovalue | (hivalue<<1);
write4(v, addr, RELWR);
}
else if ((opcode & 0xffe0) == 0xe500)
{
/* lea: [1110 0101 000 d:5] [o:32] */
write4(value, addr+2, 0);
}
else
assert(0 && "unrecognised VC4 instruction");
}
/*
* The bits in type indicate how many bytes the value occupies and what
* significance should be attributed to each byte.
@ -138,6 +255,9 @@ putvalu(valu, addr, type)
case RELOH2:
write2(valu>>16, addr, type);
break;
case RELOVC4:
put_vc4_valu(addr, valu);
break;
default:
fatal("bad relocation size");
}