From 7cc3f65a586ab13a01e0d5439a2dba030f769ac2 Mon Sep 17 00:00:00 2001 From: d0p1 Date: Tue, 20 Feb 2024 04:11:09 +0100 Subject: [PATCH] xr/17032 boilerplate --- build.lua | 3 +- mach/xr17032/as/build.lua | 19 + mach/xr17032/as/instructions.dat | 319 ++++++++++ mach/xr17032/as/mach0.c | 26 + mach/xr17032/as/mach1.c | 3 + mach/xr17032/as/mach2.c | 21 + mach/xr17032/as/mach3.c | 118 ++++ mach/xr17032/as/mach4.c | 212 +++++++ mach/xr17032/as/mach5.c | 0 mach/xr17032/as/mktables.lua | 192 ++++++ mach/xr17032/libem/aar4.s | 47 ++ mach/xr17032/libem/and.s | 30 + mach/xr17032/libem/bls4.s | 31 + mach/xr17032/libem/build.lua | 43 ++ mach/xr17032/libem/c_ud_i.s | 36 ++ mach/xr17032/libem/c_uf_i.s | 38 ++ mach/xr17032/libem/c_ui_d.s | 25 + mach/xr17032/libem/c_ui_f.s | 26 + mach/xr17032/libem/cms.s | 35 + mach/xr17032/libem/com.s | 28 + mach/xr17032/libem/compareul.s | 39 ++ mach/xr17032/libem/csa.s | 42 ++ mach/xr17032/libem/csb.s | 47 ++ mach/xr17032/libem/dus4.s | 28 + mach/xr17032/libem/exg.s | 31 + mach/xr17032/libem/fef8.s | 56 ++ mach/xr17032/libem/fif8.s | 69 ++ mach/xr17032/libem/inn.s | 32 + mach/xr17032/libem/ior.s | 30 + mach/xr17032/libem/lar4.s | 23 + mach/xr17032/libem/los4.s | 55 ++ mach/xr17032/libem/rck.s | 35 + mach/xr17032/libem/sar4.s | 24 + mach/xr17032/libem/set.s | 39 ++ mach/xr17032/libem/sts4.s | 57 ++ mach/xr17032/libem/trp.s | 65 ++ mach/xr17032/libem/xor.s | 30 + mach/xr17032/libem/zer.s | 25 + mach/xr17032/libend/build.lua | 13 + mach/xr17032/libend/edata.s | 9 + mach/xr17032/libend/em_end.s | 24 + mach/xr17032/libend/end.s | 7 + mach/xr17032/libend/etext.s | 9 + mach/xr17032/mcg/build.lua | 7 + mach/xr17032/mcg/platform.c | 309 +++++++++ mach/xr17032/mcg/table | 1018 ++++++++++++++++++++++++++++++ mach/xr17032/top/table | 51 ++ plat/mintia/README | 37 ++ plat/mintia/boot.s | 58 ++ plat/mintia/build-pkg.lua | 25 + plat/mintia/build-tools.lua | 29 + plat/mintia/descr | 83 +++ plat/mintia/include/ack/fcntl.h | 19 + plat/mintia/include/ack/plat.h | 12 + plat/mintia/include/ack/signal.h | 74 +++ plat/mintia/include/build.lua | 28 + plat/mintia/include/sys/ioctl.h | 76 +++ plat/mintia/include/sys/types.h | 9 + plat/mintia/include/sys/wait.h | 19 + plat/mintia/libsys/_syscall.s | 34 + plat/mintia/libsys/build.lua | 36 ++ util/amisc/axlofflod.1 | 63 ++ util/amisc/axlofflod.c | 890 ++++++++++++++++++++++++++ util/amisc/build.lua | 1 + 64 files changed, 4917 insertions(+), 2 deletions(-) create mode 100644 mach/xr17032/as/build.lua create mode 100644 mach/xr17032/as/instructions.dat create mode 100644 mach/xr17032/as/mach0.c create mode 100644 mach/xr17032/as/mach1.c create mode 100644 mach/xr17032/as/mach2.c create mode 100644 mach/xr17032/as/mach3.c create mode 100644 mach/xr17032/as/mach4.c create mode 100644 mach/xr17032/as/mach5.c create mode 100755 mach/xr17032/as/mktables.lua create mode 100644 mach/xr17032/libem/aar4.s create mode 100644 mach/xr17032/libem/and.s create mode 100644 mach/xr17032/libem/bls4.s create mode 100644 mach/xr17032/libem/build.lua create mode 100644 mach/xr17032/libem/c_ud_i.s create mode 100644 mach/xr17032/libem/c_uf_i.s create mode 100644 mach/xr17032/libem/c_ui_d.s create mode 100644 mach/xr17032/libem/c_ui_f.s create mode 100644 mach/xr17032/libem/cms.s create mode 100644 mach/xr17032/libem/com.s create mode 100644 mach/xr17032/libem/compareul.s create mode 100644 mach/xr17032/libem/csa.s create mode 100644 mach/xr17032/libem/csb.s create mode 100644 mach/xr17032/libem/dus4.s create mode 100644 mach/xr17032/libem/exg.s create mode 100644 mach/xr17032/libem/fef8.s create mode 100644 mach/xr17032/libem/fif8.s create mode 100644 mach/xr17032/libem/inn.s create mode 100644 mach/xr17032/libem/ior.s create mode 100644 mach/xr17032/libem/lar4.s create mode 100644 mach/xr17032/libem/los4.s create mode 100644 mach/xr17032/libem/rck.s create mode 100644 mach/xr17032/libem/sar4.s create mode 100644 mach/xr17032/libem/set.s create mode 100644 mach/xr17032/libem/sts4.s create mode 100644 mach/xr17032/libem/trp.s create mode 100644 mach/xr17032/libem/xor.s create mode 100644 mach/xr17032/libem/zer.s create mode 100644 mach/xr17032/libend/build.lua create mode 100644 mach/xr17032/libend/edata.s create mode 100644 mach/xr17032/libend/em_end.s create mode 100644 mach/xr17032/libend/end.s create mode 100644 mach/xr17032/libend/etext.s create mode 100644 mach/xr17032/mcg/build.lua create mode 100644 mach/xr17032/mcg/platform.c create mode 100644 mach/xr17032/mcg/table create mode 100644 mach/xr17032/top/table create mode 100644 plat/mintia/README create mode 100644 plat/mintia/boot.s create mode 100644 plat/mintia/build-pkg.lua create mode 100644 plat/mintia/build-tools.lua create mode 100644 plat/mintia/descr create mode 100644 plat/mintia/include/ack/fcntl.h create mode 100644 plat/mintia/include/ack/plat.h create mode 100644 plat/mintia/include/ack/signal.h create mode 100644 plat/mintia/include/build.lua create mode 100644 plat/mintia/include/sys/ioctl.h create mode 100644 plat/mintia/include/sys/types.h create mode 100644 plat/mintia/include/sys/wait.h create mode 100644 plat/mintia/libsys/_syscall.s create mode 100644 plat/mintia/libsys/build.lua create mode 100644 util/amisc/axlofflod.1 create mode 100644 util/amisc/axlofflod.c diff --git a/build.lua b/build.lua index 418bc7dc0..da9ed23f1 100644 --- a/build.lua +++ b/build.lua @@ -6,6 +6,7 @@ vars.ackcflags = { } vars.ackldflags = {} vars.plats = { + "mintia", "cpm", "linux386", "linux68k", @@ -23,9 +24,7 @@ vars.plats = { vars.plats_with_tests = { "cpm", "linux68k", - --"linux386", "linuxppc", - --"linuxmips", "pc86", } diff --git a/mach/xr17032/as/build.lua b/mach/xr17032/as/build.lua new file mode 100644 index 000000000..d330957a0 --- /dev/null +++ b/mach/xr17032/as/build.lua @@ -0,0 +1,19 @@ +normalrule { + name = "astables", + outleaves = {"definitions.y", "tokens.y", "rules.y"}, + ins = {"./mktables.lua", "./instructions.dat"}, + commands = {"$(LUA) %{ins[1]} %{outs} < %{ins[2]}"} +} + +bundle { + name = "headers", + srcs = { + "./mach0.c", + "./mach1.c", + "./mach2.c", + "./mach3.c", + "./mach4.c", + "./mach5.c", + } +} + diff --git a/mach/xr17032/as/instructions.dat b/mach/xr17032/as/instructions.dat new file mode 100644 index 000000000..33f75ee9c --- /dev/null +++ b/mach/xr17032/as/instructions.dat @@ -0,0 +1,319 @@ +# Syntax: +# : a field occupying so many bits. +# T: a field occupying one bit. +# Undefined bits end up as 0. +# +# This is intended to be compatible with MIPS release 5, integer instructions +# only. It's based on the MIPS32 Instruction Set v5.04 manual (available from +# https://www.mips.com/products/architectures/mips32-2/). + +# Useful pseudoops. + +# beq zero, offset +00000111101 "b" OFF=offset21 + +# jalr zero, lr, 0 +00000000000000001111100000111000 "ret" + +# jalr zero, RA, 0 +000000000000000000000111000 "jr" RA=gpr + +# add RA, RB, zero LSH 0 +0111000000000000111001 "mov" RA=gpr ',' RB=gpr + +# addi RA, zero, imm +00000111100 "li" RA=gpr ',' IMM=e16 + +# addi zero, zero, 0 +00000000000000000000000000111100 "nop" + +# Condition code tokens; these have to be defined here because .f overlaps with +# a format code. + +%token .f +%token .un +%token .eq +%token .ueq +%token .olt +%token .ult +%token .ole +%token .ule +%token .sf +%token .ngle +%token .seq +%token .ngl +%token .lt +%token .nge +%token .le +%token .ngt + +# Core ALU instructions. + +111 "jal" OFF=offset29 +110 "j" OFF=offset29 +111101 "beq" RA=gpr ',' OFF=offset21 +110101 "bne" RA=gpr ',' OFF=offset21 +101101 "blt" RA=gpr ',' OFF=offset21 +100101 "bgt" RA=gpr ',' OFF=offset21 +011101 "ble" RA=gpr ',' OFF=offset21 +010101 "bge" RA=gpr ',' OFF=offset21 +001101 "bpe" RA=gpr ',' OFF=offset21 +000101 "bpo" RA=gpr ',' OFF=offset21 +111100 "addi" RA=gpr ',' RB=gpr ',' IMM=e16 +110100 "subi" RA=gpr ',' RB=gpr ',' IMM=e16 +101100 "slti" RA=gpr ',' RB=gpr ',' IMM=e16 +100100 "slti" "signed" RA=gpr ',' RB=gpr ',' IMM=e16 +011100 "andi" RA=gpr ',' RB=gpr ',' IMM=e16 +010100 "xori" RA=gpr ',' RB=gpr ',' IMM=e16 +001100 "ori" RA=gpr ',' RB=gpr ',' IMM=e16 +000100 "lui" RA=gpr ',' RB=gpr ',' IMM=e16 +111011 "mov" RA=gpr ',' "byte" '[' RB=gpr '+' IMM=e16 ']' +110011 "mov" RA=gpr ',' "int" '[' RB=gpr '+' IMM=e16 ']' +101011 "mov" RA=gpr ',' "long" '[' RB=gpr '+' IMM=e16 ']' +111010 "mov" "byte" '[' RA=gpr '+' IMM=e16 ']' ',' RB=gpr +110010 "mov" "int" '[' RA=gpr '+' IMM=e16 ']' ',' RB=gpr +101010 "mov" "long" '[' RA=gpr '+' IMM=e16 ']' ',' RB=gpr +011010 "mov" "byte" '[' RA=gpr '+' IMM=e16 ']' ',' I=u5 +010010 "mov" "int" '[' RA=gpr '+' IMM=e16 ']' ',' I=u5 +001010 "mov" "long" '[' RA=gpr '+' IMM=e16 ']' ',' I=u5 +111000 "jalr" RA=gpr ',' RB=gpr ',' IMM=e16 + + +00000000000100000 "add" RD=gpr ',' RS=gpr ',' RT=gpr +001000 "addi" RT=gpr ',' RS=gpr ',' IMM=e16 +001001 "addiu" RT=gpr ',' RS=gpr ',' IMM=e16 +00000000000100001 "addu" RD=gpr ',' RS=gpr ',' RT=gpr +00000000000100100 "and" RD=gpr ',' RS=gpr ',' RT=gpr +001100 "andi" RT=gpr ',' RS=gpr ',' IMM=e16 +0001000000000000 "b" OFF=offset16 +0000010000010001 "bal" OFF=offset16 +000100 "beq" RS=gpr ',' RT=gpr ',' OFF=offset16 +010100 "beql" RS=gpr ',' RT=gpr ',' OFF=offset16 +00000100001 "bgez" RS=gpr ',' OFF=offset16 +00000110001 "bgezal" RS=gpr ',' OFF=offset16 +00000110011 "bgezall" RS=gpr ',' OFF=offset16 +00000100011 "bgezl" RS=gpr ',' OFF=offset16 +00011100000 "bgtz" RS=gpr ',' OFF=offset16 +01011100000 "bgtzl" RS=gpr ',' OFF=offset16 +00011000000 "blez" RS=gpr ',' OFF=offset16 +01011000000 "blezl" RS=gpr ',' OFF=offset16 +00000100000 "bltz" RS=gpr ',' OFF=offset16 +00000110000 "bltzal" RS=gpr ',' OFF=offset16 +00000110010 "bltzall" RS=gpr ',' OFF=offset16 +00000100010 "bltzl" RS=gpr ',' OFF=offset16 +000101 "bne" RS=gpr ',' RT=gpr ',' OFF=offset16 +010101 "bnel" RS=gpr ',' RT=gpr ',' OFF=offset16 +101111 "cache" OP=u5 ',' OFF=e16 '(' RS=gpr ')' +0111110011011 "cachee" OP=u5 ',' OFF=e9 '(' RS=gpr ')' +01110000000100001 "clo" RD=RT=gpr ',' RS=gpr +01110000000100000 "clz" RD=RT=gpr ',' RS=gpr +01000010000000000000000000011111 "deret" +010000010110110000000000000 "di" RT=gpr +01000001011000000110000000000000 "di" +0000000000000000011010 "div" RS=gpr ',' RT=gpr +0000000000000000011011 "divu" RS=gpr ',' RT=gpr +00000000000000000000000011000000 "ehb" +010000010110110000000100000 "ei" RT=gpr +01000001011000000110000000100000 "ei" +011111000000 "ext" RT=gpr ',' RS=gpr ',' extmsblsb +011111000100 "ins" RT=gpr ',' RS=gpr ',' insmsblsb +000010 "j" ABS=abs26 +000011 "jal" ABS=abs26 +0000000000000000001001 "jalr" RD=gpr ',' RS=gpr +000000000001111100000001001 "jalr" RS=gpr +0000000000010000001001 "jalr.hb" RD=gpr ',' RS=gpr +000000000001111110000001001 "jalr.hb" RS=gpr +011101 "jalx" ABS=abs26 +000000000000000000000001000 "jr" RS=gpr +000000000000000010000001000 "jr.hb" RS=gpr +100000 "lb" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110101100 "lbe" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +100100 "lbu" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110101000 "lbue" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +100001 "lh" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110101101 "lhe" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +100101 "lhu" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110101001 "lhue" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +110000 "ll" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110101110 "lle" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +00111100000 "lui" RT=gpr ',' IMM=e16 +100011 "lw" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110101111 "lwe" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +100010 "lwl" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110011001 "lwle" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +100110 "lwr" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110011010 "lwre" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +0111000000000000000000 "madd" RS=gpr ',' RT=gpr +0111000000000000000001 "maddu" RS=gpr ',' RT=gpr +000000000000000000000010000 "mfhi" RD=gpr +000000000000000000000010010 "mflo" RD=gpr +00000000000001011 "movn" RD=gpr ',' RS=gpr ',' RT=gpr +00000000000001010 "movz" RD=gpr ',' RS=gpr ',' RT=gpr +0111000000000000000100 "msub" RS=gpr ',' RT=gpr +0111000000000000000101 "msubu" RS=gpr ',' RT=gpr +000000000000000000000010001 "mthi" RS=gpr +000000000000000000000010011 "mtlo" RS=gpr +01110000000000010 "mul" RD=gpr ',' RS=gpr ',' RT=gpr +0000000000000000011000 "mult" RS=gpr ',' RT=gpr +0000000000000000000001 "multu" RS=gpr ',' RT=gpr +00000000000100111 "nor" RD=gpr ',' RS=gpr ',' RT=gpr +00000000000100101 "or" RD=gpr ',' RS=gpr ',' RT=gpr +001101 "ori" RT=gpr ',' RS=gpr ',' IMM=e16 +00000000000000000000000101000000 "pause" +110011 "pref" H=u5 ',' IMM=e16 '(' RS=gpr ')' +0111110100011 "prefe" H=u5 ',' IMM=e9 '(' RS=gpr ')' +01001100000001111 "prefx" H=u5 ',' RT=gpr '(' RS=gpr ')' +0111110000000000111011 "rdhwr" RT=gpr ',' RD=gpr +0100000101000000000000 "rdpgpr" RD=gpr ',' RT=gpr +00000000001000010 "rotr" RD=gpr ',' RT=gpr ',' SA=u5 +00000000001000110 "rotrv" RD=gpr ',' RT=gpr ',' RS=gpr +101000 "sb" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110011100 "sbe" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +111000 "sc" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110011110 "sce" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +011100111111 "sdbbp" CODE=u20 +0111110000010000100000 "seb" RD=gpr ',' RT=gpr +0111110000011000100000 "seh" RD=gpr ',' RT=gpr +101001 "sh" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110011101 "she" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +00000000000000000 "sll" RD=gpr ',' RT=gpr ',' SA=u5 +00000000000000100 "sllv" RD=gpr ',' RT=gpr ',' RS=gpr +00000000000101010 "slt" RD=gpr ',' RS=gpr ',' RT=gpr +001010 "slti" RT=gpr ',' RS=gpr ',' IMM=e16 +001011 "sltiu" RT=gpr ',' RS=gpr ',' IMM=e16 +00000000000101011 "sltu" RD=gpr ',' RS=gpr ',' RT=gpr +00000000000000011 "sra" RD=gpr ',' RT=gpr ',' SA=u5 +00000000000000111 "srav" RD=gpr ',' RT=gpr ',' RS=gpr +00000000000000010 "srl" RD=gpr ',' RT=gpr ',' SA=u5 +00000000000000110 "srlv" RD=gpr ',' RT=gpr ',' RS=gpr +00000000000000000000000001000000 "ssnop" +00000000000100010 "sub" RD=gpr ',' RS=gpr ',' RT=gpr +00000000000100011 "subu" RD=gpr ',' RS=gpr ',' RT=gpr +101011 "sw" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110011111 "swe" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +101010 "swl" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110010001 "swle" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +101110 "swr" RT=gpr ',' IMM=e16 '(' RS=gpr ')' +0111110100010 "swre" RT=gpr ',' IMM=e9 '(' RS=gpr ')' +00000111111 "synci" IMM=e16 '(' RS=gpr ')' +000000001100 "syscall" CODE=u20 +0000000000000000110100 "teq" RS=gpr ',' RT=gpr +00000101100 "teqi" RS=gpr ',' IMM=e16 +0000000000000000110000 "tge" RS=gpr ',' RT=gpr +00000101000 "tgei" RS=gpr ',' IMM=e16 +00000101001 "tgeiu" RS=gpr ',' IMM=e16 +0000000000000000110001 "tgeu" RS=gpr ',' RT=gpr +01000010000000000000000000000011 "tlbinv" +01000010000000000000000000000100 "tlbinvf" +01000010000000000000000000001000 "tlbp" +01000010000000000000000000000001 "tlbr" +01000010000000000000000000000010 "tlbwi" +01000010000000000000000000000110 "tlbwr" +0000000000000000110010 "tlt" RS=gpr ',' RT=gpr +00000101010 "tlti" RS=gpr ',' IMM=e16 +00000101011 "tltiu" RS=gpr ',' IMM=e16 +0000000000000000110011 "tltu" RS=gpr ',' RT=gpr +0000000000000000110110 "tne" RS=gpr ',' RT=gpr +00000101110 "tnei" RS=gpr ',' IMM=e16 +01000010000000000000000000100000 "wait" +0100000111000000000000 "wrpgpr" RD=gpr ',' RT=gpr +0111110000000010100000 "wsbh" RD=gpr ',' RT=gpr +00000000000100110 "xor" RD=gpr ',' RS=gpr ',' RT=gpr +001110 "xori" RT=gpr ',' RS=gpr ',' IMM=e16 + +# FPU instructions. + +01000100000000101 "abs" F=fmt FD=fpr ',' FS=fpr +010001000000 "add" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr +010011011110 "alnv" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr ',' RS=gpr +0100010011 "c" CO=fcond F=fmt C=u3 ',' FS=fpr ',' FT=fpr +01000100000001010 "ceil" ".l" F=fmt FD=fpr ',' FS=fpr +01000100000001110 "ceil" ".w" F=fmt FD=fpr ',' FS=fpr +0100010001000000000000 "cfc1" RT=gpr ',' FS=fpr +0100010011000000000000 "ctc1" RT=gpr ',' FS=fpr +01000100000100001 "cvt" ".d" F=fmt FD=fpr ',' FS=fpr +01000100000100101 "cvt" ".l" F=fmt FD=fpr ',' FS=fpr +01000110000100110 "cvt" ".ps" ".s" FD=fpr ',' FS=fpr ',' FT=fpr +01000100000100000 "cvt" ".s" F=fmt FD=fpr ',' FS=fpr +0100011011000000101000 "cvt" ".s" ".pl" FS=fpr ',' FD=fpr +0100011011000000100000 "cvt" ".s" ".pu" FS=fpr ',' FD=fpr +01000100000100100 "cvt" ".w" F=fmt FD=fpr ',' FS=fpr +010001000011 "div" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr +01000100000001011 "floor" ".l" F=fmt FD=fpr ',' FS=fpr +01000100000001111 "floor" ".w" F=fmt FD=fpr ',' FS=fpr +110101 "ldc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')' +01001100000000001 "ldxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')' +01001100000000101 "luxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')' +110001 "lwc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')' +01001100000000000 "lwxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')' +010011100 "madd" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr +0100010000000000000000 "mfc1" RT=gpr ',' FS=fpr +0100010001100000000000 "mfhc1" RT=gpr ',' FS=fpr +01000100000000110 "mov" F=fmt FD=fpr ',' FS=fpr +0000000000000000001 "movf" RD=gpr ',' RS=gpr ',' C=u3 +01000100010001 "movf" F=fmt FD=fpr ',' FS=fpr ',' C=u3 +010001010011 "movn" F=fmt FD=fpr ',' FS=fpr ',' RT=gpr +0000000100000000001 "movt" RD=gpr ',' RS=gpr ',' C=u3 +01000101010001 "movt" F=fmt FD=fpr ',' FS=fpr ',' C=u3 +010001010010 "movz" F=fmt FD=fpr ',' FS=fpr ',' RT=gpr +010011101 "msub" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr +0100010010000000000000 "mtc1" RT=gpr ',' FS=fpr +0100010011100000000000 "mthc1" RT=gpr ',' FS=fpr +010001000010 "mul" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr +01000100000000111 "neg" F=fmt FD=fpr ',' FS=fpr +010011110 "nmadd" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr +010011111 "nmsub" F=fmt3 FD=fpr ',' FR=fpr ',' FS=fpr ',' FT=fpr +01000110110101100 "pll" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr +01000110110101101 "plu" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr +01000110110101110 "pul" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr +01000110110101111 "puu" ".ps" FD=fpr ',' FS=fpr ',' FT=fpr +01000100000010101 "recip." F=fmt FD=fpr ',' FS=fpr +01000100000001000 "round" ".l" F=fmt FD=fpr ',' FS=fpr +01000100000001100 "round" ".w" F=fmt FD=fpr ',' FS=fpr +01000100000010110 "rsqrt" F=fmt FD=fpr ',' FS=fpr +111101 "sdc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')' +01001100000001001 "sdxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')' +01000100000000100 "sqrt" F=fmt FD=fpr ',' FS=fpr +010001000001 "sub" F=fmt FD=fpr ',' FS=fpr ',' FT=fpr +01001100000001101 "suxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')' +111001 "swc1" FT=fpr ',' IMM=e16 '(' RS=gpr ')' +01001100000001000 "swxc1" FD=fpr ',' RT=gpr '(' RS=gpr ')' +01000100000001001 "trunc" ".l" F=fmt FD=fpr ',' FS=fpr +01000100000001101 "trunc" ".w" F=fmt FD=fpr ',' FS=fpr + +# Generic coprocessor instructions. + +0100010100000 "bc1f" C=u3 ',' OFF=offset16 +0100010100000000 "bc1f" OFF=offset16 +0100010100010 "bc1fl" C=u3 ',' OFF=offset16 +0100010100000010 "bc1fl" OFF=offset16 +0100010100001 "bc1t" C=u3 ',' OFF=offset16 +0100010100000001 "bc1t" OFF=offset16 +0100010100011 "bc1tl" C=u3 ',' OFF=offset16 +0100010100000011 "bc1tl" OFF=offset16 +0100100100000 "bc2f" C=u3 ',' OFF=offset16 +0100100100000000 "bc2f" OFF=offset16 +0100100100010 "bc2fl" C=u3 ',' OFF=offset16 +0100100100000010 "bc2fl" OFF=offset16 +0100100100001 "bc2t" C=u3 ',' OFF=offset16 +0100100100000001 "bc2t" OFF=offset16 +0100100100011 "bc2tl" C=u3 ',' OFF=offset16 +0100100100000011 "bc2tl" OFF=offset16 +01001000010 "cfc2" RT=gpr ',' IMM=u16 +01001000110 "ctc2" RT=gpr ',' IMM=u16 +0100101 "cop2" FUN=u25 +110110 "ldc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')' +110010 "lwc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')' +0100000000000000000 "mfc0" RT=gpr ',' RD=u5 ',' S=u3 +01001000000 "mfc2" RT=gpr ',' IMM=u16 +0100000001000000000 "mfhc0" RT=gpr ',' RD=u5 ',' S=u3 +01001000011 "mfhc2" RT=gpr ',' IMM=u16 +0100000010000000000 "mtc0" RT=gpr ',' RD=u5 ',' S=u3 +01001000100 "mtc2" RT=gpr ',' IMM=u16 +0100000011000000000 "mthc0" RT=gpr ',' RD=u5 ',' S=u3 +01001000111 "mthc2" RT=gpr ',' IMM=u16 +111110 "sdc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')' +111010 "swc2" RT=u5 ',' IMM=e16 '(' RS=gpr ')' + + + diff --git a/mach/xr17032/as/mach0.c b/mach/xr17032/as/mach0.c new file mode 100644 index 000000000..8aef3d697 --- /dev/null +++ b/mach/xr17032/as/mach0.c @@ -0,0 +1,26 @@ +/* + * $Source$ + * $State$ + */ + +#define THREE_PASS /* branch and offset optimization */ +#define LISTING /* enable listing facilities */ +#define RELOCATION /* generate relocatable code */ +#define DEBUG 0 + +#undef ADDR_T +#define ADDR_T uint32_t + +#undef word_t +#define word_t uint32_t + +#undef ALIGNWORD +#define ALIGNWORD 4 + +#undef ALIGNSECT +#define ALIGNSECT 4 + +#undef VALWIDTH +#define VALWIDTH 8 + +#define FIXUPFLAGS 0 diff --git a/mach/xr17032/as/mach1.c b/mach/xr17032/as/mach1.c new file mode 100644 index 000000000..55c6b5507 --- /dev/null +++ b/mach/xr17032/as/mach1.c @@ -0,0 +1,3 @@ +/* + * Do not #include anything here. Do it in mach/proto/as/comm0.h + */ diff --git a/mach/xr17032/as/mach2.c b/mach/xr17032/as/mach2.c new file mode 100644 index 000000000..61d7111e0 --- /dev/null +++ b/mach/xr17032/as/mach2.c @@ -0,0 +1,21 @@ +%token GPR +%token FPR +%token FCOND + +%token HI16 +%token HA16 +%token LO16 + +%type gpr fpr +%type e16 e9 +%type u25 u20 u16 u5 u3 +%type abs26 offset16 offset29 offset21 + +%type fmt fmt3 +%type fcond + +%type extmsblsb insmsblsb +%type extabsexp + +#include "definitions.y" + diff --git a/mach/xr17032/as/mach3.c b/mach/xr17032/as/mach3.c new file mode 100644 index 000000000..628e18501 --- /dev/null +++ b/mach/xr17032/as/mach3.c @@ -0,0 +1,118 @@ +/* Integer registers */ + +0, GPR, 0, "r0", +0, GPR, 0, "zero", +0, GPR, 1, "r1", +0, GPR, 1, "at", +0, GPR, 1, "t0", +0, GPR, 2, "r2", +0, GPR, 2, "t1", +0, GPR, 3, "r3", +0, GPR, 3, "t2", +0, GPR, 4, "r4", +0, GPR, 4, "t3", +0, GPR, 5, "r5", +0, GPR, 5, "t4", +0, GPR, 6, "r6", +0, GPR, 6, "t5", +0, GPR, 7, "r7", +0, GPR, 7, "a0", +0, GPR, 8, "r8", +0, GPR, 8, "a1", +0, GPR, 9, "r9", +0, GPR, 9, "a2", +0, GPR, 10, "r10", +0, GPR, 10, "a3", +0, GPR, 11, "r11", +0, GPR, 11, "s0", +0, GPR, 12, "r12", +0, GPR, 12, "s1", +0, GPR, 13, "r13", +0, GPR, 13, "s2", +0, GPR, 14, "r14", +0, GPR, 14, "s3", +0, GPR, 15, "r15", +0, GPR, 15, "s4", +0, GPR, 16, "r16", +0, GPR, 16, "s5", +0, GPR, 17, "r17", +0, GPR, 17, "s6", +0, GPR, 18, "r18", +0, GPR, 18, "s7", +0, GPR, 19, "r19", +0, GPR, 19, "s8", +0, GPR, 20, "r20", +0, GPR, 20, "s9", +0, GPR, 21, "r21", +0, GPR, 21, "s10", +0, GPR, 22, "r22", +0, GPR, 22, "s11", +0, GPR, 23, "r23", +0, GPR, 23, "s12", +0, GPR, 24, "r24", +0, GPR, 24, "s13", +0, GPR, 25, "r25", +0, GPR, 25, "s14", +0, GPR, 26, "r26", +0, GPR, 26, "s15", +0, GPR, 27, "r27", +0, GPR, 27, "s16", +0, GPR, 28, "r28", +/* xxx */ +0, GPR, 28, "gp", +/* xxx */ +0, GPR, 28, "s17", +0, GPR, 29, "r29", +/* xxx */ +0, GPR, 29, "fp", +/* xxx */ +0, GPR, 29, "tp", +0, GPR, 30, "r30", +0, GPR, 30, "sp", +0, GPR, 31, "r31", +0, GPR, 31, "lr", +0, GPR, 31, "ra", + + +/* Floating-point registers */ + +0, FPR, 0, "f0", +0, FPR, 1, "f1", +0, FPR, 2, "f2", +0, FPR, 3, "f3", +0, FPR, 4, "f4", +0, FPR, 5, "f5", +0, FPR, 6, "f6", +0, FPR, 7, "f7", +0, FPR, 8, "f8", +0, FPR, 9, "f9", +0, FPR, 10, "f10", +0, FPR, 11, "f11", +0, FPR, 12, "f12", +0, FPR, 13, "f13", +0, FPR, 14, "f14", +0, FPR, 15, "f15", +0, FPR, 16, "f16", +0, FPR, 17, "f17", +0, FPR, 18, "f18", +0, FPR, 19, "f19", +0, FPR, 20, "f20", +0, FPR, 21, "f21", +0, FPR, 22, "f22", +0, FPR, 23, "f23", +0, FPR, 24, "f24", +0, FPR, 25, "f25", +0, FPR, 26, "f26", +0, FPR, 27, "f27", +0, FPR, 28, "f28", +0, FPR, 29, "f29", +0, FPR, 30, "f30", +0, FPR, 31, "f31", + +0, OP_LI, 0, "li", +0, HI16, 0, "hi16", +0, HA16, 0, "ha16", +0, LO16, 0, "lo16", + +#include "tokens.y" + diff --git a/mach/xr17032/as/mach4.c b/mach/xr17032/as/mach4.c new file mode 100644 index 000000000..25eb6c275 --- /dev/null +++ b/mach/xr17032/as/mach4.c @@ -0,0 +1,212 @@ +#include "rules.y" + | OP_LI GPR ',' extabsexp + { + word_t reg = $2; + uint32_t val = $4; + + if (((int32_t)val >= -0x8000) && ((int32_t)val <= 0x7fff)) + emit4(0x24000000 | (reg<<16) | (val & 0xffff)); /* addiu reg, zero, value */ + else if (val <= 0xffff) + emit4(0x34000000 | (reg<<16) | val); /* ori reg, zero, value */ + else + { + emit4(0x3c000000 | (reg<<16) | (val>>16)); /* lui reg, value */ + emit4(0x34000000 | (reg<<16) | (reg<<21) | (val & 0xffff)); /* ori reg, reg, value */ + } + } + +extabsexp + : absexp + | LO16 ASC_LPAR expr ASC_RPAR + { + newrelo($3.typ, RELO2 | FIXUPFLAGS); + $$ = $3.val; + } + | HI16 ASC_LPAR expr ASC_RPAR + { + newrelo($3.typ, RELO2HI | FIXUPFLAGS); + if ($3.val & 0xffff0000) + fatal("relocation offset in hi16[] too big"); + $$ = $3.val; + } + | HA16 ASC_LPAR expr ASC_RPAR + { + newrelo($3.typ, RELO2HISAD | FIXUPFLAGS); + if ($3.val & 0xffff0000) + fatal("relocation offset in ha16[] too big"); + $$ = $3.val; + } + ; + +gpr: GPR +fpr: FPR + +fmt3 + : OP__DOT_S { $$ = 0; } + | OP__DOT_D { $$ = 1; } + | OP__DOT_W { $$ = 4; } + | OP__DOT_L { $$ = 5; } + | OP__DOT_PS { $$ = 6; } + ; + +fmt + : fmt3 { $$ = $1 + 16; } + ; + +fcond + : OP__DOT_F { $$ = 0; } + | OP__DOT_UN { $$ = 1; } + | OP__DOT_EQ { $$ = 2; } + | OP__DOT_UEQ { $$ = 3; } + | OP__DOT_OLT { $$ = 4; } + | OP__DOT_ULT { $$ = 5; } + | OP__DOT_OLE { $$ = 6; } + | OP__DOT_ULE { $$ = 7; } + | OP__DOT_SF { $$ = 8; } + | OP__DOT_NGLE { $$ = 9; } + | OP__DOT_SEQ { $$ = 10; } + | OP__DOT_NGL { $$ = 11; } + | OP__DOT_LT { $$ = 12; } + | OP__DOT_NGE { $$ = 13; } + | OP__DOT_LE { $$ = 14; } + | OP__DOT_NGT { $$ = 15; } + ; + +e16 + : extabsexp + { + /* Allow signed or unsigned 16-bit values. */ + if (($1 < -0x8000) || ($1 > 0xffff)) + serror("16-bit signed value out of range"); + $$ = (uint16_t) $1; + } + ; + +e9 + : absexp + { + /* Allow signed or unsigned 9-bit values. */ + if (($1 < -0x100) || ($1 > 0x1ff)) + serror("9-bit signed value out of range"); + $$ = (uint16_t) $1; + } + ; + +u25 + : absexp + { + if (($1 < 0) || ($1 > 0x1ffffff)) + serror("25-bit unsigned value out of range"); + $$ = $1; + } + ; + +u20 + : absexp + { + if (($1 < 0) || ($1 > 0xfffff)) + serror("20-bit unsigned value out of range"); + $$ = $1; + } + ; + +u16 + : extabsexp + { + if (($1 < 0) || ($1 > 0xffff)) + serror("16-bit unsigned value out of range"); + $$ = $1; + } + ; + +u5 + : absexp + { + if (($1 < 0) || ($1 > 0x1f)) + serror("5-bit unsigned value out of range"); + $$ = $1; + } + ; + +u3 + : absexp + { + if (($1 < 0) || ($1 > 0x7)) + serror("3-bit unsigned value out of range"); + $$ = $1; + } + ; + +offset16 + : expr + { + int dist = $1.val - DOTVAL - 4; + fit(fitx(dist, 18)); + + if (dist & 0x3) + serror("jump targets must be 4-aligned"); + + newrelo($1.typ, RELOMIPS | RELPC | FIXUPFLAGS); + $$ = (dist >> 2) & 0x0000ffff; + } + ; + +offset21 + : expr + { + int dist = $1.val - DOTVAL - 4; + fit(fitx(dist, 28)); + + if (dist & 0x3) + serror("jump targets must be 4-aligned"); + + newrelo($1.typ, RELOMIPS | RELPC | FIXUPFLAGS); + $$ = (dist >> 2) & 0x001fffff; + } + ; + +offset29 + : expr + { + int dist = $1.val - DOTVAL - 4; + fit(fitx(dist, 32)); + + if (dist & 0x3) + serror("jump targets must be 4-aligned"); + + newrelo($1.typ, RELOMIPS | RELPC | FIXUPFLAGS); + $$ = (dist >> 2) & 0x1fffffff; + } + ; + +abs26 + : expr + { + int target = $1.val; + fit(fitx(target, 28)); + + if (target & 0x3) + serror("jump targets must be 4-aligned"); + + newrelo($1.typ, RELOMIPS | FIXUPFLAGS); + $$ = (target >> 2) & 0x03ffffff; + } + ; + +extmsblsb + : u5 ',' u5 + { + int pos = $1; + int size = $3; + $$ = ((size-1) << 5) | pos; + } + ; + +insmsblsb + : u5 ',' u5 + { + int pos = $1; + int size = $3; + $$ = ((pos+size-1) << 5) | pos; + } + ; diff --git a/mach/xr17032/as/mach5.c b/mach/xr17032/as/mach5.c new file mode 100644 index 000000000..e69de29bb diff --git a/mach/xr17032/as/mktables.lua b/mach/xr17032/as/mktables.lua new file mode 100755 index 000000000..b6bbf1883 --- /dev/null +++ b/mach/xr17032/as/mktables.lua @@ -0,0 +1,192 @@ +local args = {...} + +local words = {} +local insns = {} + +local function addword(word) + local w = words[word] + if not w then + w = word:upper() + w = w:gsub("%.", "_DOT_") + if not w:match("^[A-Z0-9_]*$") then + error(word.." is not a valid token") + end + words[word] = w + end + return w +end + +local function parsesyntax(line) + local syntax = {} + for word in line:gmatch("%S+") do + local _, _, s = word:find('^"(.*)"$') + if s then + syntax[#syntax+1] = {word=addword(s) } + else + _, _, s = word:find("^('.*')$") + if s then + syntax[#syntax+1] = {punct=s } + else + local token = {} + for equate in word:gmatch("([^=]+)=") do + token[#token+1] = equate + end + _, _, token.token = word:find("([^=]*)$") + syntax[#syntax+1] = token + if not token.token then + error("can't parse "..word) + end + end + end + end + return syntax +end + +local function parsefields(line) + local _, _, bits = line:find("^([^ ]+) ") + if #bits ~= 32 then + error("'"..bits.."' isn't 32 bits long") + end + + local fields = {} + local i = 1 + while i ~= 33 do + local c = line:sub(i, i) + if c ~= "." then + local f = { pos=i } + if c:find("%w") then + f.size = 1 + f.value = c + elseif c == "<" then + local _, newi, name = line:find("^<%-*(%w+)%-*>", i) + f.size = 1 + newi - i + f.value = name + i = newi + else + error("bad field char '"..c.."' in '"..line.."'") + end + if f.value:find("[0-9]+") then + f.literal = true + f.variable = false + else + f.literal = false + f.variable = true + end + -- Convert from PowerPC numbering to sane numbering + f.pos = 33-(f.pos + f.size) + fields[#fields+1] = f + if f.value then + fields[f.value] = f + end + end + i = i + 1 + end + + local value = 0 + for _, f in ipairs(fields) do + if f.literal then + local s = math.pow(2, f.pos) + value = value + f.value*s + end + end + fields.value = value + + return fields +end + + +local function emit(fields, code) + local mask = 0 + local value = 0 + for _, f in ipairs(fields) do + if f.literal then + local s = math.pow(2, f.pos) + local m = math.pow(2, f.size) - 1 + mask = mask + m*s + value = value + f.value*s + end + end + + print(string.format("if ((value & 0x%x) == 0x%x) {", mask, value)) + for _, f in ipairs(fields) do + if f.variable then + local m = math.pow(2, f.size) - 1 + print(string.format("uint32_t %s = (value >> %d) & 0x%x;", f.value, f.pos, m)) + end + end + + print(code) + print("return;") + print("}") +end + +while true do + local line = io.stdin:read("*l") + if not line then + break + end + line = line:gsub("#.*$", "") + line = line:gsub(" *$", "") + if line:find("^%%token ") then + addword(line:sub(8)) + elseif line ~= "" then + local fields = parsefields(line) + local syntax = parsesyntax(line:sub(34, #line)) + insns[#insns+1] = { + fields=parsefields(line), + syntax=parsesyntax(line:sub(34, #line)) + } + end +end + +local definitionsfp = io.open(args[1], "wb") +for word, value in pairs(words) do + definitionsfp:write("%token OP_", tostring(value), " /* ", word, " */\n") +end +definitionsfp:close() + +local tokensfp = io.open(args[2], "wb") +for word, value in pairs(words) do + tokensfp:write("0, OP_", value, ", 0, \"", word, "\",\n") +end +tokensfp:close() + +local rulesfp = io.open(args[3], "wb") +rulesfp:write("operation\n") +for index, insn in ipairs(insns) do + if index == 1 then + rulesfp:write("\t:") + else + rulesfp:write("\t|") + end + for _, word in ipairs(insn.syntax) do + if word.word then + rulesfp:write(" OP_", word.word) + end + if word.punct then + rulesfp:write(" ", word.punct) + end + if word.token then + rulesfp:write(" ", word.token) + end + end + rulesfp:write("\n") + + rulesfp:write("\t{ emit4(", string.format("0x%08x", insn.fields.value)) + for wordindex, word in ipairs(insn.syntax) do + if word.token then + for _, alias in ipairs(word) do + local f = insn.fields[alias] + if not f then + error("reference to field "..alias.." which doesn't exist") + end + local mask = math.pow(2, f.size) - 1 + rulesfp:write(" | (($", wordindex, + " & ", string.format("0x%x", mask), ") << ", f.pos, ")") + end + end + end + rulesfp:write("); }\n") +end +rulesfp:close() + diff --git a/mach/xr17032/libem/aar4.s b/mach/xr17032/libem/aar4.s new file mode 100644 index 000000000..e33165b9d --- /dev/null +++ b/mach/xr17032/libem/aar4.s @@ -0,0 +1,47 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Get address of element of bounds-checked array. + * + * Stack: ( array-adr index descriptor-adr -- element-adr ) + * Sets r2 = size of element for .los4, .sts4 + * Preserves r25 (the last volatile register) + * + * An array descriptor is: + * + * +0 lower bound + * +4 range (upper bound - lower bound); *inclusive* + * +8 element size + */ + +.sect .text +.define .aar4 +.aar4: + lw r4, 0(sp) ! r4 = address of descriptor + lw r5, 4(sp) ! r5 = index + lw r6, 8(sp) ! r6 = address of array + + lw r7, 0(r4) ! r7 = lower bound + slt at, r5, r7 ! at = index < lower bound + bne at, zero, .trap_earray + nop + subu r5, r5, r7 ! adjust index for non-zero lower bound + + lw at, 4(r4) ! at = range + slt at, at, r5 ! at = range < adjusted index + bne at, zero, .trap_earray + nop + + lw r2, 8(r4) ! r2 = size of element + mul r5, r5, r2 ! scale index by size + addu r5, r5, r6 ! calculate address of element + + sw r5, 8(sp) ! push address of element + addiu sp, sp, 8 + jr ra + nop + +.define .trap_earray +.trap_earray: + li r4, 0 ! EARRAY = 0 in h/em_abs.h + b .trp diff --git a/mach/xr17032/libem/and.s b/mach/xr17032/libem/and.s new file mode 100644 index 000000000..5f0eacb2c --- /dev/null +++ b/mach/xr17032/libem/and.s @@ -0,0 +1,30 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* + * Set intersection. + * Stack: ( a b size -- a&b ) + */ + +.sect .text +.define .and +.and: + lw r4, 0(sp) ! r4 = size + addiu sp, sp, 4 ! sp points at b + addu r5, sp, r4 ! r5 points at a + srl r4, r4, 2 ! r4 = count of words + +1: + lw at, 0(r5) ! load a + lw r6, 0(sp) ! load b + and at, at, r6 ! combine + sw at, 0(r5) ! write back to a + addiu r5, r5, 4 + addiu sp, sp, 4 + addiu r4, r4, -1 + bne r4, zero, 1b + nop + + jr ra + nop + diff --git a/mach/xr17032/libem/bls4.s b/mach/xr17032/libem/bls4.s new file mode 100644 index 000000000..35d287f5b --- /dev/null +++ b/mach/xr17032/libem/bls4.s @@ -0,0 +1,31 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Does a block move of words between non-overlapping buffers. + * Stack: ( src dst len -- ) + */ + +.sect .text +.define .bls4 +.bls4: + lw r4, 0(sp) ! r4=len + lw r5, 4(sp) ! r5=dst + lw r6, 8(sp) ! r6=src + addiu sp, sp, 12 + + srl r4, r4, 2 ! convert len to words +1: + beq r4, zero, 2f + nop + + lw at, 0(r6) + sw at, 0(r5) + addiu r6, r6, 4 + addiu r5, r5, 4 + addiu r4, r4, -1 + b 1b + nop + +2: + jr ra + nop diff --git a/mach/xr17032/libem/build.lua b/mach/xr17032/libem/build.lua new file mode 100644 index 000000000..9145f6730 --- /dev/null +++ b/mach/xr17032/libem/build.lua @@ -0,0 +1,43 @@ +for _, plat in ipairs(vars.plats) do + acklibrary { + name = "headers_"..plat, + } + + acklibrary { + name = "lib_"..plat, + srcs = { + "./aar4.s", + "./and.s", + "./bls4.s", + "./cms.s", + "./compareul.s", + "./com.s", + "./csa.s", + "./csb.s", + "./c_ud_i.s", + "./c_uf_i.s", + "./c_ui_d.s", + "./c_ui_f.s", + "./dus4.s", + "./exg.s", + "./fef8.s", + "./fif8.s", + "./inn.s", + "./ior.s", + "./lar4.s", + "./los4.s", + "./rck.s", + "./sar4.s", + "./set.s", + "./sts4.s", + "./trp.s", + "./xor.s", + "./zer.s", + }, + vars = { plat = plat }, + deps = { + "h+emheaders", + "+headers_"..plat, + } + } +end diff --git a/mach/xr17032/libem/c_ud_i.s b/mach/xr17032/libem/c_ud_i.s new file mode 100644 index 000000000..8ba1bfc04 --- /dev/null +++ b/mach/xr17032/libem/c_ud_i.s @@ -0,0 +1,36 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +.sect .text +.define .c_ud_i +.c_ud_i: + /* Input: f0 + * Output: r2 + * Only at and f30/f31 may be used. + */ + + lui at, ha16[.fd_80000000] + ldc1 f30, lo16[.fd_80000000] (at) + c.le.d 0, f30, f0 + bc1t toobig + nop + + trunc.w.d f0, f0 + mfc1 r2, f0 + jr ra + nop + +toobig: + sub.d f0, f0, f30 + trunc.w.d f0, f0 + mfc1 r2, f0 + lui at, 0x8000 ! load 0x80000000 + addu r2, r2, at + jr ra + nop + +.sect .rom +.define .fd_80000000 +.fd_80000000: + .dataf8 2147483648.0 + diff --git a/mach/xr17032/libem/c_uf_i.s b/mach/xr17032/libem/c_uf_i.s new file mode 100644 index 000000000..27f14e03e --- /dev/null +++ b/mach/xr17032/libem/c_uf_i.s @@ -0,0 +1,38 @@ +# +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text +.define .c_uf_i +.c_uf_i: + /* Input: f0 + * Output: r2 + * Only at and f30/f31 may be used. + */ + + lui at, ha16[.ff_80000000] + lwc1 f30, lo16[.ff_80000000] (at) + c.le.s 0, f30, f0 + bc1t toobig + nop + + trunc.w.s f0, f0 + mfc1 r2, f0 + jr ra + nop + +toobig: + sub.s f0, f0, f30 + trunc.w.s f0, f0 + mfc1 r2, f0 + lui at, 0x8000 ! load 0x80000000 + addu r2, r2, at + jr ra + nop + +.sect .rom +.ff_80000000: + .dataf4 2147483648.0 + diff --git a/mach/xr17032/libem/c_ui_d.s b/mach/xr17032/libem/c_ui_d.s new file mode 100644 index 000000000..0432d9074 --- /dev/null +++ b/mach/xr17032/libem/c_ui_d.s @@ -0,0 +1,25 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +.sect .text +.define .c_ui_d +.c_ui_d: + /* Input: r2 + * Output: f0 + * Only at and f30/f31 may be used. + */ + mtc1 r2, f0 + cvt.d.w f0, f0 + bgez r2, nonnegative + nop + + lui at, ha16[.fd_100000000] + ldc1 f30, lo16[.fd_100000000] (at) + add.d f0, f0, f30 +nonnegative: + jr ra + nop + +.sect .rom +.fd_100000000: + .dataf8 4294967296.0 diff --git a/mach/xr17032/libem/c_ui_f.s b/mach/xr17032/libem/c_ui_f.s new file mode 100644 index 000000000..e22745afb --- /dev/null +++ b/mach/xr17032/libem/c_ui_f.s @@ -0,0 +1,26 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +.sect .text +.define .c_ui_f +.c_ui_f: + /* Input: r2 + * Output: f0 + * Only at and f30/f31 may be used. + */ + mtc1 r2, f0 + cvt.s.w f0, f0 + bgez r2, nonnegative + nop + + lui at, ha16[.fs_100000000] + ldc1 f30, lo16[.fs_100000000] (at) + add.d f0, f0, f30 +nonnegative: + jr ra + nop + +/* 4294967296 as a float. */ +.sect .rom +.fs_100000000: + .dataf4 4294967296.0 diff --git a/mach/xr17032/libem/cms.s b/mach/xr17032/libem/cms.s new file mode 100644 index 000000000..e7e87e731 --- /dev/null +++ b/mach/xr17032/libem/cms.s @@ -0,0 +1,35 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* + * Set comparison Returns 0 if the sets were equal. + * Stack: ( a b size -- a!=b ) + */ + +.sect .text +.define .cms +.cms: + lw r4, 0(sp) ! r4 = size; sp points at b-word + addu r5, sp, r4 ! r5 points at a-word + addu r6, r5, r4 ! r6 is final sp-word + srl r4, r4, 2 ! r4 = count of words + li r8, 1 ! result + +1: + lw at, 4(r5) ! load a + lw r7, 4(sp) ! load b + bne at, r7, exit ! branch if not equal + nop + addiu r5, r5, 4 + addiu sp, sp, 4 + addiu r4, r4, -1 + bne r4, zero, 1b + nop + + li r8, 0 ! Update result. +exit: + mov sp, r6 + sw r8, 0(sp) + jr ra + nop + diff --git a/mach/xr17032/libem/com.s b/mach/xr17032/libem/com.s new file mode 100644 index 000000000..ffabe9f5e --- /dev/null +++ b/mach/xr17032/libem/com.s @@ -0,0 +1,28 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* + * Set complement. + * Stack: ( a size -- ~a ) + */ + +.sect .text +.define .com +.com: + lw r4, 0(sp) ! r4 = size + addiu sp, sp, 4 + mov r5, sp ! r5 points to set + srl r4, r4, 2 ! r4 = word count + +1: + lw at, 0(r5) + nor at, zero, at + sw at, 0(r5) + addiu r5, r5, 4 + addiu r4, r4, -1 + bne r4, zero, 1b + nop + + jr ra + nop + diff --git a/mach/xr17032/libem/compareul.s b/mach/xr17032/libem/compareul.s new file mode 100644 index 000000000..dccd92234 --- /dev/null +++ b/mach/xr17032/libem/compareul.s @@ -0,0 +1,39 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* + * 64-big unsigned tristate comparison. + * Inputs: + * r2r3: left + * r4r5: right + * Outputs; + * r2: result + */ + +.sect .text +.define .compareul +.compareul: + /* Compare high words. */ + + sltu at, r3, r5 ! if r3r5, then 1 + bne at, zero, exit + nop + + /* High words are equal --- compare low words. */ + + sltu at, r2, r4 ! if r2r4, then 1 +exit: + mov r2, at + jr ra + nop + diff --git a/mach/xr17032/libem/csa.s b/mach/xr17032/libem/csa.s new file mode 100644 index 000000000..bbc386be0 --- /dev/null +++ b/mach/xr17032/libem/csa.s @@ -0,0 +1,42 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* This is not a subroutine, but just a + * piece of code that computes the jump- + * address and jumps to it. + * traps if resulting address is zero + * + * Stack: ( value tableaddr -- ) + */ + +.sect .text +.define .csa +.csa: + lw r4, 0(sp) /* r4 = table */ + lw r5, 4(sp) /* r5 = value */ + addiu sp, sp, 8 + + lw r6, 0(r4) /* r6 = default target */ + lw r7, 4(r4) /* r7 = lower bound */ + subu r5, r5, r7 /* adjust value */ + bltz r5, 1f /* jump to default if out of range */ + nop + + lw r7, 8(r4) /* fetch range */ + subu r7, r7, r5 /* compute difference within range */ + bltz r7, 1f /* jump to default if out of range */ + nop + + addiu r4, r4, 12 /* skip header */ + sll r5, r5, 2 /* value = value<<2 */ + addu r4, r4, r5 /* find address of target */ + lw r6, 0(r4) /* r6 = new target */ + +1: + beq r6, zero, 2f /* trap if null */ + nop + jr r6 /* otherwise jump */ + nop +2: + j .trap_ecase + nop diff --git a/mach/xr17032/libem/csb.s b/mach/xr17032/libem/csb.s new file mode 100644 index 000000000..c04382b79 --- /dev/null +++ b/mach/xr17032/libem/csb.s @@ -0,0 +1,47 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* this is not a subroutine, but just a + * piece of code that computes the jump- + * address and jumps to it. + * traps if resulting address is zero + * + * Stack: ( value tableaddr -- ) + */ + +.sect .text +.define .csb +.csb: + lw r4, 0(sp) ! r4 = address of table + lw r5, 4(sp) ! r5 = value + addiu sp, sp, 8 + + lw r6, 0(r4) ! r6 = default target + lw r7, 4(r4) ! r7 = table count + +2: + addiu r7, r7, -1 ! decrement count + bltz r7, 1f ! exit loop if out + nop + + lw r8, 8(r4) ! candidate value + beq r8, r5, 3f ! branch if equal + nop + + addiu r4, r4, 8 ! next entry + b 2b + nop + +3: + /* We found an item in the table. */ + lw r6, 12(r4) ! load jump target + /* fall through */ +1: + beq r6, zero, 4f /* trap if null */ + nop + jr r6 /* otherwise jump */ + nop +4: + j .trap_ecase + nop + diff --git a/mach/xr17032/libem/dus4.s b/mach/xr17032/libem/dus4.s new file mode 100644 index 000000000..ca5a295a9 --- /dev/null +++ b/mach/xr17032/libem/dus4.s @@ -0,0 +1,28 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Duplicates some words on top of stack. + * Stack: ( a size -- a a ) + */ + +.sect .text +.define .dus4 +.dus4: + lw r4, 0(sp) ! r4 = size + addiu sp, sp, 4 ! sp = pointer to a + mov r5, sp ! r5 = pointer to a + subu sp, sp, r4 ! sp = pointer to newa + mov r6, sp ! r6 = pointer to b + + srl r4, r4, 2 ! r4 = number of words +1: + lw at, 0(r5) + sw at, 0(r6) + addiu r5, r5, 4 + addiu r6, r6, 4 + addiu r4, r4, -1 + bne r4, zero, 1b + nop + + jr ra + nop diff --git a/mach/xr17032/libem/exg.s b/mach/xr17032/libem/exg.s new file mode 100644 index 000000000..24753f328 --- /dev/null +++ b/mach/xr17032/libem/exg.s @@ -0,0 +1,31 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Exchange top two values on stack. + * Stack: ( a b size -- b a ) + */ + +.sect .text +.define .exg +.exg: + lw r4, 0(sp) ! r4 = size + srl r5, r4, 2 ! r5 = number of words + addiu sp, sp, 4 ! adjust stack for input/output parameter size + + mov r6, sp ! r6 = pointer to b + addu r7, r6, r4 ! r7 = pointer to a + + ! Loop to swap each pair of words. +1: + lw r8, 0(r6) + lw r9, 0(r7) + sw r9, 0(r6) + sw r8, 0(r7) + addiu r6, r6, 4 + addiu r7, r7, 4 + addiu r5, r5, -1 + bne r5, zero, 1b + nop + + jr ra + nop diff --git a/mach/xr17032/libem/fef8.s b/mach/xr17032/libem/fef8.s new file mode 100644 index 000000000..4fa545676 --- /dev/null +++ b/mach/xr17032/libem/fef8.s @@ -0,0 +1,56 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Split a double-precision float into fraction and exponent, like + * frexp(3) in C, http://en.cppreference.com/w/c/numeric/math/frexp + * + * Stack: ( double -- fraction exponent ) + */ + +#define DBL_EXPBITS 11 +#define DBL_FRACHBITS 20 +#define DBL_FRACLBITS 32 +#define DBL_FRACBITS 52 +#define DBL_EXP_INFNAN 2047 + +#define DBL_EXP_BIAS 1023 + +.sect .text +.define .fef8 +.fef8: + lw r4, 0(sp) ! r4 = low word (bits 0..31) + lw r5, 4(sp) ! r5 = high word (bits 32..63) + + ! IEEE double = sign * 1.fraction * 2**(exponent - 1023) + ! sign exponent fraction + ! 31 30..19 18..0, 31..0 + ! + ! IEEE exponent = 1022 in [0.5, 1) or (-1, -0.5]. + + ext r7, r5, DBL_FRACHBITS, DBL_EXPBITS ! r7 = IEEE exponent + beq r7, zero, zeroexp ! this number is zero or denormalised, treat specially + nop + + li at, DBL_EXP_INFNAN + beq r7, at, return ! just return if infinity or NaN + nop + + addiu r7, r7, -[DBL_EXP_BIAS-1] ! undo exponent bias + li at, DBL_EXP_BIAS-1 + ins r5, at, DBL_FRACHBITS, DBL_EXPBITS ! replace exponent +return: + addiu sp, sp, -4 ! returning one more quad than we got + sw r5, 8(sp) + sw r6, 4(sp) + sw r7, 0(sp) + jr ra + nop + + /* We received a denormalised number or zero. */ +zeroexp: + /* TODO: we just assume that the number is zero here. */ + mov r5, zero + mov r6, zero + mov r7, zero + b return + nop diff --git a/mach/xr17032/libem/fif8.s b/mach/xr17032/libem/fif8.s new file mode 100644 index 000000000..e03812b4b --- /dev/null +++ b/mach/xr17032/libem/fif8.s @@ -0,0 +1,69 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Multiplies two double-precision floats, then splits the product into + * fraction and integer, both as floats, like modf(3) in C, + * http://en.cppreference.com/w/c/numeric/math/modf + * + * Stack: ( a b -- fraction integer ) + */ + +.sect .text +.define .fif8 +.fif8: + ldc1 f0, 8(sp) ! f0 = a + ldc1 f2, 0(sp) ! f2 = b + mul.d f0, f0, f2 ! f0 = a * b + abs.d f2, f0 ! f2 = abs(f0) + + lui at, ha16[max_power_of_two] + ldc1 f4, lo16[max_power_of_two] (at) ! f4 = max power of two + + mov.d f6, f2 ! we're going to assemble the integer part in f6 + c.lt.d 0, f4, f2 ! if absolute value too big, it must be integral + bc1t 0, return + nop + + ! Crudely strip off the fractional part. + + add.d f6, f2, f4 ! f6 = absolute value + max power of two + sub.d f6, f6, f4 ! f6 -= max_power_of_two + + ! The above might round, so correct that. + + lui at, ha16[one] + ldc1 f8, lo16[one] (at) ! f8 = 1.0 +1: + c.le.d 0, f6, f2 ! if result <= absolute value, stop + bc1t 0, 2f + nop + + sub.d f6, f6, f8 ! result -= 1.0 + b 1b + nop +2: + + ! Correct the sign of the result. + + mtc1 zero, f8 + mthc1 zero, f8 ! f8 = 0.0 + c.lt.d 0, f0, f8 ! if original value was negative + bc1f 0, 1f + nop + neg.d f6, f6 ! negate the result +1: + +return: + sdc1 f6, 0(sp) ! store integer part + sub.d f6, f0, f6 ! calculate fractional part + sdc1 f6, 8(sp) ! store fractional part + jr ra + nop + +! doubles >= MAXPOWTWO are already integers +.sect .rom +max_power_of_two: + .dataf8 4.503599627370496000E+15 + +one: + .dataf8 1.0 diff --git a/mach/xr17032/libem/inn.s b/mach/xr17032/libem/inn.s new file mode 100644 index 000000000..a0fcb0931 --- /dev/null +++ b/mach/xr17032/libem/inn.s @@ -0,0 +1,32 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Tests a bit in a bitset on the stack. + * + * Stack: ( bitset bitnum setsize -- bool ) + * + * Some back ends push false if bitnum is too large. We don't because + * the compilers tend to pass a small enough bitnum. + */ + +.sect .text +.define .inn +.inn: + lw r4, 0(sp) ! r4 = size of set (bytes) + lw r5, 4(sp) ! r5 = bit number + addiu sp, sp, 4 ! sp now points to word below bitset + + andi r6, r5, ~31 ! r6 = bit offset of base of word in set + srl r6, r6, 3 ! r6 = byte offset of base of word in set + addu r6, sp, r6 ! r6 = address of word in set + lw r6, 4(r6) ! r6 = word (remember stack offset) + + andi r7, r5, 31 ! r7 = bit number within word + srlv r6, r6, r7 ! r7 = candidate bit now at bit 0 + andi r6, r6, 1 ! r7 = bool + + addu sp, sp, r4 ! retract over bitfield (remember stack offset) + sw r6, 0(sp) ! store result + + jr ra + nop diff --git a/mach/xr17032/libem/ior.s b/mach/xr17032/libem/ior.s new file mode 100644 index 000000000..df2828dfe --- /dev/null +++ b/mach/xr17032/libem/ior.s @@ -0,0 +1,30 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* + * Set union. + * Stack: ( a b size -- a|b ) + */ + +.sect .text +.define .ior +.ior: + lw r4, 0(sp) ! r4 = size + addiu sp, sp, 4 ! sp points at b + addu r5, sp, r4 ! r5 points at a + srl r4, r4, 2 ! r4 = count of words + +1: + lw at, 0(r5) ! load a + lw r6, 0(sp) ! load b + or at, at, r6 ! combine + sw at, 0(r5) ! write back to a + addiu r5, r5, 4 + addiu sp, sp, 4 + addiu r4, r4, -1 + bne r4, zero, 1b + nop + + jr ra + nop + diff --git a/mach/xr17032/libem/lar4.s b/mach/xr17032/libem/lar4.s new file mode 100644 index 000000000..218496644 --- /dev/null +++ b/mach/xr17032/libem/lar4.s @@ -0,0 +1,23 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Load from bounds-checked array. + * + * Stack: ( array-adr index descriptor-adr -- element ) + */ + +.sect .text +.define .lar4 +.lar4: + mov r25, ra + + jal .aar4 + nop + + /* pass r2 = size from .aar4 to .los4 */ + + jal .los4 + nop + + jr r25 + nop diff --git a/mach/xr17032/libem/los4.s b/mach/xr17032/libem/los4.s new file mode 100644 index 000000000..bebb7b616 --- /dev/null +++ b/mach/xr17032/libem/los4.s @@ -0,0 +1,55 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Loads a variable-sized block onto the stack. + * + * On entry: r2 = size + * Stack: ( address -- block ) + * Preserves r25 for .lar4 and .sar4 + */ + +.sect .text +.define .los4 +.los4: + lw r4, 0(sp) ! r4 = address of source block + + ! Sizes 1 and 2 are handled specially. + + li at, 1 + beq r2, at, byte_sized + nop + + li at, 2 + beq r2, at, word_sized + nop + + ! Else the size must be a multiple of 4. + + srl r5, r2, 2 ! r5 = number of words + addiu sp, sp, 4 ! retract over address + subu sp, sp, r2 ! allocate space for destination block + mov r6, sp ! r6 = start of destination block + +1: + lw at, 0(r4) + sw at, 0(r6) + addiu r4, r4, 4 + addiu r6, r6, 4 + addiu r5, r5, -1 + bne r5, zero, 1b + nop + + jr ra + nop + +byte_sized: + lbu at, 0(r4) + sw at, 0(sp) + jr ra + nop + +word_sized: + lhu at, 0(r4) + sw at, 0(sp) + jr ra + nop diff --git a/mach/xr17032/libem/rck.s b/mach/xr17032/libem/rck.s new file mode 100644 index 000000000..f6d6606a4 --- /dev/null +++ b/mach/xr17032/libem/rck.s @@ -0,0 +1,35 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Bounds check. Traps if the value is out of range. + * Stack: ( value descriptor -- value ) + * + * This ".rck" only works with 4-byte integers. The name is ".rck" and + * not ".rck4" because many back ends only do rck with the word size. + */ + +.sect .text +.define .rck +.rck: + lw r4, 0(sp) ! r4 = pointer to descriptor + addiu sp, sp, 4 ! leave value on stack + lw r5, 0(sp) ! r5 = value + + lw at, 0(r4) ! at = lower bound + slt at, r5, at ! at = r5 < at + bne at, zero, .trap_erange + nop + + lw at, 4(r4) ! at = upper bound + slt at, at, r5 ! at = at < r5 + bne at, zero, .trap_erange + nop + + jr ra + nop + +.define .trap_erange +.trap_erange: + li r4, 1 + j .trp + nop diff --git a/mach/xr17032/libem/sar4.s b/mach/xr17032/libem/sar4.s new file mode 100644 index 000000000..8c70bf553 --- /dev/null +++ b/mach/xr17032/libem/sar4.s @@ -0,0 +1,24 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Store to bounds-checked array. + * + * Stack: ( element array-adr index descriptor-adr -- ) + */ + +.sect .text +.define .sar4 +.sar4: + mov r25, ra + + jal .aar4 + nop + + /* pass r2 = size from .aar4 to .sts4 */ + + jal .sts4 + nop + + jr r25 + nop + diff --git a/mach/xr17032/libem/set.s b/mach/xr17032/libem/set.s new file mode 100644 index 000000000..ec45eb45a --- /dev/null +++ b/mach/xr17032/libem/set.s @@ -0,0 +1,39 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* + * Create singleton set. + * Stack: ( bitnumber size -- set ) + */ + +.sect .text +.define .set +.set: + lw r4, 0(sp) ! r4 = size + lw r5, 4(sp) ! r5 = bit number + addiu sp, sp, 8 + srl r4, r4, 2 ! r4 = word count + + ! Create an empty set by pushing zeros. + +1: + addiu sp, sp, -4 + sw zero, 0(sp) + addiu r4, r4, -1 + bne r4, zero, 1b + nop + + ! sp now points at the set. + + andi r6, r5, ~31 ! r6 = bit offset of base of word in set + srl r6,r6, 3 ! r6 = byte offset of word in set + addu r6, sp, r6 ! r6 = address of word in set + + andi r7, r5, 31 ! r7 = bit number within word + li r8, 1 + sllv r8, r8, r7 ! r8 = word with 1 set + sw r8, 0(r6) ! write to set + + jr ra + nop + diff --git a/mach/xr17032/libem/sts4.s b/mach/xr17032/libem/sts4.s new file mode 100644 index 000000000..56ea9efa8 --- /dev/null +++ b/mach/xr17032/libem/sts4.s @@ -0,0 +1,57 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* Stores a variable-sized block from the stack. + * + * On entry: r2 = size + * Stack: ( block address -- ) + * Preserves r25 for .lar4 and .sar4 + */ + +.sect .text +.define .sts4 +.sts4: + lw r4, 0(sp) ! r4 = address + addiu sp, sp, 4 ! sp = pointer to block + + ! Sizes 1 and 2 are handled specially. + + li at, 1 + beq r2, at, byte_sized + nop + + li at, 2 + beq r2, at, word_sized + nop + + ! Else the size must be a multiple of 4. + + srl r5, r2, 2 ! r5 = number of words + + ! Copy. + +1: + lw at, 0(sp) + sw at, 0(r4) + addiu sp, sp, 4 + addiu r4, r4, 4 + addiu r5, r5, -1 + bne r5, zero, 1b + nop + + jr ra + nop + +byte_sized: + lw at, 0(sp) + sb at, 0(r4) + addiu sp, sp, 4 + jr ra + nop + +word_sized: + lw at, 0(sp) + sh at, 0(r4) + addiu sp, sp, 4 + jr ra + nop diff --git a/mach/xr17032/libem/trp.s b/mach/xr17032/libem/trp.s new file mode 100644 index 000000000..29e8543d7 --- /dev/null +++ b/mach/xr17032/libem/trp.s @@ -0,0 +1,65 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + + +.sect .text +.define .trap_ecase +.trap_ecase: + li r4, 20 ! ECASE = 20 in h/em_abs.h + ! FALLTHROUGH to .trp + +! Raises an EM trap. +! Expects r4 = trap number. + +.define .trp +.trp: + andi at, r4, 0xfff0 + bne at, zero, 1f ! traps > 15 can't be ignored + nop + + lui at, ha16[.ignmask] + lw r5, lo16[.ignmask] (at) ! load ignore mask + srlv r5, r5, r4 + andi r5, r5, 1 + bne r5, zero, return ! return if ignoring trap + nop +1: + + lui at, ha16[.trppc] + lw r5, lo16[.trppc] (at) ! r5 = user trap routine + sw zero, lo16[.trppc] (at) ! reset the trap routine for next time + beq r5, zero, abend ! abort if no user trap routine + nop + + addiu sp, sp, -8 + sw r4, 0(sp) ! push trap number + sw ra, 4(sp) ! and link register + jalr r5 ! call trap routine + nop + + lw ra, 4(sp) ! ...and return + addiu sp, sp, 8 +return: + jr ra + nop + + ! No trap handler; write error message and exit. +abend: + addiu sp, sp, -12 + li at, 2 + sw at, 0(sp) + lui at, hi16[message] + ori at, at, lo16[message] + sw at, 4(sp) + li at, 6 + sw at, 8(sp) + jal _write ! write(2, message, 6) + nop + + li at, 1 + sw at, 0(sp) + j __exit ! _exit(1) + +.sect .rom +message: + .ascii "TRAP!\n" diff --git a/mach/xr17032/libem/xor.s b/mach/xr17032/libem/xor.s new file mode 100644 index 000000000..ad23b1d52 --- /dev/null +++ b/mach/xr17032/libem/xor.s @@ -0,0 +1,30 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* + * Set xor.. + * Stack: ( a b size -- a^b ) + */ + +.sect .text +.define .xor +.xor: + lw r4, 0(sp) ! r4 = size + addiu sp, sp, 4 ! sp points at b + addu r5, sp, r4 ! r5 points at a + srl r4, r4, 2 ! r4 = count of words + +1: + lw at, 0(r5) ! load a + lw r6, 0(sp) ! load b + xor at, at, r6 ! combine + sw at, 0(r5) ! write back to a + addiu r5, r5, 4 + addiu sp, sp, 4 + addiu r4, r4, -1 + bne r4, zero, 1b + nop + + jr ra + nop + diff --git a/mach/xr17032/libem/zer.s b/mach/xr17032/libem/zer.s new file mode 100644 index 000000000..b48fb8ffc --- /dev/null +++ b/mach/xr17032/libem/zer.s @@ -0,0 +1,25 @@ +# +.sect .text; .sect .rom; .sect .data; .sect .bss + +/* + * Create empty set. + * Stack: ( size -- set ) + */ + +.sect .text +.define .zer +.zer: + lw r4, 0(sp) ! r4 = size + addiu sp, sp, 4 + srl r4, r4, 2 ! r4 = word count + +1: + addiu sp, sp, -4 + sw zero, 0(sp) + addiu r4, r4, -1 + bne r4, zero, 1b + nop + + jr ra + nop + diff --git a/mach/xr17032/libend/build.lua b/mach/xr17032/libend/build.lua new file mode 100644 index 000000000..bfbf21cd0 --- /dev/null +++ b/mach/xr17032/libend/build.lua @@ -0,0 +1,13 @@ +for _, plat in ipairs(vars.plats) do + acklibrary { + name = "lib_"..plat, + srcs = { + "./edata.s", + "./em_end.s", + "./end.s", + "./etext.s", + }, + vars = { plat = plat }, + } +end + diff --git a/mach/xr17032/libend/edata.s b/mach/xr17032/libend/edata.s new file mode 100644 index 000000000..f53adc109 --- /dev/null +++ b/mach/xr17032/libend/edata.s @@ -0,0 +1,9 @@ +.sect .text +.sect .rom +.sect .data +.sect .bss +.define _edata +.sect .data + .align 4 + .sect .data +_edata: diff --git a/mach/xr17032/libend/em_end.s b/mach/xr17032/libend/em_end.s new file mode 100644 index 000000000..0271f09f6 --- /dev/null +++ b/mach/xr17032/libend/em_end.s @@ -0,0 +1,24 @@ +! $Source$ +! $State$ +! $Revision$ + +.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 + .align 4 +endtext: + .sect .rom + .align 4 +endrom: + .sect .data + .align 4 +enddata: + .sect .end + .align 4 +__end: +endbss: diff --git a/mach/xr17032/libend/end.s b/mach/xr17032/libend/end.s new file mode 100644 index 000000000..93a1e6e00 --- /dev/null +++ b/mach/xr17032/libend/end.s @@ -0,0 +1,7 @@ +.sect .text +.sect .rom +.sect .data +.sect .bss +.define _end +.sect .end ! only for declaration of _end, __end and endbss. +_end: diff --git a/mach/xr17032/libend/etext.s b/mach/xr17032/libend/etext.s new file mode 100644 index 000000000..8c7453cb4 --- /dev/null +++ b/mach/xr17032/libend/etext.s @@ -0,0 +1,9 @@ +.sect .text +.sect .rom +.sect .data +.sect .bss +.define _etext +.sect .text + .align 4 + .sect .text +_etext: diff --git a/mach/xr17032/mcg/build.lua b/mach/xr17032/mcg/build.lua new file mode 100644 index 000000000..ed2d2687c --- /dev/null +++ b/mach/xr17032/mcg/build.lua @@ -0,0 +1,7 @@ +bundle { + name = "headers", + srcs = { + "./platform.c", + } +} + diff --git a/mach/xr17032/mcg/platform.c b/mach/xr17032/mcg/platform.c new file mode 100644 index 000000000..a29a69ebe --- /dev/null +++ b/mach/xr17032/mcg/platform.c @@ -0,0 +1,309 @@ +#include "mcg.h" + +/* mcg stack frames are laid out as: + * + * | ...params... + * | --------------- <- ab + * | old FR + * | old FP + * | --------------- <- fp (a.k.a. lb) + * | locals + * | --------------- + * | spills + * | --------------- <- sb + * | saved regs + * | --------------- <- sp, rb + * V ...user area... + * + * st indexes up; lb indexes down. + * + * Note that [fp] == old_fp and ab == fp + 8. + */ + +static ARRAYOF(struct hreg) saved_regs; + +void platform_calculate_offsets(void) +{ + int i; + + saved_regs.count = 0; + for (i=0; iusedregs.count; i++) + { + struct hreg* hreg = current_proc->usedregs.item[i]; + + if (!(hreg->attrs & burm_volatile_ATTR) && + ((hreg->attrs & burm_long_ATTR) || (hreg->attrs & burm_double_ATTR))) + { + hreg->offset = current_proc->saved_size; + current_proc->saved_size += 8; + array_append(&saved_regs, hreg); + } + } + for (i=0; iusedregs.count; i++) + { + struct hreg* hreg = current_proc->usedregs.item[i]; + + if (!(hreg->attrs & burm_volatile_ATTR) && + ((hreg->attrs & burm_int_ATTR) || (hreg->attrs & burm_float_ATTR))) + { + hreg->offset = current_proc->saved_size; + current_proc->saved_size += 4; + array_append(&saved_regs, hreg); + } + } + + current_proc->fp_to_ab = 8; + current_proc->fp_to_lb = 0; + current_proc->fp_to_sb = -(current_proc->locals_size + current_proc->spills_size); + current_proc->fp_to_rb = current_proc->fp_to_sb - current_proc->saved_size; +} + +struct hop* platform_prologue(void) +{ + int i; + int spoffset = current_proc->saved_size + current_proc->spills_size + + current_proc->locals_size; + struct hop* hop = new_hop(current_proc->entry, NULL); + + hop_add_insel(hop, "! locals_size = %d", current_proc->locals_size); + hop_add_insel(hop, "! spills_size = %d", current_proc->spills_size); + hop_add_insel(hop, "! saved_size = %d", current_proc->saved_size); + hop_add_insel(hop, "! params @ fp+%d", current_proc->fp_to_ab); + hop_add_insel(hop, "! lr @ fp+4"); + hop_add_insel(hop, "! fp @ fp+0"); + hop_add_insel(hop, "! locals @ fp-%d to fp+0", + current_proc->locals_size); + hop_add_insel(hop, "! spills @ fp-%d to fp-%d", + -current_proc->fp_to_sb, current_proc->locals_size); + for (i=saved_regs.count-1; i>=0; i--) + { + struct hreg* hreg = saved_regs.item[i]; + hop_add_insel(hop, "! %s @ fp-%d", + hreg->id, -(current_proc->fp_to_rb + hreg->offset)); + } + + hop_add_insel(hop, "addiu sp, sp, %d", -(spoffset + 8)); + hop_add_insel(hop, "sw fp, %d(sp)", spoffset + 0); + hop_add_insel(hop, "sw ra, %d(sp)", spoffset + 4); + hop_add_insel(hop, "addiu fp, sp, %d", spoffset); + + /* Saved reg offsets are negative. */ + for (i=0; iattrs & burm_int_ATTR) + hop_add_insel(hop, "sw %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_long_ATTR) + { + hop_add_insel(hop, "sw %0H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset + 0); + hop_add_insel(hop, "sw %1H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset + 4); + } + else if (hreg->attrs & burm_float_ATTR) + hop_add_insel(hop, "swc1 %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_double_ATTR) + hop_add_insel(hop, "sdc1 %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else + fatal("unsavable non-volatile register %s", hreg->id); + } + return hop; +} + +struct hop* platform_epilogue(void) +{ + struct hop* hop = new_hop(current_proc->exit, NULL); + int i; + + for (i=0; iattrs & burm_int_ATTR) + hop_add_insel(hop, "lw %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_long_ATTR) + { + hop_add_insel(hop, "lw %0H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset + 0); + hop_add_insel(hop, "lw %1H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset + 4); + } + else if (hreg->attrs & burm_float_ATTR) + hop_add_insel(hop, "lwc1 %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else if (hreg->attrs & burm_double_ATTR) + hop_add_insel(hop, "ldc1 %H, %d(fp)", + hreg, current_proc->fp_to_rb + hreg->offset); + else + fatal("unloadable non-volatile register %s", hreg->id); + } + + hop_add_insel(hop, "lw ra, 4(fp)"); + hop_add_insel(hop, "lw at, 0(fp)"); /* load old fp */ + hop_add_insel(hop, "addiu sp, fp, %d", current_proc->fp_to_ab); + hop_add_insel(hop, "jr ra"); + hop_add_insel(hop, "mov fp, at"); /* delay slot */ + + return hop; +} + +struct hop* platform_move(struct basicblock* bb, struct vreg* vreg, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + if ((src->attrs & TYPE_ATTRS) != (dest->attrs & TYPE_ATTRS)) + fatal("hreg move of %%%d from %s to %s with mismatched types", vreg->id, src->id, dest->id); + else + { + uint32_t type = src->attrs & TYPE_ATTRS; + tracef('R', "R: non-converting move from %s to %s of type 0x%x\n", src->id, dest->id, type); + + if (!src->is_stacked && dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "sw %H, %S(fp) ! %H", src, dest, dest); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "sw %0H, 0+%S(fp) ! %H", src, dest, dest); + hop_add_insel(hop, "sw %1H, 4+%S(fp) ! %H", src, dest, dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "swc1 %H, %S(fp) ! %H", src, dest, dest); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "sdc1 %H, %S(fp) ! %H", src, dest, dest); + break; + + default: + goto nomove; + } + } + else if (src->is_stacked && !dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "lw %H, %S(fp) ! %H", dest, src, src); + break; + + case burm_long_ATTR: + /* Can't load straight into dest because it might overlap with src. */ + hop_add_insel(hop, "lw at, 0+%S(fp) ! %H", dest, src, src); + hop_add_insel(hop, "lw %1H, 4+%S(fp) ! %H", dest, src, src); + hop_add_insel(hop, "mov %0H, at", dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "lwc1 %H, %S(fp) ! %H", dest, src, src); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "ldc1 %H, %S(fp) ! %H", dest, src, src); + break; + + default: + goto nomove; + } + } + else if (!src->is_stacked && !dest->is_stacked) + { + switch (type) + { + case burm_int_ATTR: + hop_add_insel(hop, "mov %H, %H", dest, src); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "mov %0H, %0H", dest, src); + hop_add_insel(hop, "mov %1H, %1H", dest, src); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "mov.s %H, %H", dest, src); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "mov.d %H, %H", dest, src); + break; + + default: + goto nomove; + } + } + else if (src->is_stacked && dest->is_stacked) + fatal("tried to move stacked object %%%d of type 0x%x from %s to %s", vreg->id, type, src->id, dest->id); + else + goto nomove; + } + + return hop; + +nomove: + fatal("cannot move %s to %s", src->id, dest->id); +} + +struct hop* platform_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + tracef('R', "R: swap of %s to %s\n", src->id, dest->id); + assert(!src->is_stacked); + assert(!dest->is_stacked); + assert((src->attrs & TYPE_ATTRS) == (dest->attrs & TYPE_ATTRS)); + + switch (src->attrs & TYPE_ATTRS) + { + case burm_int_ATTR: + hop_add_insel(hop, "mov at, %H", src); + hop_add_insel(hop, "mov %H, %H", src, dest); + hop_add_insel(hop, "mov %H, at", dest); + break; + + case burm_long_ATTR: + hop_add_insel(hop, "mov at, %0H", src); + hop_add_insel(hop, "mov %0H, %0H", src, dest); + hop_add_insel(hop, "mov %0H, at", dest); + + hop_add_insel(hop, "mov at, %1H", src); + hop_add_insel(hop, "mov %1H, %1H", src, dest); + hop_add_insel(hop, "mov %1H, at", dest); + break; + + case burm_float_ATTR: + hop_add_insel(hop, "mov.s f30, %H", src); + hop_add_insel(hop, "mov.s %H, %H", src, dest); + hop_add_insel(hop, "mov.s %H, f30", dest); + break; + + case burm_double_ATTR: + hop_add_insel(hop, "mov.d f30, %H", src); + hop_add_insel(hop, "mov.d %H, %H", src, dest); + hop_add_insel(hop, "mov.d %H, f30", dest); + break; + } + + return hop; +} + +const char* platform_label(const char* label) +{ + /* Labels starting with . are internal, not exported, and don't need mangling. */ + + if (label[0] == '.') + return label; + + /* Otherwise, mangle. */ + + return aprintf("_%s", label); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/xr17032/mcg/table b/mach/xr17032/mcg/table new file mode 100644 index 000000000..120e0385b --- /dev/null +++ b/mach/xr17032/mcg/table @@ -0,0 +1,1018 @@ +OPTIONS + + LOWER_PUSHES_TO_LOADS_AND_STORES; + +REGISTERS + + /* Registers are allocated top down. The odd order below is to make sure + * that cheap registers get allocated first. + * + * Attributes may have at most one of: int, float, long, double. These + * indicate that the register is used to store a value of that type. If + * your register can store more than one type, create an alias. Registers + * with none of these cannot be copied by the code generator (and so cannot + * be moved from register to register or spilt). + */ + + r4 int volatile; + r5 int volatile; + r6 int volatile; + r7 int volatile; + r8 int volatile; + r9 int volatile; + r10 int volatile; + r11 int volatile; + r12 int volatile; + r13 int volatile; + r14 int volatile; + r15 int volatile; + r24 int volatile; + r25 int volatile; + r2 int volatile iret; + r3 int volatile; + + r17 named("r16") int; + r18 named("r18") int; + r19 named("r19") int; + r20 named("r20") int; + r21 named("r21") int; + r22 named("r22") int; + r23 named("r23") int; + + r4r5 named("r4", "r5") aliases(r4, r5) long volatile lret1; + r6r7 named("r6", "r7") aliases(r6, r7) long volatile; + r8r9 named("r8", "r9") aliases(r8, r9) long volatile; + r10r11 named("r10", "r11") aliases(r10, r11) long volatile; + r12r13 named("r12", "r13") aliases(r12, r13) long volatile; + r14r15 named("r14", "r15") aliases(r14, r15) long volatile; + r24r25 named("r24", "r25") aliases(r24, r25) long volatile; + r2r3 named("r2", "r3") aliases(r2, r3) long volatile lret; + + r17r18 named("r17", "r18") aliases(r17, r18) long; + r19r20 named("r19", "r20") aliases(r19, r20) long; + r21r22 named("r21", "r22") aliases(r21, r22) long; + + f0 float volatile fret; + f1 float volatile; + f2 float volatile; + f3 float volatile; + f4 float volatile; + f5 float volatile; + f6 float volatile; + f7 float volatile; + f8 float volatile; + f9 float volatile; + f10 float volatile; + f11 float volatile; + f12 float volatile; + f13 float volatile; + f14 float volatile; + f15 float volatile; + f16 float volatile; + f17 float volatile; + f18 float volatile; + f19 float volatile; + + f20 float; + f21 float; + f22 float; + f23 float; + f24 float; + f25 float; + f26 float; + f27 float; + f28 float; + f29 float; + /* f30 and f31 is used by the compiler as a temporary. */ + + d0 named("f0") aliases(f0, f1) double volatile dret; + d2 named("f2") aliases(f2, f3) double volatile; + d4 named("f4") aliases(f4, f5) double volatile; + d6 named("f6") aliases(f6, f7) double volatile; + d8 named("f8") aliases(f8, f9) double volatile; + d10 named("f10") aliases(f10, f11) double volatile; + d12 named("f12") aliases(f12, f13) double volatile; + d14 named("f14") aliases(f14, f15) double volatile; + d16 named("f16") aliases(f16, f17) double volatile; + d18 named("f18") aliases(f18, f19) double volatile; + + d20 named("f20") aliases(f20, f21) double; + d22 named("f22") aliases(f22, f23) double; + d24 named("f24") aliases(f24, f25) double; + d26 named("f26") aliases(f26, f27) double; + d28 named("f28") aliases(f28, f29) double; + + + +DECLARATIONS + + ubyteX; /* bottom 8 bits valid, the rest undefined */ + ubyte0; /* bottom 8 bits valid, the rest 0 */ + ushortX; /* bottom 16 bits valid, the rest undefined */ + ushort0; /* bottom 16 bits valid, the rest 0 */ + + address fragment; + intregorzero fragment; + byteregorzero fragment; + shortregorzero fragment; + + + +PATTERNS + +/* Special */ + + PAIR(BLOCK.I, BLOCK.I); + + + +/* Miscellaneous special things */ + + out:(int)reg = POP.I + emit "lw %out, 0(sp)" + emit "addiu sp, sp, 4" + cost 8; + + out:(long)reg = POP.L + emit "lw %out.0, 4(sp)" + emit "lw %out.1, 0(sp)" + emit "addiu sp, sp, 8" + cost 12; + + out:(float)reg = POP.F + emit "lwc1 %out, 0(sp)" + emit "addiu sp, sp, 4" + cost 8; + + out:(double)reg = POP.D + emit "ldc1 %out, 0(sp)" + emit "addiu sp, sp, 8" + cost 8; + + SETRET.I(in:(iret)reg) + emit "! setret.i" + cost 1; + + SETRET.L(in:(lret)reg) + emit "! setret.l" + cost 1; + + SETRET.F(in:(fret)reg) + emit "! setret.f" + cost 1; + + SETRET.D(in:(dret)reg) + emit "! setret.d" + cost 1; + + STACKADJUST.I(delta:CONST.I) + when signed_constant(%delta, 16) + emit "addiu sp, sp, $delta" + cost 4; + + STACKADJUST.I(in:intregorzero) + emit "addu sp, sp, %in" + cost 4; + + STACKADJUST.I(NEG.I(in:intregorzero)) + emit "subu sp, sp, %in" + cost 4; + + out:(int)reg = GETFP.I + emit "mov %out, fp" + cost 4; + + SETFP.I(in:(int)reg) + emit "mov fp, %in" + cost 4; + + out:(int)reg = CHAINFP.I(in:(int)reg) + emit "lw %out, 0(%in)" + cost 4; + + out:(int)reg = FPTOAB.I(GETFP.I) + emit "addiu %out, fp, 8" + cost 4; + + out:(int)reg = FPTOAB.I(in:(int)reg) + emit "addiu %out, %in, 8" + cost 4; + + out:(int)reg = FPTOLB.I(in:(int)reg) + with %out == %in + cost 1; + + out:(int)reg = GETSP.I + emit "mov %out, sp" + cost 4; + + SETSP.I(in:(int)reg) + emit "mov sp, %in" + cost 4; + + out:(int)reg = ANY.I + cost 1; + + out:(long)reg = ANY.L + cost 1; + + + +/* Memory operations */ + + /* Stores */ + + STORE.L(addr:address, value:(long)reg) + emit "sw %value.0, 0+%addr" + emit "sw %value.1, 4+%addr" + cost 8; + + STORE.I(addr:address, value:intregorzero) + emit "sw %value, %addr" + cost 4; + + STORE.I(label:LABEL.I, value:intregorzero) + emit "lui at, ha16[$label]" + emit "sw %value, lo16[$label] (at)" + cost 8; + + STOREH.I(addr:address, value:shortregorzero) + emit "sh %value, %addr" + cost 4; + + STOREH.I(label:LABEL.I, value:shortregorzero) + emit "lui at, ha16[$label]" + emit "sh %value, lo16[$label] (at)" + cost 8; + + STOREB.I(addr:address, value:byteregorzero) + emit "sb %value, %addr" + cost 4; + + STOREB.I(label:LABEL.I, value:byteregorzero) + emit "lui at, ha16[$label]" + emit "sb %value, lo16[$label] (at)" + cost 8; + + STORE.F(addr:address, value:(float)reg) + emit "swc1 %value, %addr" + cost 4; + + STORE.F(label:LABEL.I, value:(float)reg) + emit "lui at, ha16[$label]" + emit "swc1 %value, lo16[$label] (at)" + cost 8; + + STORE.D(addr:address, value:(double)reg) + emit "sdc1 %value, %addr" + cost 4; + + STORE.D(label:LABEL.I, value:(double)reg) + emit "lui at, ha16[$label]" + emit "sdc1 %value, lo16[$label] (at)" + cost 8; + + /* Loads */ + + out:(int)reg = LOAD.I(addr:address) + emit "lw %out, %addr" + cost 4; + + out:(int)reg = LOAD.I(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "lw %out, lo16[$label] (at)" + cost 8; + + /* We can't just load directly because %out.0 and %addr might share + * a register, resulting in %addr being corrupted before %out.1 is + * loaded. */ + out:(long)reg = LOAD.L(addr:address) + emit "lw at, 0+%addr" + emit "lw %out.1, 4+%addr" + emit "mov %out.0, at" + cost 12; + + out:(int)ushort0 = LOADH.I(addr:address) + emit "lhu %out, %addr" + cost 4; + + out:(int)reg = EXTENDH.I(LOADH.I(addr:address)) + emit "lh %out, %addr" + cost 4; + + out:(int)ushort0 = LOADH.I(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "lhu %out, lo16[$label] (at)" + cost 8; + + out:(int)reg = EXTENDH.I(LOADH.I(label:LABEL.I)) + emit "lui at, ha16[$label]" + emit "lh %out, lo16[$label] (at)" + cost 8; + + out:(int)ubyte0 = LOADB.I(addr:address) + emit "lbu %out, %addr" + cost 4; + + out:(int)reg = EXTENDB.I(LOADB.I(addr:address)) + emit "lb %out, %addr" + cost 4; + + out:(int)ubyte0 = LOADB.I(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "lbu %out, lo16[$label] (at)" + cost 8; + + out:(int)reg = EXTENDB.I(LOADB.I(label:LABEL.I)) + emit "lui at, ha16[$label]" + emit "lb %out, lo16[$label] (at)" + cost 8; + + out:(float)reg = LOAD.F(addr:address) + emit "lwc1 %out, %addr" + cost 4; + + out:(float)reg = LOAD.F(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "lwc1 %out, lo16[$label] (at)" + cost 8; + + out:(double)reg = LOAD.D(addr:address) + emit "ldc1 %out, %addr" + cost 4; + + out:(double)reg = LOAD.D(label:LABEL.I) + emit "lui at, ha16[$label]" + emit "ldc1 %out, lo16[$label] (at)" + cost 8; + + /* ubyte intrinsics */ + + out:(int)ubyteX = in:(int)ubyte0 + with %out == %in + emit "! ubyte0 -> ubyteX" + cost 1; + + out:(int)ubyte0 = in:(int)ubyteX + emit "andiu %out, %in, 0xff ! ubyteX -> ubyte0" + cost 4; + + out:(int)reg = in:(int)ubyte0 + with %out == %in + emit "! ubyte0 -> reg" + cost 4; + + out:(int)ubyteX = in:(int)reg + with %out == %in + emit "! reg -> ubyteX" + cost 1; + + /* ushort intrinsics */ + + out:(int)ushortX = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> ushortX" + cost 1; + + out:(int)ushort0 = in:(int)ushortX + emit "andiu %out, %in, 0xffff ! ushortX -> ushort0" + cost 4; + + out:(int)reg = in:(int)ushort0 + with %out == %in + emit "! ushort0 -> reg" + cost 4; + + out:(int)ushortX = in:(int)reg + with %out == %in + emit "! reg -> ushortX" + cost 1; + + + +/* Extensions and conversions */ + + out:(int)reg = EXTENDB.I(in:intregorzero) + emit "seb %out, %in" + cost 4; + + out:(int)reg = EXTENDH.I(in:intregorzero) + emit "seh %out, %in" + cost 4; + + out:(int)reg = FROMSI.I(in:(int)reg) + with %out == %in + emit "! FROMSI.I(int) -> int" + cost 1; + + out:(int)reg = FROMUI.I(in:(int)reg) + with %out == %in + emit "! FROMUI.I(int) -> int" + cost 1; + + out:(long)reg = FROMSI.L(in:(int)reg) + emit "mov %out.0, %in" + emit "sra %out.1, %in, 31" + cost 8; + + out:(long)reg = FROMUI.L(in:(int)reg) + emit "mr %out.0, %in" + emit "li %out.1, 0" + cost 8; + + out:(lret)reg = FROMIPAIR.L(in1:(int)reg, in2:(int)reg) + with preserved(%in1), preserved(%in2) + emit "mov %out.0, %in1" + emit "mov %out.1, %in2" + cost 8; + + out:(int)reg = FROML0.I(in:(long)reg) + emit "mov %out, %in.0" + cost 4; + + out:(int)reg = FROML1.I(in:(long)reg) + emit "mov %out, %in.1" + cost 4; + + intregorzero = zero:CONST.I + when specific_constant(%zero, 0) + emit "zero"; + + intregorzero = value:(int)reg + emit "%value"; + + intregorzero = value:(int)ubyte0 + emit "%value"; + + intregorzero = value:(int)ushort0 + emit "%value"; + + shortregorzero = zero:CONST.I + when specific_constant(%zero, 0) + emit "zero"; + + shortregorzero = value:(int)ushort0 + emit "%value"; + + shortregorzero = value:(int)ushortX + emit "%value"; + + shortregorzero = value:(int)ubyte0 + emit "%value"; + + byteregorzero = zero:CONST.I + when specific_constant(%zero, 0) + emit "zero"; + + byteregorzero = value:(int)ubyte0 + emit "%value"; + + byteregorzero = value:(int)ubyteX + emit "%value"; + + + +/* Locals and stack-relatives */ + + out:(int)reg = in:LOCAL.I + emit "addiu %out, fp, $in" + cost 4; + + address = in:LOCAL.I + emit "$in(fp)"; + + address = ADD.I(GETSP.I, offset:CONST.I) + when signed_constant(%offset, 16) + emit "$offset(sp)"; + + + +/* Memory addressing modes */ + + address = ADD.I(addr:(int)reg, offset:CONST.I) + when signed_constant(%offset, 16) + emit "$offset(%addr)"; + + address = addr:(int)reg + emit "0(%addr)"; + + + +/* Branches */ + + JUMP(addr:BLOCK.I) + emit "b $addr" + emit "nop" + cost 8; + + FARJUMP(addr:LABEL.I) + with corrupted(volatile) + emit "j $addr" + emit "nop" + cost 8; + + JUMP(dest:(int)reg) + emit "jr %dest" + emit "nop" + cost 8; + + CJUMPEQ(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "beq %left, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLT(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "bltz %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLE(left:(int)reg, PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "blez %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + #define CALLLABEL(insn) \ + insn (dest:LABEL.I) \ + with corrupted(volatile) \ + emit "jal $dest" \ + emit "nop" \ + cost 8; + + CALLLABEL(CALL) + out:(iret)reg = CALLLABEL(CALL.I) + out:(lret)reg = CALLLABEL(CALL.L) + + #define CALLINDIRECT(insn) \ + insn (dest:(int)reg) \ + with corrupted(volatile) \ + emit "jalr %dest" \ + emit "nop" \ + cost 8; + + CALLINDIRECT(CALL) + out:(iret)reg = CALLINDIRECT(CALL.I) + out:(lret)reg = CALLINDIRECT(CALL.L) + + JUMP(dest:LABEL.I) + emit "b $dest" + emit "nop" + cost 8; + + + +/* Conditional branches */ + + /* Normally COMPARE returns a condition code (in a flags register) which the CJUMP + * instructions can then operate on. But MIPS doesn't have a flags register, and + * requires you to know what condition you're testing for when you do the comparison. + * mcg doesn't like this much and we have to list every combination individually. + */ + + /* Signed integer comparisons against zero */ + + CJUMPEQ(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%zero, 0) + emit "beq %left, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLT(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%zero, 0) + emit "bltz %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLE(COMPARESI.I(left:(int)reg, zero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%zero, 0) + emit "blez %left, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + /* Signed integer comparisons against a constant */ + + CJUMPEQ(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "li at, $value" + emit "beq %left, at, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLT(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when signed_constant(%value, 16) + emit "slti at, %left, $value" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLE(COMPARESI.I(left:(int)reg, value:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when constant_within_inclusive_range(%value, -0x8000, 0x7ffe) + emit "slti at, %left, 1+$value" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + /* Signed integer comparisons against a register */ + + CJUMPEQ(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "beq %left, %right, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLT(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "slt at, %left, %right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + CJUMPLE(COMPARESI.I(left:(int)reg, right:(int)reg), PAIR(true:BLOCK.I, false:BLOCK.I)) + emit "slt at, %right, %left" + emit "beq at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + /* Unsigned integer comparisons against a constant */ + + CJUMPLT(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:CONST.I), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when signed_constant(%right, 16) + when specific_constant(%alwayszero, 0) + emit "sltiu at, %left, $right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLE(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:CONST.I), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when constant_within_inclusive_range(%right, -0x8000, 0x7ffe) + when specific_constant(%alwayszero, 0) + emit "sltiu at, %left, 1+$right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 20; + + /* Unsigned integer comparisons against registers */ + + CJUMPEQ(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%alwayszero, 0) + emit "beq %left, %right, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLT(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%alwayszero, 0) + emit "sltu at, %left, %right" + emit "bne at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + CJUMPLE(COMPARESI.I(COMPAREUI.I(left:(int)reg, right:(int)reg), alwayszero:CONST.I), PAIR(true:BLOCK.I, false:BLOCK.I)) + when specific_constant(%alwayszero, 0) + emit "sltu at, %right, %left" + emit "beq at, zero, $true" + emit "nop" + emit "b $false" + emit "nop" + cost 16; + + + + +/* Comparisons */ + + /* The COMPARE nodes return tristate integer values; -1, 0 or 1. */ + + out:(int)reg = COMPARESI.I(left:(int)reg, right:(int)reg) + with preserved(%left), preserved(%right) + emit "slt at, %left, %right" + emit "bne at, zero, 1f" + emit "li %out, -1" /* delay slot */ + emit "slt %out, %right, %left" + emit "1:" + cost 20; + + out:(int)reg = COMPAREUI.I(left:(int)reg, right:(int)reg) + with preserved(%left), preserved(%right) + emit "sltu at, %left, %right" + emit "bne at, zero, 1f" + emit "li %out, -1" /* delay slot */ + emit "sltu %out, %right, %left" + emit "1:" + cost 20; + + out:(iret)reg = COMPAREUL.I(left:(lret)reg, right:(lret1)reg) + emit "jal .compareul" + emit "nop" + cost 30; + + out:(int)reg = COMPAREF.I(left:(float)reg, right:(float)reg) + with preserved(%left), preserved(%right) + emit "c.lt.s 0, %left, %right" + emit "li %out, -1" + emit "bc1t 0, 1f" + emit "nop" + emit "c.lt.s 0, %right, %left" + emit "li %out, 1" + emit "movf %out, zero, 0" + emit "1:" + cost 28; + + out:(int)reg = COMPARED.I(left:(double)reg, right:(double)reg) + with preserved(%left), preserved(%right) + emit "c.lt.d 0, %left, %right" + emit "li %out, -1" + emit "bc1t 0, 1f" + emit "nop" + emit "c.lt.d 0, %right, %left" + emit "li %out, 1" + emit "movf %out, zero, 0" + emit "1:" + cost 28; + +/* Booleans */ + + /* If 0 then 1, else 0 */ + out:(int)reg = IFEQ.I(in:intregorzero) + emit "sltiu %out, %in, 1" + cost 4; + + /* If -1 then 1, else 0 */ + out:(int)reg = IFLT.I(in:intregorzero) + emit "srl %out, %in, 31" + cost 4; + + /* If 1 or 0 then 1, else 0 */ + out:(int)reg = IFLE.I(in:intregorzero) + emit "slti %out, %in, 1" + cost 4; + + + +/* Conversions */ + +#if 0 + out:(int)reg = CIU44(in:(int)reg) + with %out == %in + emit "! ciu44" + cost 4; + + out:(int)reg = CUI44(in:(int)reg) + with %out == %in + emit "! cui44" + cost 4; +#endif + +/* ALU operations */ + + /* reg + reg */ + #define ALUR(name, instr) \ + out:(int)reg = name(left:intregorzero, right:intregorzero) \ + emit instr " %out, %left, %right" \ + cost 4; \ + + /* reg + const */ + #define ALUC(name, instr, predicate) \ + out:(int)reg = name(left:intregorzero, right:CONST.I) \ + when predicate(%right, 16) \ + emit instr " %out, %left, $right" \ + cost 4; \ + + /* const + reg */ + #define ALUC_reversed(name, instr, predicate) \ + out:(int)reg = name(left:CONST.I, right:intregorzero) \ + when predicate(%left, 16) \ + emit instr " %out, %right, $left" \ + cost 4; \ + + /* reg + const AND const + reg */ + #define ALUCC(name, instr, predicate) \ + ALUC(name, instr, predicate) \ + ALUC_reversed(name, instr, predicate) + + ALUR(ADD.I, "addu") + ALUCC(ADD.I, "addiu", signed_constant) + + out:(int)reg = SUB.I(left:intregorzero, right:intregorzero) + emit "subu %out, %left, %right" + cost 4; + + out:(int)reg = SUB.I(left:intregorzero, right:CONST.I) + emit "addiu %out, %left, -[$right]" + cost 4; + + out:(int)reg = DIV.I(left:intregorzero, right:intregorzero) + emit "div %left, %right" + emit "mflo %out" + cost 8; + + out:(int)reg = DIVU.I(left:intregorzero, right:intregorzero) + emit "divu %left, %right" + emit "mflo %out" + cost 8; + + out:(int)reg = MOD.I(left:intregorzero, right:intregorzero) + emit "div %left, %right" + emit "mfhi %out" + cost 8; + + out:(int)reg = MODU.I(left:intregorzero, right:intregorzero) + emit "divu %left, %right" + emit "mfhi %out" + cost 8; + + ALUR(MUL.I, "mul") + + ALUR(ASL.I, "sllv") + ALUC(ASL.I, "sll", signed_constant) + ALUR(ASR.I, "srav") + ALUC(ASR.I, "sra", signed_constant) + + ALUR(LSL.I, "sllv") + ALUC(LSL.I, "sll", signed_constant) + ALUR(LSR.I, "srlv") + ALUC(LSR.I, "srl", signed_constant) + + out:(int)reg = NEG.I(left:intregorzero) + emit "subu %out, zero, %left" + cost 4; + + out:(int)reg = NOT.I(in:intregorzero) + emit "nor %out, %in, %in" + cost 4; + + ALUR(AND.I, "and") + ALUCC(AND.I, "andi", signed_constant) + + ALUR(OR.I, "or") + ALUCC(OR.I, "ori", unsigned_constant) + + ALUR(EOR.I, "xor") + ALUCC(EOR.I, "xori", unsigned_constant) + + out:(int)reg = value:LABEL.I + emit "lui %out, hi16[$value]" + emit "ori %out, %out, lo16[$value]" + cost 4; + + out:(int)reg = value:BLOCK.I + emit "lui %out, hi16[$value]" + emit "ori %out, %out, lo16[$value]" + cost 4; + + out:(int)reg = value:CONST.I + emit "li %out, $value" + cost 4; + + + +/* FPU operations */ + + /* Doubles */ + + out:(double)reg = ADDF.D(left:(double)reg, right:(double)reg) + emit "add.d %out, %left, %right" + cost 4; + + out:(double)reg = SUBF.D(left:(double)reg, right:(double)reg) + emit "sub.d %out, %left, %right" + cost 4; + + out:(double)reg = MULF.D(left:(double)reg, right:(double)reg) + emit "mul.d %out, %left, %right" + cost 4; + + out:(double)reg = DIVF.D(left:(double)reg, right:(double)reg) + emit "div.d %out, %left, %right" + cost 4; + + out:(double)reg = NEGF.D(left:(double)reg) + emit "neg.d %out, %left" + cost 4; + + out:(double)reg = FROMSI.D(in:(int)reg) + emit "mtc1 %in, %out" /* mtc1 has reversed parameters */ + emit "cvt.d.w %out, %out" + cost 4; + + out:(dret)reg = FROMUI.D(in:(iret)reg) + emit "jal .c_ui_d" + emit "nop" + cost 30; + + out:(int)reg = FROMSD.I(in:(double)reg) + emit "trunc.w.d f30, %in" + emit "mfc1 %out, f30" + cost 8; + + out:(lret)reg = FROMSD.L(in:(dret)reg) + emit "jal .c_sd_l" + emit "nop" + cost 30; + + out:(iret)reg = FROMUD.I(in:(dret)reg) + with corrupted(dret) + emit "jal .c_ud_i" + emit "nop" + cost 30; + + out:(double)reg = COPYL.D(in:(long)reg) + emit "mtc1 %in.0, %out" /* mtc1 has reversed parameters */ + emit "mthc1 %in.1, %out" /* mtc1 has reversed parameters */ + cost 8; + + out:(long)reg = COPYD.L(in:(double)reg) + emit "mfc1 %out.0, %in" + emit "mfhc1 %out.1, %in" + cost 8; + + /* Floats */ + + out:(float)reg = ADDF.F(left:(float)reg, right:(float)reg) + emit "add.d %out, %left, %right" + cost 4; + + out:(float)reg = SUBF.F(left:(float)reg, right:(float)reg) + emit "sub.d %out, %left, %right" + cost 4; + + out:(float)reg = MULF.F(left:(float)reg, right:(float)reg) + emit "mul.d %out, %left, %right" + cost 4; + + out:(float)reg = DIVF.F(left:(float)reg, right:(float)reg) + emit "div.d %out, %left, %right" + cost 4; + + out:(float)reg = NEGF.F(left:(float)reg) + emit "neg.s %out, %left" + cost 4; + + out:(float)reg = FROMSI.F(in:intregorzero) + emit "mtc1 %in, %out" /* mtc1 has reversed parameters */ + emit "cvt.s.w %out, %out" + cost 4; + + out:(int)reg = FROMSF.I(in:(float)reg) + emit "trunc.w.s f30, %in" + emit "mfc1 %out, f30" + cost 8; + + out:(lret)reg = FROMSF.L(in:(fret)reg) + emit "jal .c_sf_l" + emit "nop" + cost 30; + + out:(fret)reg = FROMUI.F(in:(iret)reg) + emit "jal .c_ui_f" + emit "nop" + cost 30; + + out:(iret)reg = FROMUF.I(in:(fret)reg) + with corrupted(fret) + emit "jal .c_uf_i" + emit "nop" + cost 30; + + out:(float)reg = COPYI.F(in:intregorzero) + emit "mtc1 %in, %out" /* mtc1 has reversed parameters */ + cost 4; + + out:(int)reg = COPYF.I(in:(float)reg) + emit "mfc1 %out, %in" + cost 4; + + out:(float)reg = value:CONST.F + when specific_constant(%value, 0) + emit "mtc1 zero, %out" /* mtc1 has reversed parameters */ + cost 4; + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/xr17032/top/table b/mach/xr17032/top/table new file mode 100644 index 000000000..655f288c7 --- /dev/null +++ b/mach/xr17032/top/table @@ -0,0 +1,51 @@ + +/* MIPS table for ACK target optimizer */ + +MAXOP 5; +LABEL_STARTER '.'; + +{ +int plus(const char *, const char *, char *); +} + +%%; + +X, Y, Z { TRUE }; +R { TRUE }; + +%%; + +/* Whitespace is significant here! */ + +addiu R, R, X : addiu R, R, Y { plus(X, Y, Z) } -> addiu R, R, Z ; + +addiu X, X, 0 -> ; + +b X : nop : labdef X -> labdef X ; + +%%; + +/* Does it fit a signed 16-bit integer? */ +static int fits16(long l) { + return l >= -32768 && l <= 32767; +} + +/* Tries sum = a + b with signed 16-bit integers. */ +int plus(const char *a, const char *b, char *sum) +{ + long la, lb, lsum; + char *end; + + la = strtol(a, &end, 10); + if (*a == '\0' || *end != '\0' || !fits16(la)) + return 0; + lb = strtol(b, &end, 10); + if (*b == '\0' || *end != '\0' || !fits16(lb)) + return 0; + + lsum = la + lb; + if (!fits16(lsum)) + return 0; + snprintf(sum, 7, "%ld", lsum); + return 1; +} diff --git a/plat/mintia/README b/plat/mintia/README new file mode 100644 index 000000000..ab294db86 --- /dev/null +++ b/plat/mintia/README @@ -0,0 +1,37 @@ +The linuxmips platform +====================== + +linuxmips is a little-endian MIPS32r2 BSP that produces Linux MIPS executables. + +This port only implements a very limited number of system calls; basically, +just enough to make the demo apps run. Adding more is easy, but there are some +subtleties that require more thought. The port should be considered only in +proof-of-concept stage right now. + +Important note: you *can't* link access ELF shared libraries from these +executables. In other words, you have to all your work from inside ACK. + +IEEE floating point is available, but requires an FPU. + +The executables are generated with aelfslod and are extremely simple; there's +one rwx ELF section which contains all the application's code and data. This +is not optimal, but it does work. Symbols are provided. + + +Bugs +==== + +isatty() is a stub and always returns 0. + + +Example command line +==================== + +ack -mlinuxmips -O -o linuxmips.exe examples/paranoia.c + +The file linuxmips.exe can then be run on a MIPS32r2 Linux machine (or on an +emulation thereof). + + +David Given +dg@cowlark.com diff --git a/plat/mintia/boot.s b/plat/mintia/boot.s new file mode 100644 index 000000000..7f5ff16c2 --- /dev/null +++ b/plat/mintia/boot.s @@ -0,0 +1,58 @@ +# +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +.define .entry +.entry: + ! This code is placed at the beginning of the ELF executable and is the + ! first thing that runs. + ! + ! On entry, the stack looks like this: + ! + ! sp+... NULL + ! sp+8+(4*argc) env (X quads) + ! sp+4+(4*argc) NULL + ! sp+4 argv (argc quads) + ! sp argc + ! + ! The ACK actually expects: + ! + ! sp+8 argc + ! sp+4 ptr to argv + ! sp ptr to env + + lw r4, 0(sp) ! r4 = argc + addiu r5, sp, 4 ! r5 = argv + sll r6, r4, 2 ! r6 = argc*4 + addu r6, r6, r5 ! r6 = null after last arg + addiu r6, r6, 4 ! r6 = env + + addiu sp, sp, -3 * 4 + sw r4, 0(sp) ! argc + sw r5, 4(sp) ! argv + sw r6, 8(sp) ! envp + + j __m_a_i_n + nop + +! Define symbols at the beginning of our various segments, so that we can find +! them. (Except .text, which has already been done.) + +.sect .data; begdata: +.sect .rom; begrom: +.sect .bss; begbss: + +! Some magic data. All EM systems need these. + +.define _errno +.comm _errno, 4 ! Posix errno storage + +.define .trppc, .ignmask +.comm .trppc, 4 ! ptr to user trap handler +.comm .ignmask, 4 ! user trap ignore mask diff --git a/plat/mintia/build-pkg.lua b/plat/mintia/build-pkg.lua new file mode 100644 index 000000000..fc5b86a0a --- /dev/null +++ b/plat/mintia/build-pkg.lua @@ -0,0 +1,25 @@ +include("plat/build.lua") + +ackfile { + name = "boot", + srcs = { "./boot.s" }, + vars = { plat = "mintia" } +} + +build_plat_libs { + name = "libs", + arch = "xr17032", + plat = "mintia", +} + +installable { + name = "pkg", + map = { + "+tools", + "+libs", + "./include+pkg", + ["$(PLATIND)/mintia/boot.o"] = "+boot", + ["$(PLATIND)/mintia/libsys.a"] = "./libsys+lib", + } +} + diff --git a/plat/mintia/build-tools.lua b/plat/mintia/build-tools.lua new file mode 100644 index 000000000..baa03c3b3 --- /dev/null +++ b/plat/mintia/build-tools.lua @@ -0,0 +1,29 @@ +include("plat/build.lua") + +build_as { + name = "as", + arch = "xr17032", + deps = { "mach/xr17032/as+astables" } +} + +build_mcg { + name = "mcg", + arch = "xr17032", +} + +build_top { + name = "top", + arch = "xr17032", +} + +return installable { + name = "tools", + map = { + ["$(PLATDEP)/mintia/as"] = "+as", + ["$(PLATDEP)/mintia/mcg"] = "+mcg", + ["$(PLATDEP)/mintia/top"] = "+top", + ["$(PLATIND)/descr/mintia"] = "./descr", + "util/amisc+axlofflod-pkg", + "util/opt+pkg", + } +} diff --git a/plat/mintia/descr b/plat/mintia/descr new file mode 100644 index 000000000..dac2e1284 --- /dev/null +++ b/plat/mintia/descr @@ -0,0 +1,83 @@ +# plat/linuxppc/descr + +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=8 +var da={d} +var x=8 +var xa={x} +var ARCH=xr17032 +var PLATFORM=mintia +var PLATFORMDIR={EM}/share/ack/{PLATFORM} +var CPP_F=-D__mintia +var ALIGN=-a0:8 -a1:8 -a2:8 -a3:8 -b0:0x00400058 +var MACHOPT_F=-m2 + +var C_INCLUDES=-I{EM}/share/ack/mintia/include -I{EM}/share/ack/include/ansi + +name be + from .m.g + to .s + program {EM}/lib/ack/{PLATFORM}/mcg + mapflag -gdb GF=-gdb + args {GF?} < + stdout + need .e +end +name asopt + from .s + to .so + program {EM}/lib/ack/{PLATFORM}/top + args + optimizer + stdin + stdout +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 -fp FLOATS={EM}/{LIB}fp + args {ALIGN} {SEPID?} \ + ({RTS}:.b=-u _i_main) \ + (.e:{HEAD}={PLATFORMDIR}/boot.o) \ + ({RTS}:.ocm.bas.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}/libb.a) \ + (.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \ + (.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \ + (.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \ + (.ocm.bas.mod.b.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 .exe + program {EM}/bin/axlofflod + args -m8 -l -f0x70001000 < > + outfile mintia.exe +end diff --git a/plat/mintia/include/ack/fcntl.h b/plat/mintia/include/ack/fcntl.h new file mode 100644 index 000000000..361fad97a --- /dev/null +++ b/plat/mintia/include/ack/fcntl.h @@ -0,0 +1,19 @@ +#ifndef _ACK_FCNTL_H +#define _ACK_FCNTL_H + +/* Linux O_ constants. */ + +enum +{ + O_ACCMODE = 0x3, + + O_RDONLY = 0, + O_WRONLY = 1, + O_RDWR = 2, + + O_CREAT = 00000100, + O_TRUNC = 00001000, + O_APPEND = 00002000 +}; + +#endif diff --git a/plat/mintia/include/ack/plat.h b/plat/mintia/include/ack/plat.h new file mode 100644 index 000000000..f0ad12797 --- /dev/null +++ b/plat/mintia/include/ack/plat.h @@ -0,0 +1,12 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#ifndef _ACK_PLAT_H +#define _ACK_PLAT_H + +#define ACKCONF_WANT_STANDARD_O 0 +#define ACKCONF_WANT_STANDARD_SIGNALS 0 + +#endif diff --git a/plat/mintia/include/ack/signal.h b/plat/mintia/include/ack/signal.h new file mode 100644 index 000000000..55c0f3a04 --- /dev/null +++ b/plat/mintia/include/ack/signal.h @@ -0,0 +1,74 @@ +#ifndef _ACK_SIGNAL_H +#define _ACK_SIGNAL_H + +/* Signal constants. */ + +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 SIGHUP 1 /* Hangup (POSIX). */ +#define SIGINT 2 /* Interrupt (ANSI). */ +#define SIGQUIT 3 /* Quit (POSIX). */ +#define SIGILL 4 /* Illegal instruction (ANSI). */ +#define SIGTRAP 5 /* Trace trap (POSIX). */ +#define SIGABRT 6 /* Abort (ANSI). */ +#define SIGIOT 6 /* IOT trap (4.2 BSD). */ +#define SIGBUS 7 /* BUS error (4.2 BSD). */ +#define SIGFPE 8 /* Floating-point exception (ANSI). */ +#define SIGKILL 9 /* Kill, unblockable (POSIX). */ +#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ +#define SIGSEGV 11 /* Segmentation violation (ANSI). */ +#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ +#define SIGPIPE 13 /* Broken pipe (POSIX). */ +#define SIGALRM 14 /* Alarm clock (POSIX). */ +#define SIGTERM 15 /* Termination (ANSI). */ +#define SIGSTKFLT 16 /* Stack fault. */ +#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ +#define SIGCHLD 17 /* Child status has changed (POSIX). */ +#define SIGCONT 18 /* Continue (POSIX). */ +#define SIGSTOP 19 /* Stop, unblockable (POSIX). */ +#define SIGTSTP 20 /* Keyboard stop (POSIX). */ +#define SIGTTIN 21 /* Background read from tty (POSIX). */ +#define SIGTTOU 22 /* Background write to tty (POSIX). */ +#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ +#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ +#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ +#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ +#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ +#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ +#define SIGPOLL SIGIO /* Pollable event occurred (System V). */ +#define SIGIO 29 /* I/O now possible (4.2 BSD). */ +#define SIGPWR 30 /* Power failure restart (System V). */ +#define SIGSYS 31 /* Bad system call. */ +#define SIGUNUSED 31 + +#define _NSIG 32 /* Biggest signal number + 1 + (not including real-time signals). */ + +/* sigprocmask */ +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 +typedef unsigned long sigset_t; + +/* sa_flags */ +#define SA_NODEFER 0x40000000UL +#define SA_RESETHAND 0x80000000UL + +struct __siginfo; +struct sigaction { + union { + void (*__sa_handler)(int); + void (*__sa_sigaction)(int, struct __siginfo *, void *); + } __sigaction_u; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; +#define sa_handler __sigaction_u.__sa_handler +#define sa_sigaction __sigaction_u.__sa_sigaction + +#endif diff --git a/plat/mintia/include/build.lua b/plat/mintia/include/build.lua new file mode 100644 index 000000000..a00dfdee6 --- /dev/null +++ b/plat/mintia/include/build.lua @@ -0,0 +1,28 @@ +include("plat/build.lua") + +headermap = {} +packagemap = {} + +local function addheader(h) + headermap[h] = "./"..h + packagemap["$(PLATIND)/mintia/include/"..h] = "./"..h +end + +addheader("ack/fcntl.h") +addheader("ack/plat.h") +addheader("ack/signal.h") +addheader("sys/ioctl.h") +addheader("sys/types.h") +addheader("sys/wait.h") + +acklibrary { + name = "headers", + hdrs = headermap +} + +installable { + name = "pkg", + map = packagemap +} + + diff --git a/plat/mintia/include/sys/ioctl.h b/plat/mintia/include/sys/ioctl.h new file mode 100644 index 000000000..e35308d8a --- /dev/null +++ b/plat/mintia/include/sys/ioctl.h @@ -0,0 +1,76 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H + +/* These are copied from the ioctl_list(2) man page. */ + +/* */ + +#define FIOSETOWN 0x00008901 +#define SIOCSPGRP 0x00008902 +#define FIOGETOWN 0x00008903 +#define SIOCGPGRP 0x00008904 +#define SIOCATMARK 0x00008905 +#define SIOCGSTAMP 0x00008906 + +/* */ + +#define TCGETS 0x00005401 +#define TCSETS 0x00005402 +#define TCSETSW 0x00005403 +#define TCSETSF 0x00005404 +#define TCGETA 0x00005405 +#define TCSETA 0x00005406 +#define TCSETAW 0x00005407 +#define TCSETAF 0x00005408 +#define TCSBRK 0x00005409 +#define TCXONC 0x0000540A +#define TCFLSH 0x0000540B +#define TIOCEXCL 0x0000540C +#define TIOCNXCL 0x0000540D +#define TIOCSCTTY 0x0000540E +#define TIOCGPGRP 0x0000540F +#define TIOCSPGRP 0x00005410 +#define TIOCOUTQ 0x00005411 +#define TIOCSTI 0x00005412 +#define TIOCGWINSZ 0x00005413 +#define TIOCSWINSZ 0x00005414 +#define TIOCMGET 0x00005415 +#define TIOCMBIS 0x00005416 +#define TIOCMBIC 0x00005417 +#define TIOCMSET 0x00005418 +#define TIOCGSOFTCAR 0x00005419 +#define TIOCSSOFTCAR 0x0000541A +#define FIONREAD 0x0000541B +#define TIOCINQ 0x0000541B +#define TIOCLINUX 0x0000541C +#define TIOCCONS 0x0000541D +#define TIOCGSERIAL 0x0000541E +#define TIOCSSERIAL 0x0000541F +#define TIOCPKT 0x00005420 +#define FIONBIO 0x00005421 +#define TIOCNOTTY 0x00005422 +#define TIOCSETD 0x00005423 +#define TIOCGETD 0x00005424 +#define TCSBRKP 0x00005425 +#define TIOCTTYGSTRUCT 0x00005426 +#define FIONCLEX 0x00005450 +#define FIOCLEX 0x00005451 +#define FIOASYNC 0x00005452 +#define TIOCSERCONFIG 0x00005453 +#define TIOCSERGWILD 0x00005454 +#define TIOCSERSWILD 0x00005455 +#define TIOCGLCKTRMIOS 0x00005456 +#define TIOCSLCKTRMIOS 0x00005457 +#define TIOCSERGSTRUCT 0x00005458 +#define TIOCSERGETLSR 0x00005459 +#define TIOCSERGETMULTI 0x0000545A +#define TIOCSERSETMULTI 0x0000545B + + + +#endif diff --git a/plat/mintia/include/sys/types.h b/plat/mintia/include/sys/types.h new file mode 100644 index 000000000..b706026ef --- /dev/null +++ b/plat/mintia/include/sys/types.h @@ -0,0 +1,9 @@ +#ifndef _SYS_TYPES_H +#define _SYS_TYPES_H + +typedef int pid_t; +typedef int mode_t; +typedef long suseconds_t; +typedef long time_t; + +#endif diff --git a/plat/mintia/include/sys/wait.h b/plat/mintia/include/sys/wait.h new file mode 100644 index 000000000..1d30dbcdf --- /dev/null +++ b/plat/mintia/include/sys/wait.h @@ -0,0 +1,19 @@ +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include + +extern pid_t wait(int *__wstatus); +extern pid_t waitpid(pid_t __pid, int *__wstatus, int __options); + +#define WNOHANG (1 << 0) +#define WUNTRACED (1 << 1) +#define WSTOPPED WUNTRACED +#define WEXITED (1 << 2) +#define WCONTINUED (1 << 3) +#define WNOWAIT (1 << 24) +#define __WNOTHREAD (1 << 29) +#define __WALL (1 << 30) +#define __WCLONE (1 << 31) + +#endif diff --git a/plat/mintia/libsys/_syscall.s b/plat/mintia/libsys/_syscall.s new file mode 100644 index 000000000..8d5ecde90 --- /dev/null +++ b/plat/mintia/libsys/_syscall.s @@ -0,0 +1,34 @@ +# +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +#define EINVAL 22 + +! Perform a Linux system call. + +.define __syscall +__syscall: + lw r2, 0(sp) ! syscall number + addiu r2, r2, 4000 ! MIPS uses non-standard numbers + lw r4, 4(sp) + lw r5, 8(sp) + lw r6, 12(sp) + syscall 0 + + beq r7, zero, exit ! branch on success + nop + + /* The result (in r2) is the errno. */ + lui at, ha16[_errno] + sw r2, lo16[_errno] (at) + li r2, -1 +exit: + jr ra + nop + diff --git a/plat/mintia/libsys/build.lua b/plat/mintia/libsys/build.lua new file mode 100644 index 000000000..462f687fc --- /dev/null +++ b/plat/mintia/libsys/build.lua @@ -0,0 +1,36 @@ +acklibrary { + name = "lib", + srcs = { + "./_syscall.s", + "plat/linux/libsys/_exit.c", + "plat/linux/libsys/_hol0.s", + "plat/linux/libsys/close.c", + "plat/linux/libsys/creat.c", + "plat/linux/libsys/execve.c", + "plat/linux/libsys/fork.c", + "plat/linux/libsys/getpid.c", + "plat/linux/libsys/gettimeofday.c", + "plat/linux/libsys/ioctl.c", + "plat/linux/libsys/isatty.c", + "plat/linux/libsys/kill.c", + "plat/linux/libsys/lseek.c", + "plat/linux/libsys/open.c", + "plat/linux/libsys/read.c", + "plat/linux/libsys/sbrk.c", + "plat/linux/libsys/signal.c", + "plat/linux/libsys/sigprocmask.c", + "plat/linux/libsys/unlink.c", + "plat/linux/libsys/wait.c", + "plat/linux/libsys/waitpid.c", + "plat/linux/libsys/write.c", + }, + deps = { + "plat/linux/libsys+headers", + "lang/cem/libcc.ansi/headers+headers", + "plat/linuxmips/include+pkg", + }, + vars = { + plat = "linuxmips" + } +} + diff --git a/util/amisc/axlofflod.1 b/util/amisc/axlofflod.1 new file mode 100644 index 000000000..9c6134b33 --- /dev/null +++ b/util/amisc/axlofflod.1 @@ -0,0 +1,63 @@ +.TH AELFLOD 1 2017-01-18 +.SH NAME +aelflod \- ACK ELF loader +.SH SYNOPSIS +.B aelflod +[\-a\fInumber\fP] [\-b] [\-h] [\-l] [\-m\fInumber\fP] [\-v] +inputfile outputfile +.SH DESCRIPTION +.I aelflod +converts an absolute ack.out file into a simple binary memory +dump wrapped up in an ELF executable. +It is suitable for producing executables for operating systems +such as Linux. +.PP +.I aelflod +accepts the following flags: +.TP +.BI \-a number +Set the ABI in the ELF header to \fInumber\fP. +The default value is \fI3\fP for Linux. +.TP +.B \-b +Write a big-endian ELF file. +.TP +.B \-h +Print a help message and exit. +.TP +.B \-l +Write a little-endian ELF file. +This is the default. +.TP +.BI \-m number +Set the machine type in the ELF header to \fInumber\fP. +The default value is \fI3\fP for Intel 386 (i386). +Other values are \fI4\fP for Motorola 68000 (m68k) +and \fI20\fP for PowerPC. +.TP +.BI \-f number +Set the processor flags in the ELF header to \fInumber\fP. +The default value is 0. +.TP +.B \-v +Be verbose. +.PP +The input file must contain exactly four segments: TEXT, ROM, +DATA and BSS, in that order, all occupying contiguous memory. +The file must have all references resolved and be linked to a +fixed address. +The fixed address must be at least 0x54 bytes greater than a +page boundary, in order to make room for the ELF header itself. +.PP +.I aelflod +will write out an ELF header followed by each segment, in order, +ensuring that enough padding is inserted between each segment +to keep the offsets correct. +The created executable will contain just one ELF segment mapped rwx. +.PP +If the input file has symbols, then +.I aelflod +will convert the symbol table to ELF. +The output file has ELF section headers if and only if it has symbols. +.SH "SEE ALSO" +ack.out(5) diff --git a/util/amisc/axlofflod.c b/util/amisc/axlofflod.c new file mode 100644 index 000000000..083fdf2f5 --- /dev/null +++ b/util/amisc/axlofflod.c @@ -0,0 +1,890 @@ +/* + * Simple tool to produce an utterly basic ELF executable + * from an absolute ack.out file. Suitable for operating + * systems like Linux. + * + * This tool produces an executable with a program header + * only and no section header. + * + * Mostly pinched from the ARM cv (and then rewritten in + * ANSI C). Which, according to the comment, was pinched + * from m68k2; therefore I am merely continuing a time- + * honoured tradition. + * + * (I was 10 when the original for this was checked into + * CVS...) + * + * dtrg, 2006-10-17 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "out.h" + +#define ASSERT(x) switch (2) { case 0: case (x): ; } + +/* Global settings. */ + +int bigendian = 0; +int elfabi = 3; /* abi = Linux */ +int elfmachine = 3; /* machine = EM_386 */ +uint32_t elfflags = 0; /* elf processor flags */ + +/* Header and section table of an ack object file. */ + +struct outhead outhead; +struct outsect outsect[S_MAX]; +struct outname* outname = NULL; +char* stringarea; +uint32_t ack_off_char; +int nstab = 0; /* S_STB symbol count */ +int nsym = 0; /* other symbol count */ +int nlocal = 0; /* local symbols */ + +char* outputfile = NULL; /* Name of output file, or NULL */ +char* program; /* Name of current program: argv[0] */ + +FILE* input; /* Input stream */ +FILE* output; /* Output stream */ + +#define readf(a, b, c) fread((a), (b), (int)(c), input) +#define writef(a, b, c) fwrite((a), (b), (int)(c), output) + +/* Contents of an ELF object file. */ + +#define ELF_HEADER_SIZE 0x34 +#define PROGRAM_HEADER_SIZE 0x20 +#define PROGRAM_HEADER_COUNT 1 +#define SECTION_HEADER_SIZE 0x28 +#define STAB_SYMBOL_SIZE 12 +#define ELF_SYMBOL_SIZE 16 + +uint32_t code_offset; /* ELF segment */ +uint32_t stab_offset; /* Debugger symbol table */ +uint32_t symtab_offset; /* ELF symbol table */ +uint32_t strtab_offset; /* String table */ +uint32_t shstrtab_offset; /* Section header string table */ +uint32_t sh_offset; /* ELF section headers */ + +int sh_count = 0; /* Number of ELF sections */ +int shstrtab_nr = 0; /* Section number of .shstrtab */ +int shstrtab_size; + +const char elf_le_ident_string[] = { + 0x7F, 'E', 'L', 'F' +}; + +bool verbose = false; + +/* Segment numbers understood by aelflod. */ + +enum { + TEXT = 0, + ROM, + DATA, + BSS, + NUM_SEGMENTS +}; + +/* + * ELF section numbers count up in the order that we write the ELF + * section headers. If we have no debugger symbols, we will skip + * .stab and .stabstr, then subtract 2 from all later numbers. + */ +enum { + N_UNDEF = 0, + N_TEXT, + N_RODATA, + N_DATA, + N_BSS, + N_STAB, + N_STABSTR, + N_SYMTAB, + N_STRTAB, + N_SHSTRTAB, + NUM_ELF_SECTIONS, +}; +const char shstrtab[] = + "\0.text\0.rodata\0.data\0.bss\0.stab\0.stabstr\0" + ".symtab\0.strtab\0.shstrtab"; + /* Compiler appends one more "\0". */ +const int sh_name[] = { + /* Index of each name in shstrtab: */ + 0, 1, 7, 15, 21, 26, 32, + 41, 49, 57, +}; + +/* Produce an error message and exit. */ + +void fatal(const char* s, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ",program) ; + + va_start(ap, s); + vfprintf(stderr, s, ap); + va_end(ap); + + fprintf(stderr, "\n"); + + if (outputfile) + unlink(outputfile); + exit(1); +} + +/* Calculate the result of a aligned to b (rounding up if necessary). + * b must be a power of two. */ + +long align(long a, long b) +{ + a += b - 1; + return a & ~(b-1); +} + +int follows(struct outsect* pa, struct outsect* pb) +{ + /* return 1 if pa follows pb */ + + return (pa->os_base >= align(pb->os_base+pb->os_size, pa->os_lign)); +} + +/* Convert a symbol's name index from ack.out to ELF. */ + +uint32_t cvname(struct outname* n) +{ + if (n->on_foff) { + /* ack.out: offset from beginning of file + * ELF: index in string table + * the + 1 because we prepend a '\0' */ + return n->on_foff - ack_off_char + 1; + } else + return 0; /* no name */ +} + +/* Convert a symbol's type and binding from ack.out to ELF. */ + +int cvinfo(struct outname* n) +{ + int bind, type; + + switch (n->on_type & S_ETC) { + case S_SCT: + type = 3; /* STT_SECTION */ + break; + case S_FIL: + case S_MOD: + type = 4; /* STT_FILE */ + break; + default: + switch (n->on_type & S_TYP) { + case S_MIN + TEXT: + type = 2; /* STT_FUNC */ + break; + case S_MIN + ROM: + case S_MIN + DATA: + case S_MIN + BSS: + case S_MIN + NUM_SEGMENTS: + type = 1; /* STT_OBJECT */ + break; + default: + type = 0; /* STT_NOTYPE */ + break; + } + break; + } + + if (n->on_type & S_EXT) + bind = 1; /* STB_GLOBAL */ + else + bind = 0; /* STB_LOCAL */ + + return (bind << 4) | type; +} + +/* Convert a symbol's section index from ack.out to ELF. */ + +int cvsect(struct outname* n) +{ + switch (n->on_type & S_TYP) { + case S_ABS: + return 0xfff1; /* SHN_ABS */ + case S_MIN + TEXT: + return N_TEXT; + case S_MIN + ROM: + return N_RODATA; + case S_MIN + DATA: + return N_DATA; + case S_MIN + BSS: + case S_MIN + NUM_SEGMENTS: + return N_BSS; + default: + return N_UNDEF; + } +} + +/* Writes a byte. */ + +void emit8(unsigned char value) +{ + writef(&value, 1, 1); +} + +/* Writes out 16 and 32 bit words in the appropriate endianness. */ + +void emit16(unsigned short value) +{ + unsigned char buffer[2]; + + if (bigendian) + { + buffer[0] = (value >> 8) & 0xFF; + buffer[1] = (value >> 0) & 0xFF; + } + else + { + buffer[1] = (value >> 8) & 0xFF; + buffer[0] = (value >> 0) & 0xFF; + } + + writef(buffer, 1, sizeof(buffer)); +} + +void emit32(unsigned long value) +{ + unsigned char buffer[4]; + + if (bigendian) + { + buffer[0] = (value >> 24) & 0xFF; + buffer[1] = (value >> 16) & 0xFF; + buffer[2] = (value >> 8) & 0xFF; + buffer[3] = (value >> 0) & 0xFF; + } + else + { + buffer[3] = (value >> 24) & 0xFF; + buffer[2] = (value >> 16) & 0xFF; + buffer[1] = (value >> 8) & 0xFF; + buffer[0] = (value >> 0) & 0xFF; + } + + writef(buffer, 1, sizeof(buffer)); +} + +/* Copies the contents of a section from the input stream + * to the output stream. */ + +void emits(struct outsect* section) +{ + char buffer[BUFSIZ]; + long n = section->os_flen; + while (n > 0) + { + int blocksize = (n > BUFSIZ) ? BUFSIZ : n; + readf(buffer, 1, blocksize); + writef(buffer, 1, blocksize); + n -= blocksize; + } + + /* Zero fill any remaining space. */ + + if (section->os_flen != section->os_size) + { + long n = section->os_size - section->os_flen; + memset(buffer, 0, BUFSIZ); + + while (n > 0) + { + int blocksize = (n > BUFSIZ) ? BUFSIZ : n; + writef(buffer, 1, blocksize); + n -= blocksize; + } + } +} + +/* Writes out an ELF program header. */ + +void emitphdr(unsigned long address, unsigned long filesize, + unsigned int memsize, unsigned int alignment, int flags) +{ + static unsigned long fileoffset = 0; + + emit32(1); /* type = PT_LOAD */ + emit32(fileoffset); /* file offset */ + emit32(address); /* virtual address */ + emit32(0); /* physical address */ + emit32(filesize); /* file size */ + emit32(memsize); /* memory size */ + emit32(flags); /* executable, readable, writable */ + emit32(alignment); /* alignment */ + + fileoffset += filesize; +} + +/* The next few functions write parts of the symbol table. */ + +void emit_stab(void) +{ + struct outname* n; + int i; + + for (i = 0; i < outhead.oh_nname; i++) { + n = &outname[i]; + if (n->on_type & S_STB) { + emit32(cvname(n)); /* name index */ + emit8(n->on_type >> 8); /* type */ + emit8(cvsect(n)); /* section */ + emit16(n->on_desc); /* desc */ + emit32(n->on_valu); /* value */ + } + } +} + +void emit_symtab(void) +{ + struct outname* n; + int i, pass; + bool global; + + /* ELF .symtab must have local symbols before other symbols. + * We emit locals in pass 0, globals in pass 1. */ + for (pass = 0; pass < 2; pass++) { + for (i = 0; i < outhead.oh_nname; i++) { + n = &outname[i]; + + /* Don't emit .stab symbol in .symtab. */ + if (n->on_type & S_STB) + continue; + + global = (n->on_type & S_EXT); + if ((pass == 0 && !global) || + (pass == 1 && global)) { + emit32(cvname(n)); /* name index */ + emit32(n->on_valu); /* value */ + emit32(0); /* size = unknown */ + emit8(cvinfo(n)); /* info */ + emit8(0); /* other */ + emit16(cvsect(n)); /* section */ + } + } + } +} + +void emit_strtab(void) +{ + /* We prepend a '\0' because ELF uses offset 0 for symbols + * without a name. */ + emit8('\0'); + writef(stringarea, outhead.oh_nchar, 1); +} + +void emit_shstrtab(void) +{ + if (nstab) { + writef(shstrtab, sizeof(shstrtab), 1); + } else { + /* Skip .stab and .stabstr */ + int i = sh_name[N_SYMTAB]; + writef(shstrtab, sh_name[N_STAB], 1); + writef(shstrtab + i, sizeof(shstrtab) - i, 1); + } +} + +/* Writes out an ELF section header. */ + +void emit_sh(int i) +{ + uint32_t name, type, flags, addr, offset, size, link, info, + addralign, entsize; + + /* If no debugger symbols, skip .stab and .stabstr */ + if (nstab == 0 && (i == N_STAB || i == N_STABSTR)) + return; + + name = sh_name[i]; + if (nstab == 0 && i >= N_STAB) + name -= (sh_name[N_SYMTAB] - sh_name[N_STAB]); + + switch (i) { + case N_TEXT: + case N_RODATA: + case N_DATA: + case N_STAB: + type = 1; /* SHT_PROGBITS */ + break; + case N_BSS: + type = 8; /* SHT_NOBITS */ + break; + case N_SYMTAB: + type = 2; /* SHT_SYMTAB */ + break; + case N_STABSTR: + case N_STRTAB: + case N_SHSTRTAB: + type = 3; /* SHT_STRTAB */ + break; + default: + type = 0; /* SHT_NULL */ + break; + } + + switch (i) { + case N_TEXT: + flags = 4|2; /* SHF_EXECINSTR|SHF_ALLOC */ + addr = outsect[TEXT].os_base; + offset = code_offset; + size = outsect[TEXT].os_size; + addralign = outsect[TEXT].os_lign; + break; + case N_RODATA: + flags = 2; /* SHF_ALLOC */ + addr = outsect[ROM].os_base; + offset = code_offset + outsect[TEXT].os_size; + size = outsect[ROM].os_size; + addralign = outsect[ROM].os_lign; + break; + case N_DATA: + flags = 2|1; /* SHF_ALLOC|SHF_WRITE */ + addr = outsect[DATA].os_base; + offset = code_offset + outsect[TEXT].os_size + + outsect[ROM].os_size; + size = outsect[DATA].os_size; + addralign = outsect[DATA].os_lign; + break; + case N_BSS: + flags = 2|1; /* SHF_ALLOC|SHF_WRITE */ + addr = outsect[BSS].os_base; + offset = code_offset + outsect[TEXT].os_size + + outsect[ROM].os_size + outsect[DATA].os_size; + size = outsect[BSS].os_size; + addralign = outsect[BSS].os_lign; + break; + default: + flags = addr = offset = size = addralign = 0; + break; + } + + entsize = 0; + switch (i) { + case N_STAB: + offset = stab_offset; + size = STAB_SYMBOL_SIZE * nstab; + entsize = STAB_SYMBOL_SIZE; + break; + case N_SYMTAB: + offset = symtab_offset; + size = ELF_SYMBOL_SIZE * nsym; + entsize = ELF_SYMBOL_SIZE; + break; + case N_STABSTR: + case N_STRTAB: + /* .stabstr, .strtab share the string area */ + offset = strtab_offset; + /* the + 1 because we prepend a '\0' */ + size = 1 + outhead.oh_nchar; + break; + case N_SHSTRTAB: + offset = shstrtab_offset; + size = shstrtab_size; + break; + } + + /* Link .stab to .stabstr and .symtab to .strtab */ + switch (i) { + case N_STAB: + link = N_STABSTR; + break; + case N_SYMTAB: + link = N_STRTAB; + if (nstab == 0) + link -= 2; + break; + default: + link = 0; + break; + } + + switch (i) { + case N_SYMTAB: + info = nlocal; + break; + default: + info = 0; + break; + } + + emit32(name); + emit32(type); + emit32(flags); + emit32(addr); + emit32(offset); + emit32(size); + emit32(link); + emit32(info); + emit32(addralign); + emit32(entsize); +} + +/* Macros from modules/src/object/obj.h */ +#define Xchar(ch) ((ch) & 0377) +#define uget2(c) (Xchar((c)[0]) | ((unsigned) Xchar((c)[1]) << 8)) +#define get4(c) (uget2(c) | ((long) uget2((c)+2) << 16)) + +/* Read the ack.out file header. */ + +int rhead(FILE* f, struct outhead* head) +{ + char buf[SZ_HEAD], *c; + + if (fread(buf, sizeof(buf), 1, f) != 1) + return 0; + + c = buf; + head->oh_magic = uget2(c); c += 2; + head->oh_stamp = uget2(c); c += 2; + head->oh_flags = uget2(c); c += 2; + head->oh_nsect = uget2(c); c += 2; + head->oh_nrelo = uget2(c); c += 2; + head->oh_nname = uget2(c); c += 2; + head->oh_nemit = get4(c); c += 4; + head->oh_nchar = get4(c); + return 1; +} + +/* Read an ack.out section header. */ + +int rsect(FILE* f, struct outsect* sect) +{ + char buf[SZ_SECT], *c; + + if (fread(buf, sizeof(buf), 1, f) != 1) + return 0; + + c = buf; + sect->os_base = get4(c); c += 4; + sect->os_size = get4(c); c += 4; + sect->os_foff = get4(c); c += 4; + sect->os_flen = get4(c); c += 4; + sect->os_lign = get4(c); + return 1 ; +} + +/* + * Read the ack.out symbol table and string area. Count symbols. + * Seek back to the current file position. + */ +int rnames(FILE* f) +{ + long told; + int i; + + /* If no symbols, then do nothing successfully. */ + if (outhead.oh_nname == 0) + return 1; + + /* Seek to the symbol table. */ + told = ftell(f); + if (told == -1) + return 0; + ack_off_char = OFF_CHAR(outhead); /* for cvname() */ + if (fseek(f, OFF_NAME(outhead), SEEK_SET)) + return 0; + + /* Using calloc(a, b) to check if a * b would overflow. */ + outname = calloc(outhead.oh_nname, sizeof(outname[0])); + if (outname == NULL) + fatal("out of memory."); + for (i = 0; i < outhead.oh_nname; i++) { + char buf[SZ_NAME], *c; + if (fread(buf, SZ_NAME, 1, f) != 1) + return 0; + c = buf; + outname[i].on_foff = get4(c); c += 4; + outname[i].on_type = uget2(c); c += 2; + outname[i].on_desc = uget2(c); c += 2; + outname[i].on_valu = get4(c); + if (outname[i].on_type & S_STB) { + nstab++; + } else { + nsym++; + if (!(outname[i].on_type & S_EXT)) + nlocal++; + } + } + + stringarea = malloc(outhead.oh_nchar); + if (stringarea == NULL) + fatal("out of memory."); + if (fread(stringarea, outhead.oh_nchar, 1, f) != 1) + return 0; + + if (fseek(f, told, SEEK_SET)) + return 0; + return 1; +} + +int main(int argc, char* argv[]) +{ + /* General housecleaning and setup. */ + + input = stdin; + output = stdout; + program = argv[0]; + + /* Read in and process any flags. */ + + while ((argc > 1) && (argv[1][0] == '-')) + { + switch (argv[1][1]) + { + case 'a': + elfabi = strtoul(&argv[1][2], NULL, 0); + break; + + case 'b': + bigendian = 1; + break; + + case 'h': + fprintf(stderr, "%s: Syntax: aelflod [-a] [-b] [-h] [-l]\n\t[-m] [-v] \n", + program); + exit(0); + + case 'l': + bigendian = 0; + break; + + case 'm': + elfmachine = strtoul(&argv[1][2], NULL, 0); + break; + + case 'f': + elfflags = strtoul(&argv[1][2], NULL, 0); + break; + + case 'v': + verbose = true; + break; + + default: + syntaxerror: + fatal("syntax error --- try -h for help"); + } + + argv++; + argc--; + } + + /* Process the rest of the arguments. */ + + switch (argc) + { + case 1: /* No parameters --- read from stdin, write to stdout. */ + break; + + case 3: /* Both input and output files specified. */ + output = fopen(argv[2], "wb"); + if (!output) + fatal("unable to open output file."); + outputfile = argv[2]; + /* fall through */ + + case 2: /* Input file specified. */ + input = fopen(argv[1], "rb"); + if (!input) + fatal("unable to open input file."); + break; + + default: + goto syntaxerror; + } + + /* Read and check the ack.out file header. */ + + if (!rhead(input,&outhead)) + fatal("failed to read file header."); + if (BADMAGIC(outhead)) + fatal("this isn't an ack object file."); + if (outhead.oh_nrelo > 0) + fprintf(stderr, "Warning: relocation information present."); + if (!((outhead.oh_nsect == NUM_SEGMENTS) || + (outhead.oh_nsect == (NUM_SEGMENTS+1)))) + fatal("the input file must have %d sections, not %ld.", + NUM_SEGMENTS, outhead.oh_nsect); + + /* Read in the section headers. */ + + { + int i; + for (i=0; i