From b71145f79d6c00f5a852e305a8c66ba34c33a1b7 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 14 Jun 2018 03:07:36 -0700 Subject: [PATCH 1/9] Implement a non-functional skeleton of the PowerPC emulator (with, hopefully, most of the instruction decode done). --- plat/linuxppc/emu/build.lua | 28 +++++ plat/linuxppc/emu/emu.c | 168 ++++++++++++++++++++++++++++ plat/linuxppc/emu/emu.h | 32 ++++++ plat/linuxppc/emu/instructions.dat | 149 +++++++++++++++++++++++++ plat/linuxppc/emu/main.c | 173 +++++++++++++++++++++++++++++ plat/linuxppc/emu/mkdispatcher.lua | 77 +++++++++++++ plat/linuxppc/tests/build.lua | 2 +- 7 files changed, 628 insertions(+), 1 deletion(-) create mode 100644 plat/linuxppc/emu/build.lua create mode 100644 plat/linuxppc/emu/emu.c create mode 100644 plat/linuxppc/emu/emu.h create mode 100644 plat/linuxppc/emu/instructions.dat create mode 100755 plat/linuxppc/emu/main.c create mode 100644 plat/linuxppc/emu/mkdispatcher.lua diff --git a/plat/linuxppc/emu/build.lua b/plat/linuxppc/emu/build.lua new file mode 100644 index 000000000..de5208513 --- /dev/null +++ b/plat/linuxppc/emu/build.lua @@ -0,0 +1,28 @@ +normalrule { + name = "dispatcher", + ins = { + "./mkdispatcher.lua", + "./instructions.dat" + }, + outleaves = { + "dispatcher.h" + }, + commands = { + "$(LUA) %{ins[1]} < %{ins[2]} > %{outs}" + } +} + +clibrary { + name = "dispatcher_lib", + srcs = {}, + hdrs = { "+dispatcher" } +} + +cprogram { + name = "emuppc", + srcs = { "./*.c" }, + deps = { + "+dispatcher_lib" + } +} + diff --git a/plat/linuxppc/emu/emu.c b/plat/linuxppc/emu/emu.c new file mode 100644 index 000000000..b2f5f2844 --- /dev/null +++ b/plat/linuxppc/emu/emu.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include "emu.h" + +cpu_t cpu; + +static inline bool carry(void) +{ + fatal("carry() not supported yet"); +} + +#define swb16(x) bswap_16(x) +#define swb32(x) bswap_32(x) + +static inline uint32_t reg(uint8_t n) +{ + return cpu.gpr[n]; +} + +static inline uint32_t reg0(uint8_t n) +{ + if (n == 0) + return 0; + return cpu.gpr[n]; +} + +static inline uint32_t ext8(int8_t n) +{ + return (n << 24) >> 24; +} + +static inline uint32_t ext16(int16_t n) +{ + return (n << 16) >> 16; +} + +static bool getcr(uint8_t bit) +{ + bit = 31 - bit; /* note PowerPC bit numbering */ + return cpu.cr & (1<: a field occupying so many bits. +# T: a field occupying one bit. +# .: a bit we don't care about. + +# Branch processor instructions. + +<18-->AL branch(0x1f, 0x00, LI, A, L); +<16-->AL branch(BO, BI, BD, A, L); +<19--><16------>L branch(BO, BI, cpu.lr, 1, L); +<19--><528----->L branch(BO, BI, cpu.ctr, 1, L); +<17-->.................1. system_call(LEV); + +# Condition register instructions. + +<19--><257----->. setcr(BT, getcr(BA) & getcr(BB)); +<19--><449----->. setcr(BT, getcr(BA) | getcr(BB)); +<19--><193----->. setcr(BT, getcr(BA) ^ getcr(BB)); +<19--><225----->. setcr(BT, !(getcr(BA) & getcr(BB))); +<19--><33------>. setcr(BT, !(getcr(BA) | getcr(BB))); +<19--><289----->. setcr(BT, getcr(BA) == getcr(BB)); +<19--><129----->. setcr(BT, getcr(BA) & !getcr(BB)); +<19--><417----->. setcr(BT, getcr(BA) | !getcr(BB)); +<19-->.......<0------->. mcrf(BF, BA); + +# Fixed point loads + +<34--> cpu.gpr[RT] = read_byte(reg0(RA) + ext16(D)); +<31--><87------>. cpu.gpr[RT] = read_byte(reg0(RA) + reg(RB)); +<35--> uint32_t ea = reg(RA) + ext16(D); cpu.gpr[RT] = read_byte(ea); cpu.gpr[RA] = ea; +<31--><119----->. uint32_t ea = reg(RA) + reg(RB); cpu.gpr[RT] = read_byte(ea); cpu.gpr[RA] = ea; +<40--> cpu.gpr[RT] = read_word(reg0(RA) + ext16(D)); +<31--><279----->. cpu.gpr[RT] = read_word(reg0(RA) + reg(RB)); +<41--> uint32_t ea = reg(RA) + ext16(D); cpu.gpr[RT] = read_word(ea); cpu.gpr[RA] = ea; +<31--><311----->. uint32_t ea = reg(RA) + reg(RB); cpu.gpr[RT] = read_word(ea); cpu.gpr[RA] = ea; +<42--> cpu.gpr[RT] = ext16(read_word(reg0(RA) + ext16(D))); +<31--><343----->. cpu.gpr[RT] = ext16(read_word(reg0(RA) + reg(RB))); +<43--> uint32_t ea = reg(RA) + ext16(D); cpu.gpr[RT] = ext16(read_word(ea)); cpu.gpr[RA] = ea; +<31--><375----->. uint32_t ea = reg(RA) + reg(RB); cpu.gpr[RT] = ext16(read_word(ea)); cpu.gpr[RA] = ea; +<32--> cpu.gpr[RT] = read_long(reg0(RA) + ext16(D)); +<31--><23------>. cpu.gpr[RT] = read_long(reg0(RA) + reg(RB)); +<33--> uint32_t ea = reg(RA) + ext16(D); cpu.gpr[RT] = read_long(ea); cpu.gpr[RA] = ea; +<31--><55------>. uint32_t ea = reg(RA) + reg(RB); cpu.gpr[RT] = read_long(ea); cpu.gpr[RA] = ea; +<58-->10 cpu.gpr[RT] = read_long(reg0(RA) + ext16(DS<<2)); +<31--><341----->. cpu.gpr[RT] = read_long(reg0(RA) + reg(RB)); +<31--><373----->. uint32_t ea = reg(RA) + reg(RB); cpu.gpr[RT] = read_long(ea); cpu.gpr[RA] = ea; + +# Fixed point stores + +<38--> write_byte(reg0(RA) + ext16(D), RS); +<31--><215----->. write_byte(reg0(RA) + reg(RB), RS); +<39--> uint32_t ea = reg(RA) + ext16(D); write_byte(ea, reg(RS)); cpu.gpr[RA] = ea; +<31--><247----->. uint32_t ea = reg(RA) + reg(RB); write_byte(ea, reg(RS)); cpu.gpr[RA] = ea; +<44--> write_word(reg0(RA) + ext16(D), RS); +<31--><407----->. write_word(reg0(RA) + reg(RB), RS); +<45--> uint32_t ea = reg(RA) + ext16(D); write_word(ea, reg(RS)); cpu.gpr[RA] = ea; +<31--><439----->. uint32_t ea = reg(RA) + reg(RB); write_word(ea, reg(RS)); cpu.gpr[RA] = ea; +<36--> write_long(reg0(RA) + ext16(D), RS); +<31--><151----->. write_long(reg0(RA) + reg(RB), RS); +<37--> uint32_t ea = reg(RA) + ext16(D); write_long(ea, reg(RS)); cpu.gpr[RA] = ea; +<31--><183----->. uint32_t ea = reg(RA) + reg(RB); write_long(ea, reg(RS)); cpu.gpr[RA] = ea; + +# Fixed point load/stores with byte reversal + +<31--><790----->. cpu.gpr[RT] = swb16(read_word(reg0(RA) + reg(RB))); +<31--><534----->. cpu.gpr[RT] = swb32(read_long(reg0(RA) + reg(RB))); +<31--><918----->. write_word(reg0(RA) + reg(RB), swb16(reg(RS))); +<31--><662----->. write_long(reg0(RA) + reg(RB), swb32(reg(RS))); + +# Load/store multiple + +<46--> read_multiple(reg0(RA) + ext16(D), RT); +<47--> write_multiple(reg0(RA) + ext16(D), RS); +<31--><597----->. read_string(reg0(RA), RT, NB ? NB : 32); +<31--><533----->. read_string(reg0(RA) + reg(RB), RT, cpu.xer & 0x1f); +<31--><725----->. write_string(reg0(RA), RS, NB ? NB : 32); +<31--><661----->. write_string(reg0(RA) + reg(RB), RS, cpu.xer & 0x1f); + +# ALU instructions + +<14--> cpu.gpr[RT] = reg0(RA) + ext16(SI); +<15--> cpu.gpr[RT] = reg0(RA) + (SI<<16); +<31-->O<266---->R setcr0(R, cpu.gpr[RT] = addo(reg(RA), reg(RB), 0, O, 0)); +<31-->O<40----->R setcr0(R, cpu.gpr[RT] = addo(~reg(RA), reg(RB), 1, O, 0)); +<6-->R cpu.gpr[RT] = addo(reg(RA), ext16(SI), 0, 0, 1); +<8---> cpu.gpr[RT] = addo(~reg(RA), ext16(SI), 1, 0, 1); +<31-->O<10----->R setcr0(R, cpu.gpr[RT] = addo(reg(RA), reg(RB), 0, O, 1)); +<31-->O<8------>R setcr0(R, cpu.gpr[RT] = addo(~reg(RA), reg(RB), 1, O, 1)); +<31-->O<138---->R setcr0(R, cpu.gpr[RT] = addo(reg(RA), reg(RB), carry(), O, 1)); +<31-->O<136---->R setcr0(R, cpu.gpr[RT] = addo(~reg(RA), reg(RB), carry(), O, 1)); +<31-->.....O<234---->R setcr0(R, cpu.gpr[RT] = addo(reg(RA), -1, carry(), O, 1)); +<31-->.....O<232---->R setcr0(R, cpu.gpr[RT] = addo(~reg(RA), -1, carry(), O, 1)); +<31-->.....O<202---->R setcr0(R, cpu.gpr[RT] = addo(reg(RA), 0, carry(), O, 1)); +<31-->.....O<200---->R setcr0(R, cpu.gpr[RT] = addo(~reg(RA), 0, carry(), O, 1)); +<31-->.....O<104---->R setcr0(R, cpu.gpr[RT] = addo(~reg(RA), 0, 1, O, 0)); +<7---> cpu.gpr[RT] = reg(RA) * ext16(SI); +<31-->O<235---->R setcr0(R, cpu.gpr[RT] = mulo(reg(RA), reg(RB), O)); +<31-->O<491---->R setcr0(R, cpu.gpr[RT] = divo(reg(RA), reg(RB), O)); +<31-->O<459---->R setcr0(R, cpu.gpr[RT] = divuo(reg(RA), reg(RB), O)); + +# Comparison instructions + +<11-->.0 compares(reg(RA), ext16(SI), F); +<31-->.0<0------->. compares(reg(RA), reg(RB), F); +<10-->.0 compareu(reg(RA), UI, F); +<31-->.0<32------>. compareu(reg(RA), reg(RB), F); + +# Logical instructions + +<28--> cpu.gpr[RA] = reg(RS) & UI; +<29--> cpu.gpr[RA] = reg(RS) & (UI<<16); +<24--> cpu.gpr[RA] = reg(RS) | UI; +<25--> cpu.gpr[RA] = reg(RS) | (UI<<16); +<26--> cpu.gpr[RA] = reg(RS) ^ UI; +<27--> cpu.gpr[RA] = reg(RS) ^ (UI<<16); +<31--><28------>R setcr0(R, cpu.gpr[RA] = reg(RS) & reg(RB)); +<31--><444----->R setcr0(R, cpu.gpr[RA] = reg(RS) | reg(RB)); +<31--><316----->R setcr0(R, cpu.gpr[RA] = reg(RS) ^ reg(RB)); +<31--><476----->R setcr0(R, cpu.gpr[RA] = ~(reg(RS) & reg(RB))); +<31--><124----->R setcr0(R, cpu.gpr[RA] = ~(reg(RS) | reg(RB))); +<31--><284----->R setcr0(R, cpu.gpr[RA] = ~(reg(RS) ^ reg(RB))); +<31--><60------>R setcr0(R, cpu.gpr[RA] = reg(RS) & ~reg(RB)); +<31--><412----->R setcr0(R, cpu.gpr[RA] = reg(RS) | ~reg(RB)); +<31-->.....<954----->R setcr0(R, cpu.gpr[RA] = ext8(reg(RS))); +<31-->.....<922----->R setcr0(R, cpu.gpr[RA] = ext16(reg(RS))); +<31-->.....<26------>R setcr0(R, cpu.gpr[RA] = cntlzw(reg(RS))); +<31-->.....<122----->R setcr0(R, cpu.gpr[RA] = popcntb(reg(RS))); + +# Rotation/shift instructions + +<21-->R setcr0(R, cpu.gpr[RA] = rlwnm(reg(RS), SH, MB, ME)); +<23-->R setcr0(R, cpu.gpr[RA] = rlwnm(reg(RS), reg(RB), MB, ME)); +<20-->R setcr0(R, cpu.gpr[RA] = rlwmi(reg(RS), SH, MB, ME)); +<31--><24------>R setcr0(R, cpu.gpr[RA] = reg(RS) << (reg(RB) & 0x1f)); +<31--><536----->R setcr0(R, cpu.gpr[RA] = reg(RS) >> (reg(RB) & 0x1f)); +<31--><824----->R setcr0(R, cpu.gpr[RA] = ((int32_t)reg(RS)) >> SH); +<31--><792----->R setcr0(R, cpu.gpr[RA] = ((int32_t)reg(RS)) >> (reg(RB) & 0x1f)); + +# Move to/from special registers + +<31--><1-->00000<467----->. cpu.xer = reg(RS); +<31--><8-->00000<467----->. cpu.lr = reg(RS); +<31--><9-->00000<467----->. cpu.ctr = reg(RS); +<31--><1-->00000<339----->. cpu.gpr[RT] = cpu.xer; +<31--><8-->00000<339----->. cpu.gpr[RT] = cpu.lr; +<31--><9-->00000<339----->. cpu.gpr[RT] = cpu.ctr; +<31-->0.<144----->. mtcrf(FXM, reg(RS)); +<31-->0.........<19------>. cpu.gpr[RT] = cpu.cr; + diff --git a/plat/linuxppc/emu/main.c b/plat/linuxppc/emu/main.c new file mode 100755 index 000000000..3b2ef7676 --- /dev/null +++ b/plat/linuxppc/emu/main.c @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "emu.h" + +#define RAM_BASE 0x10000000 +#define RAM_TOP 0x10100000 + +#define BRK_TOP (RAM_TOP - 0x1000) + +#define INIT_SP RAM_TOP +#define INIT_PC 0x08000054 + +/* Read/write macros */ +#define READ_BYTE(BASE, ADDR) (BASE)[ADDR] +#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | \ + (BASE)[(ADDR)+1]) +#define READ_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) | \ + ((BASE)[(ADDR)+1]<<16) | \ + ((BASE)[(ADDR)+2]<<8) | \ + (BASE)[(ADDR)+3]) + +#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)&0xff +#define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff; \ + (BASE)[(ADDR)+1] = (VAL)&0xff +#define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>24) & 0xff; \ + (BASE)[(ADDR)+1] = ((VAL)>>16)&0xff; \ + (BASE)[(ADDR)+2] = ((VAL)>>8)&0xff; \ + (BASE)[(ADDR)+3] = (VAL)&0xff + + +static void emulated_syscall(void); + +static unsigned char ram[RAM_TOP - RAM_BASE]; +uint32_t brkbase = RAM_BASE; +uint32_t brkpos = RAM_BASE; +uint32_t entrypoint = RAM_BASE; + +void fatal(char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "fatal: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + + exit(EXIT_FAILURE); +} + +static uint32_t transform_address(uint32_t address) +{ + uint32_t a = address - RAM_BASE; + if (a >= RAM_TOP) + fatal("address 0x%x out of bounds", address); + return a; +} + +uint32_t read_long(uint32_t address) +{ + return READ_LONG(ram, transform_address(address)); +} + + +uint32_t read_word(uint32_t address) +{ + return READ_WORD(ram, transform_address(address)); +} + +uint32_t read_byte(uint32_t address) +{ + return READ_BYTE(ram, transform_address(address)); +} + +void write_byte(uint32_t address, uint32_t value) +{ + WRITE_BYTE(ram, transform_address(address), value); +} + +void write_word(uint32_t address, uint32_t value) +{ + WRITE_WORD(ram, transform_address(address), value); +} + +void write_long(uint32_t address, uint32_t value) +{ + WRITE_LONG(ram, transform_address(address), value); +} + +void system_call(uint8_t trapno) +{ + fatal("syscalls unimplemented"); +} + +static void load_program(FILE* fd) +{ + fseek(fd, 0, SEEK_SET); + if (fread(ram, 1, 0x34, fd) != 0x34) + fatal("couldn't read ELF header"); + + uint32_t phoff = READ_LONG(ram, 0x1c); + uint16_t phentsize = READ_WORD(ram, 0x2a); + uint16_t phnum = READ_WORD(ram, 0x2c); + entrypoint = READ_LONG(ram, 0x18); + if ((phentsize != 0x20) || (phnum != 1)) + fatal("unsupported ELF file"); + + fseek(fd, phoff, SEEK_SET); + if (fread(ram, 1, phentsize, fd) != phentsize) + fatal("couldn't read program header"); + + uint32_t offset = READ_LONG(ram, 0x04); + uint32_t vaddr = READ_LONG(ram, 0x08); + uint32_t filesz = READ_LONG(ram, 0x10); + uint32_t memsz = READ_LONG(ram, 0x14); + brkbase = brkpos = vaddr + memsz; + + uint32_t vaddroffset = transform_address(vaddr); + transform_address(vaddr + memsz); /* bounds check */ + memset(ram+vaddroffset, 0, memsz); + fseek(fd, offset, SEEK_SET); + if (fread(ram+vaddroffset, 1, filesz, fd) != filesz) + fatal("couldn't read program data"); +} + +/* The main loop */ +int main(int argc, char* argv[]) +{ + if(argc != 2) + fatal("syntax: emuppc "); + + FILE* fd = fopen(argv[1], "rb"); + if (!fd) + fatal("Unable to open %s", argv[1]); + load_program(fd); + fclose(fd); + + /* On entry, the Linux 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 + * + * We'll set it up with a bodgy stack frame with argc=0 just to keep the + * startup code happy. + */ + + { + uint32_t sp = INIT_SP; + write_long(sp -= 4, 0); + uint32_t envp = sp; + write_long(sp -= 4, envp); + write_long(sp -= 4, 0); + unsigned long argv = sp; + write_long(sp -= 4, argv); + write_long(sp -= 4, 0); + cpu.gpr[1] = sp; + cpu.cia = entrypoint; + } + + fatal("execution unimplemented"); + + return 0; +} + diff --git a/plat/linuxppc/emu/mkdispatcher.lua b/plat/linuxppc/emu/mkdispatcher.lua new file mode 100644 index 000000000..a660b8c34 --- /dev/null +++ b/plat/linuxppc/emu/mkdispatcher.lua @@ -0,0 +1,77 @@ +local function decode(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 + end + i = i + 1 + end + 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 ~= "" then + local fields = decode(line) + emit(fields, line:sub(34, #line)) + end +end + diff --git a/plat/linuxppc/tests/build.lua b/plat/linuxppc/tests/build.lua index 7601ab0be..7ea6e5bb9 100644 --- a/plat/linuxppc/tests/build.lua +++ b/plat/linuxppc/tests/build.lua @@ -3,5 +3,5 @@ include("tests/plat/build.lua") plat_testsuite { name = "tests", plat = "linuxppc", - method = "qemu-ppc" + method = "plat/linuxppc/emu+emuppc" } From 853af4c4dd40020e19c65aef646fd7189f4073ab Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 14 Jun 2018 04:41:21 -0700 Subject: [PATCH 2/9] Some code runs (up to needing setcr0). --- plat/linuxppc/emu/emu.c | 68 +++++++++++++++++++++++++++--- plat/linuxppc/emu/emu.h | 3 ++ plat/linuxppc/emu/instructions.dat | 4 +- plat/linuxppc/emu/main.c | 6 ++- 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/plat/linuxppc/emu/emu.c b/plat/linuxppc/emu/emu.c index b2f5f2844..0714de8e8 100644 --- a/plat/linuxppc/emu/emu.c +++ b/plat/linuxppc/emu/emu.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,6 +6,12 @@ #include #include "emu.h" +#define BO4 (1<<0) +#define BO3 (1<<1) +#define BO2 (1<<2) +#define BO1 (1<<3) +#define BO0 (1<<4) + cpu_t cpu; static inline bool carry(void) @@ -62,17 +69,46 @@ static void mcrf(uint8_t destfield, uint8_t srcfield) static void branch(uint8_t bo, uint8_t bi, uint32_t dest, bool a_bit, bool l_bit) { - fatal("branch not supported yet"); + bool bo0 = bo & BO0; + bool bo1 = bo & BO1; + bool bo2 = bo & BO2; + bool bo3 = bo & BO3; + bool ctr_ok; + bool cond_ok; + + if (!bo2) + cpu.ctr--; + ctr_ok = bo2 || (!!cpu.ctr ^ bo3); + cond_ok = bo0 || (!!(cpu.cr & (1<<(31-bi))) == bo1); + if (ctr_ok && cond_ok) + { + if (a_bit) + cpu.nia = dest; + else + cpu.nia = dest + cpu.cia; + } + if (l_bit) + cpu.lr = cpu.cia + 4; } static void read_multiple(uint32_t address, uint8_t reg) { - fatal("read_multiple not supported yet"); + while (reg != 32) + { + cpu.gpr[reg] = read_long(address); + reg++; + address += 4; + } } static void write_multiple(uint32_t address, uint8_t reg) { - fatal("write_multiple not supported yet"); + while (reg != 32) + { + write_long(address, cpu.gpr[reg]); + reg++; + address += 4; + } } static void read_string(uint32_t address, uint8_t reg, uint8_t bytes) @@ -137,9 +173,16 @@ static uint32_t popcntb(uint32_t source) fatal("popcntb not supported"); } +static uint32_t rotate(uint32_t i, uint32_t shift) +{ + return (i << shift) | (i >> (32-shift)); +} + static uint32_t rlwnm(uint32_t source, uint8_t shift, uint8_t mb, uint8_t me) { - fatal("rlwnm not supported"); + uint8_t masksize = 1 + me - mb; /* me and mb are inclusive */ + uint32_t mask = ((1<AL branch(0x1f, 0x00, LI, A, L); -<16-->AL branch(BO, BI, BD, A, L); +<18-->AL branch(0x1f, 0x00, LI<<2, A, L); +<16-->AL branch(BO, BI, BD<<2, A, L); <19--><16------>L branch(BO, BI, cpu.lr, 1, L); <19--><528----->L branch(BO, BI, cpu.ctr, 1, L); <17-->.................1. system_call(LEV); diff --git a/plat/linuxppc/emu/main.c b/plat/linuxppc/emu/main.c index 3b2ef7676..21abadbc9 100755 --- a/plat/linuxppc/emu/main.c +++ b/plat/linuxppc/emu/main.c @@ -166,7 +166,11 @@ int main(int argc, char* argv[]) cpu.cia = entrypoint; } - fatal("execution unimplemented"); + for (;;) + { + dump_state(stderr); + single_step(); + } return 0; } From 5111556d145675e4eba1a65abf298976358d2b1d Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 14 Jun 2018 05:53:39 -0700 Subject: [PATCH 3/9] Got the emulator to the point where we're hitting the first major emulation bug (the calloc test hangs). --- plat/linuxppc/emu/emu.c | 33 +++++++++++++++++++++++++----- plat/linuxppc/emu/instructions.dat | 8 ++++---- plat/linuxppc/emu/main.c | 13 ++++++++++-- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/plat/linuxppc/emu/emu.c b/plat/linuxppc/emu/emu.c index 0714de8e8..31bb7f1b7 100644 --- a/plat/linuxppc/emu/emu.c +++ b/plat/linuxppc/emu/emu.c @@ -44,6 +44,11 @@ static inline uint32_t ext16(int16_t n) return (n << 16) >> 16; } +static inline uint32_t ext26(int32_t n) +{ + return (n << 6) >> 6; +} + static bool getcr(uint8_t bit) { bit = 31 - bit; /* note PowerPC bit numbering */ @@ -59,7 +64,12 @@ static void setcr(uint8_t bit, bool value) static void setcr0(bool setcr0, uint32_t value) { if (setcr0) - fatal("setcr0 not supported yet"); + { + setcr(0, (int32_t)value < 0); + setcr(1, (int32_t)value > 0); + setcr(2, value == 0); + setcr(3, cpu.xer & (1<<31)); + } } static void mcrf(uint8_t destfield, uint8_t srcfield) @@ -142,6 +152,8 @@ static int32_t divo(int32_t a, int32_t b, bool set_o) if (set_o) fatal("can't use O bit in div yet"); + if (b == 0) + return 0; return a / b; } @@ -150,17 +162,27 @@ static uint32_t divuo(uint32_t a, uint32_t b, bool set_o) if (set_o) fatal("can't use O bit in divu yet"); + if (b == 0) + return 0; return a / b; } static void compares(int32_t a, int32_t b, uint8_t field) { - fatal("compares not supported yet"); + uint8_t bit = field*4; + setcr(bit+0, ab); + setcr(bit+2, a==b); + setcr(bit+3, cpu.xer & (1<<31)); } static void compareu(uint32_t a, uint32_t b, uint8_t field) { - fatal("compareu not supported yet"); + uint8_t bit = field*4; + setcr(bit+0, ab); + setcr(bit+2, a==b); + setcr(bit+3, cpu.xer & (1<<31)); } static uint32_t cntlzw(uint32_t source) @@ -207,11 +229,12 @@ void dump_state(FILE* stream) fprintf(stream, "pc=0x%08x lr=0x%08x ctr=0x%08x xer=0x%08x cr=0x%08x\n", cpu.cia, cpu.lr, cpu.ctr, cpu.xer, cpu.cr); + fprintf(stream, "insn=0x%08x", read_long(cpu.cia)); for (i=0; i<32; i++) { - if ((i % 8) == 7) + if ((i % 4) == 0) fprintf(stream, "\n"); - fprintf(stream, "gpr%d=0x%08x ", i, cpu.gpr[i]); + fprintf(stream, "gpr%02d=0x%08x ", i, cpu.gpr[i]); } fprintf(stream, "\n"); } diff --git a/plat/linuxppc/emu/instructions.dat b/plat/linuxppc/emu/instructions.dat index 34108d4d7..2203f9ccf 100644 --- a/plat/linuxppc/emu/instructions.dat +++ b/plat/linuxppc/emu/instructions.dat @@ -5,10 +5,10 @@ # Branch processor instructions. -<18-->AL branch(0x1f, 0x00, LI<<2, A, L); -<16-->AL branch(BO, BI, BD<<2, A, L); -<19--><16------>L branch(BO, BI, cpu.lr, 1, L); -<19--><528----->L branch(BO, BI, cpu.ctr, 1, L); +<18-->AL branch(0x1f, 0x00, ext26(LI<<2), A, L); +<16-->AL branch(BO, BI, ext16(BD<<2), A, L); +<19--><16------>L branch(BO, BI, cpu.lr, 1, L); +<19--><528----->L branch(BO, BI, cpu.ctr, 1, L); <17-->.................1. system_call(LEV); # Condition register instructions. diff --git a/plat/linuxppc/emu/main.c b/plat/linuxppc/emu/main.c index 21abadbc9..b7ac3e896 100755 --- a/plat/linuxppc/emu/main.c +++ b/plat/linuxppc/emu/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,8 @@ uint32_t entrypoint = RAM_BASE; void fatal(char* fmt, ...) { + static bool guard = false; + va_list ap; va_start(ap, fmt); @@ -51,13 +54,19 @@ void fatal(char* fmt, ...) fprintf(stderr, "\n"); va_end(ap); + if (!guard) + { + guard = true; + dump_state(stderr); + } + exit(EXIT_FAILURE); } static uint32_t transform_address(uint32_t address) { uint32_t a = address - RAM_BASE; - if (a >= RAM_TOP) + if (a >= (RAM_TOP-RAM_BASE)) fatal("address 0x%x out of bounds", address); return a; } @@ -168,7 +177,7 @@ int main(int argc, char* argv[]) for (;;) { - dump_state(stderr); + //dump_state(stderr); single_step(); } From 5d7cdd2c6754c61319fe5bff5260ac2bf2f25b22 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 16 Jun 2018 08:35:36 +0200 Subject: [PATCH 4/9] Fix a setcr0 bug which was trashing the condition register; some system calls are now implemented. A few tests more-or-less pass (but crash on exit). --- plat/linuxppc/emu/emu.c | 8 +++++-- plat/linuxppc/emu/main.c | 45 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/plat/linuxppc/emu/emu.c b/plat/linuxppc/emu/emu.c index 31bb7f1b7..29404390c 100644 --- a/plat/linuxppc/emu/emu.c +++ b/plat/linuxppc/emu/emu.c @@ -58,7 +58,7 @@ static bool getcr(uint8_t bit) static void setcr(uint8_t bit, bool value) { bit = 31 - bit; /* note PowerPC bit numbering */ - cpu.cr = cpu.cr & (1< Date: Sat, 16 Jun 2018 22:55:23 +0200 Subject: [PATCH 5/9] Do a bit of floating point stuff; added brk(); fixed a horrible bug where stores with 16-bit displacements were storing the register number and not the contents of the register. --- plat/linuxppc/emu/emu.c | 18 ++++++++++++++++- plat/linuxppc/emu/emu.h | 2 ++ plat/linuxppc/emu/instructions.dat | 30 ++++++++++++++++++++++------ plat/linuxppc/emu/main.c | 32 ++++++++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 9 deletions(-) diff --git a/plat/linuxppc/emu/emu.c b/plat/linuxppc/emu/emu.c index 29404390c..75800807e 100644 --- a/plat/linuxppc/emu/emu.c +++ b/plat/linuxppc/emu/emu.c @@ -34,6 +34,16 @@ static inline uint32_t reg0(uint8_t n) return cpu.gpr[n]; } +static inline uint64_t tobytes(double n) +{ + return *(uint64_t*)&n; +} + +static inline double fpr(uint8_t n) +{ + return *(double*)&cpu.fpr[n]; +} + static inline uint32_t ext8(int8_t n) { return (n << 24) >> 24; @@ -72,6 +82,12 @@ static void setcr0(bool setcr0, uint32_t value) } } +static void setcr1(bool setcr1, uint64_t value) +{ + if (setcr1) + fatal("setcr1 not implemented yet"); +} + static void mcrf(uint8_t destfield, uint8_t srcfield) { fatal("mcrf not supported yet"); @@ -220,7 +236,7 @@ static void mtcrf(uint8_t fxm, uint32_t value) static void dispatch(uint32_t value) { #include "dispatcher.h" - fatal("unimplemented instruction 0x%0x", value); + fatal("unimplemented instruction 0x%0x (major opcode %d)", value, value>>26); } void dump_state(FILE* stream) diff --git a/plat/linuxppc/emu/emu.h b/plat/linuxppc/emu/emu.h index 58fad27ec..622a02536 100644 --- a/plat/linuxppc/emu/emu.h +++ b/plat/linuxppc/emu/emu.h @@ -22,9 +22,11 @@ extern cpu_t cpu; extern uint32_t read_byte(uint32_t address); extern uint32_t read_word(uint32_t address); extern uint32_t read_long(uint32_t address); +extern uint64_t read_double(uint32_t address); extern void write_byte(uint32_t address, uint32_t value); extern void write_word(uint32_t address, uint32_t value); extern void write_long(uint32_t address, uint32_t value); +extern void write_double(uint32_t address, uint64_t value); extern void system_call(uint8_t trapno); diff --git a/plat/linuxppc/emu/instructions.dat b/plat/linuxppc/emu/instructions.dat index 2203f9ccf..09b2f3ec0 100644 --- a/plat/linuxppc/emu/instructions.dat +++ b/plat/linuxppc/emu/instructions.dat @@ -47,16 +47,16 @@ # Fixed point stores -<38--> write_byte(reg0(RA) + ext16(D), RS); -<31--><215----->. write_byte(reg0(RA) + reg(RB), RS); +<38--> write_byte(reg0(RA) + ext16(D), reg(RS)); +<31--><215----->. write_byte(reg0(RA) + reg(RB), reg(RS)); <39--> uint32_t ea = reg(RA) + ext16(D); write_byte(ea, reg(RS)); cpu.gpr[RA] = ea; <31--><247----->. uint32_t ea = reg(RA) + reg(RB); write_byte(ea, reg(RS)); cpu.gpr[RA] = ea; -<44--> write_word(reg0(RA) + ext16(D), RS); -<31--><407----->. write_word(reg0(RA) + reg(RB), RS); +<44--> write_word(reg0(RA) + ext16(D), reg(RS)); +<31--><407----->. write_word(reg0(RA) + reg(RB), reg(RS)); <45--> uint32_t ea = reg(RA) + ext16(D); write_word(ea, reg(RS)); cpu.gpr[RA] = ea; <31--><439----->. uint32_t ea = reg(RA) + reg(RB); write_word(ea, reg(RS)); cpu.gpr[RA] = ea; -<36--> write_long(reg0(RA) + ext16(D), RS); -<31--><151----->. write_long(reg0(RA) + reg(RB), RS); +<36--> write_long(reg0(RA) + ext16(D), reg(RS)); +<31--><151----->. write_long(reg0(RA) + reg(RB), reg(RS)); <37--> uint32_t ea = reg(RA) + ext16(D); write_long(ea, reg(RS)); cpu.gpr[RA] = ea; <31--><183----->. uint32_t ea = reg(RA) + reg(RB); write_long(ea, reg(RS)); cpu.gpr[RA] = ea; @@ -147,3 +147,21 @@ <31-->0.<144----->. mtcrf(FXM, reg(RS)); <31-->0.........<19------>. cpu.gpr[RT] = cpu.cr; +# Floating point loads + +<50-->. cpu.fpr[FRT] = read_double(reg0(RA) + ext16(D)); +<31--><599----->. cpu.gpr[FRT] = read_double(reg0(RA) + reg(RB)); +<51--> uint32_t ea = reg(RA) + ext16(D); cpu.fpr[FRT] = read_byte(ea); cpu.gpr[RA] = ea; +<31--><631----->. uint32_t ea = reg(RA) + reg(RB); cpu.fpr[FRT] = read_long(ea); cpu.gpr[RA] = ea; + +# Floating point stores + +<54-->. write_double(read_double(reg0(RA) + ext16(D)), cpu.fpr[FRS]); +<31--><727----->. write_double(reg0(RA) + reg(RB), cpu.fpr[FRS]); +<55--> uint32_t ea = reg(RA) + ext16(D); write_double(ea, cpu.fpr[FRS]); cpu.gpr[RA] = ea; +<31--><759----->. uint32_t ea = reg(RA) + reg(RB); write_long(ea, cpu.fpr[FRS]); cpu.gpr[RA] = ea; + +# Floating point arithmetic + +<63-->.....<72------>R setcr1(R, cpu.fpr[FRT] = cpu.fpr[FRB]); +<63--><20------>R setcr1(R, cpu.fpr[FRT] = tobytes(fpr(FRA) - fpr(FRB))); diff --git a/plat/linuxppc/emu/main.c b/plat/linuxppc/emu/main.c index b6ca92ea7..fe52aa566 100755 --- a/plat/linuxppc/emu/main.c +++ b/plat/linuxppc/emu/main.c @@ -17,6 +17,8 @@ #define INIT_SP RAM_TOP #define INIT_PC 0x08000054 +#define EXIT_PC 0xdeaddead + /* Read/write macros */ #define READ_BYTE(BASE, ADDR) (BASE)[ADDR] #define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | \ @@ -71,6 +73,11 @@ static uint32_t transform_address(uint32_t address) return a; } +uint64_t read_double(uint32_t address) +{ + return ((uint64_t)read_long(address+0) << 32) | read_long(address+4); +} + uint32_t read_long(uint32_t address) { uint32_t v = READ_LONG(ram, transform_address(address)); @@ -80,7 +87,6 @@ uint32_t read_long(uint32_t address) return v; } - uint32_t read_word(uint32_t address) { return READ_WORD(ram, transform_address(address)); @@ -109,6 +115,12 @@ void write_long(uint32_t address, uint32_t value) WRITE_LONG(ram, transform_address(address), value); } +void write_double(uint32_t address, uint64_t value) +{ + write_long(address+0, value>>32); + write_long(address+4, value); +} + void system_call(uint8_t trapno) { cpu.cr &= ~(1<<28); /* reset summary overflow (for success) */ @@ -130,6 +142,21 @@ void system_call(uint8_t trapno) break; } + case 45: /* brk */ + { + uint32_t newpos = cpu.gpr[3]; + if (newpos == 0) + cpu.gpr[4] = brkpos; + else if ((newpos < brkbase) || (newpos >= BRK_TOP)) + cpu.gpr[4] = -ENOMEM; + else + { + brkpos = newpos; + cpu.gpr[4] = 0; + } + break; + } + case 126: /* sigprocmask */ cpu.gpr[4] = 0; break; @@ -212,7 +239,8 @@ int main(int argc, char* argv[]) cpu.cia = entrypoint; } - for (;;) + cpu.lr = EXIT_PC; + while (cpu.cia != EXIT_PC) { #if 0 dump_state(stderr); From ab660a44e9a219216d828efc4e93a0b7e6b32699 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 17 Jun 2018 09:24:01 +0200 Subject: [PATCH 6/9] Lots of floating point, bugfixes, and system calls. Most of the tests pass now. --- plat/linuxppc/emu/README.md | 28 +++++++++++++ plat/linuxppc/emu/emu.c | 67 ++++++++++++++++++++++++++++-- plat/linuxppc/emu/instructions.dat | 62 +++++++++++++++++++++++---- plat/linuxppc/emu/main.c | 5 +++ 4 files changed, 149 insertions(+), 13 deletions(-) create mode 100644 plat/linuxppc/emu/README.md diff --git a/plat/linuxppc/emu/README.md b/plat/linuxppc/emu/README.md new file mode 100644 index 000000000..a37a2b44d --- /dev/null +++ b/plat/linuxppc/emu/README.md @@ -0,0 +1,28 @@ +This is just a naive domestic PowerPC simulator, but I think you'll be amused +by its presumption. + +The simulator implements just enough of the instruction set to make the tests +pass. Certain features aren't supported at all (and an effort has been made +to detect this and error out). The FPU is crudely approximated using the +native floating-point support, doesn't support reading and writing FPSCR, and +will almost certainly produce incorrect results. Plus, there are bugs. It's +also likely to be very, very slow. + +However, it should be easily extensible and the emulator core is only about +500 lines of code. + +Instructions are defined in `instructions.dat`; `mkdispatcher.lua` reads +these in and generates the instruction decoder. `emu.c` contains the main +emulator core. `main.c` contains the application front end and the incredibly +crude syscall interface. + +TODO: + + - overflow bit support (instructions that try to set OV error out) + - mtcrf + - read string / write string + - factor out the ELF loader, and linux68k/emu uses it too + - floating point condition bits + - bit-for-bit FPU emulation, although this looks like a huge amount of work + +It was written from scratch for the ACK by me, David Given. diff --git a/plat/linuxppc/emu/emu.c b/plat/linuxppc/emu/emu.c index 75800807e..3653d8c2e 100644 --- a/plat/linuxppc/emu/emu.c +++ b/plat/linuxppc/emu/emu.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "emu.h" #define BO4 (1<<0) @@ -12,6 +13,10 @@ #define BO1 (1<<3) #define BO0 (1<<4) +#define XER_SO (1<<31) +#define XER_OV (1<<30) +#define XER_CA (1<<29) + cpu_t cpu; static inline bool carry(void) @@ -22,6 +27,16 @@ static inline bool carry(void) #define swb16(x) bswap_16(x) #define swb32(x) bswap_32(x) +/* Returns the state of a carry flag after a three-way add. */ +static inline bool carry_3(uint32_t a, uint32_t b, uint32_t c) +{ + if ((a+b) < a) + return true; + if ((a+b+c) < c) + return true; + return false; +} + static inline uint32_t reg(uint8_t n) { return cpu.gpr[n]; @@ -34,14 +49,33 @@ static inline uint32_t reg0(uint8_t n) return cpu.gpr[n]; } -static inline uint64_t tobytes(double n) +/* Double to bytes */ +static inline uint64_t d2b(double n) { return *(uint64_t*)&n; } +/* Float to bytes */ +static inline uint32_t f2b(float n) +{ + return *(uint32_t*)&n; +} + +/* Bytes to double */ +static inline double b2d(uint64_t n) +{ + return *(double*)&n; +} + +/* Bytes to float */ +static inline float b2f(uint32_t n) +{ + return *(float*)&n; +} + static inline double fpr(uint8_t n) { - return *(double*)&cpu.fpr[n]; + return b2d(cpu.fpr[n]); } static inline uint32_t ext8(int8_t n) @@ -149,9 +183,16 @@ static void write_string(uint32_t address, uint8_t reg, uint8_t bytes) static uint32_t addo(uint32_t a, uint32_t b, uint32_t c, bool set_o, bool set_c) { - if (set_o || set_c) - fatal("can't use O or C bits in add yet"); + if (set_o) + fatal("can't use O bit in add yet"); + if (set_c) + { + cpu.xer = cpu.xer & ~XER_CA; + if (carry_3(a, b, c)) + cpu.xer = cpu.xer | XER_CA; + } + return a + b + c; } @@ -201,6 +242,24 @@ static void compareu(uint32_t a, uint32_t b, uint8_t field) setcr(bit+3, cpu.xer & (1<<31)); } +static void comparef(double a, double b, uint8_t field) +{ + uint8_t c; + if (isnan(a) || isnan(b)) + c = 0x1; + else if (a < b) + c = 0x8; + else if (a > b) + c = 0x4; + else + c = 0x2; + + uint8_t bit = 28 - field*4; /* note PowerPC bit numbering */ + cpu.cr = cpu.cr & ~(0xf<0.<144----->. mtcrf(FXM, reg(RS)); <31-->0.........<19------>. cpu.gpr[RT] = cpu.cr; -# Floating point loads +# Floating pointer operations follow. +# +# These are extremely crude, and just enough has been implemented to make the +# tests pass. The FPSCR bits are all ignored completely. -<50-->. cpu.fpr[FRT] = read_double(reg0(RA) + ext16(D)); -<31--><599----->. cpu.gpr[FRT] = read_double(reg0(RA) + reg(RB)); -<51--> uint32_t ea = reg(RA) + ext16(D); cpu.fpr[FRT] = read_byte(ea); cpu.gpr[RA] = ea; -<31--><631----->. uint32_t ea = reg(RA) + reg(RB); cpu.fpr[FRT] = read_long(ea); cpu.gpr[RA] = ea; +# FPSCR manipulation -# Floating point stores +<63-->..........<583----->R fatal("mffs not supported"); +<63-->.........<64------>. fatal("mcrfs not supported"); +<63-->........<134----->R fatal("mtsfsfi not supported"); +<63-->..<711----->R fatal("mtfsf not supported"); +<63-->..........<70------>R fatal("mtfsb0 not supported"); +<63-->..........<38------>R fatal("mtfsb1 not supported"); -<54-->. write_double(read_double(reg0(RA) + ext16(D)), cpu.fpr[FRS]); +# Floating point double loads (raw bits) + +<50--> cpu.fpr[FRT] = read_double(reg0(RA) + ext16(D)); +<31--><599----->. cpu.fpr[FRT] = read_double(reg0(RA) + reg(RB)); +<51--> uint32_t ea = reg(RA) + ext16(D); cpu.fpr[FRT] = read_double(ea); cpu.gpr[RA] = ea; +<31--><631----->. uint32_t ea = reg(RA) + reg(RB); cpu.fpr[FRT] = read_double(ea); cpu.gpr[RA] = ea; + +# Floating point double stores (raw bits) + +<54--> write_double(reg0(RA) + ext16(D), cpu.fpr[FRS]); <31--><727----->. write_double(reg0(RA) + reg(RB), cpu.fpr[FRS]); <55--> uint32_t ea = reg(RA) + ext16(D); write_double(ea, cpu.fpr[FRS]); cpu.gpr[RA] = ea; -<31--><759----->. uint32_t ea = reg(RA) + reg(RB); write_long(ea, cpu.fpr[FRS]); cpu.gpr[RA] = ea; +<31--><759----->. uint32_t ea = reg(RA) + reg(RB); write_double(ea, cpu.fpr[FRS]); cpu.gpr[RA] = ea; + +# Floating point single loads (convert from single to double) + +<48--> cpu.fpr[FRT] = d2b(b2f(read_long(reg0(RA) + ext16(D)))); +<31--><535----->. cpu.fpr[FRT] = d2b(b2f(read_long(reg0(RA) + reg(RB)))); +<49--> uint32_t ea = reg(RA) + ext16(D); cpu.fpr[FRT] = d2b(b2f(read_long(ea))); cpu.gpr[RA] = ea; +<31--><567----->. uint32_t ea = reg(RA) + reg(RB); cpu.fpr[FRT] = d2b(b2f(read_long(ea))); cpu.gpr[RA] = ea; + +# Floating point single stores (convert from double to single) + +<52--> write_long(reg0(RA) + ext16(D), f2b(fpr(FRS))); +<31--><663----->. write_long(reg0(RA) + reg(RB), f2b(fpr(FRS))); +<53--> uint32_t ea = reg(RA) + ext16(D); write_long(ea, f2b(fpr(FRS))); cpu.gpr[RA] = ea; +<31--><695----->. uint32_t ea = reg(RA) + reg(RB); write_long(ea, f2b(fpr(FRS))); cpu.gpr[RA] = ea; # Floating point arithmetic <63-->.....<72------>R setcr1(R, cpu.fpr[FRT] = cpu.fpr[FRB]); -<63--><20------>R setcr1(R, cpu.fpr[FRT] = tobytes(fpr(FRA) - fpr(FRB))); +<63-->.....<40------>R setcr1(R, cpu.fpr[FRT] = d2b(-fpr(FRB))); +<63-->.....<264----->R setcr1(R, cpu.fpr[FRT] = d2b(fabs(fpr(FRB)))); +<63-->.....<136----->R setcr1(R, cpu.fpr[FRT] = d2b(-fabs(fpr(FRB)))); +<63--><21------>R setcr1(R, cpu.fpr[FRT] = d2b(fpr(FRA) + fpr(FRB))); +<63--><20------>R setcr1(R, cpu.fpr[FRT] = d2b(fpr(FRA) - fpr(FRB))); +<63--><25------>R setcr1(R, cpu.fpr[FRT] = d2b(fpr(FRA) * fpr(FRB))); +<63--><18------>R setcr1(R, cpu.fpr[FRT] = d2b(fpr(FRA) / fpr(FRB))); + +# Floating point comparisons + +<63-->..<0------->. comparef(fpr(FRA), fpr(FRB), F); +<63-->..<32------>. comparef(fpr(FRA), fpr(FRB), F); + +# Floating point conversions + +<63-->.....<14------>R setcr1(R, fpr(FRB)); cpu.fpr[FRT] = (uint32_t)fpr(FRB); +<63-->.....<15------>R setcr1(R, fpr(FRB)); cpu.fpr[FRT] = (uint32_t)fpr(FRB); diff --git a/plat/linuxppc/emu/main.c b/plat/linuxppc/emu/main.c index fe52aa566..79e2634d1 100755 --- a/plat/linuxppc/emu/main.c +++ b/plat/linuxppc/emu/main.c @@ -157,6 +157,11 @@ void system_call(uint8_t trapno) break; } + case 20: /* getpid */ + case 48: /* signal */ + case 54: /* ioctl */ + case 67: /* sigaction */ + case 78: /* gettimeofday */ case 126: /* sigprocmask */ cpu.gpr[4] = 0; break; From 78eaf836bebce72450b4f2916574dcbfef9c65eb Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 17 Jun 2018 10:22:20 +0200 Subject: [PATCH 7/9] Turns out I was returning values from syscalls in the wrong register; fixed. More tests pass. --- plat/linuxppc/emu/emu.c | 6 +++--- plat/linuxppc/emu/main.c | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/plat/linuxppc/emu/emu.c b/plat/linuxppc/emu/emu.c index 3653d8c2e..ae1fb929f 100644 --- a/plat/linuxppc/emu/emu.c +++ b/plat/linuxppc/emu/emu.c @@ -303,7 +303,7 @@ void dump_state(FILE* stream) int i; fprintf(stream, "\n"); - fprintf(stream, "pc=0x%08x lr=0x%08x ctr=0x%08x xer=0x%08x cr=0x%08x\n", + fprintf(stream, "pc=0x%08x lr=0x%08x ctr=0x%08x xer=0x%08x cr=0x%08x", cpu.cia, cpu.lr, cpu.ctr, cpu.xer, cpu.cr); for (i=0; i<32; i++) { @@ -311,11 +311,11 @@ void dump_state(FILE* stream) fprintf(stream, "\n"); fprintf(stream, "gpr%02d=0x%08x ", i, cpu.gpr[i]); } - fprintf(stream, "\n"); + fprintf(stderr, "\n"); /* This might fail and cause a reentrant trap if cia is invalid, so * do it last. */ - fprintf(stream, "insn=0x%08x", read_long(cpu.cia)); + fprintf(stream, "insn=0x%08x\n", read_long(cpu.cia)); } void single_step(void) diff --git a/plat/linuxppc/emu/main.c b/plat/linuxppc/emu/main.c index 79e2634d1..0c2aaea5f 100755 --- a/plat/linuxppc/emu/main.c +++ b/plat/linuxppc/emu/main.c @@ -136,8 +136,8 @@ void system_call(uint8_t trapno) uint32_t len = cpu.gpr[5]; void* ptr = ram + transform_address(address); transform_address(address+len); /* bounds check */ - cpu.gpr[4] = write(fd, ptr, len); - if (cpu.gpr[4] == -1) + cpu.gpr[3] = write(fd, ptr, len); + if (cpu.gpr[3] == -1) goto error; break; } @@ -146,13 +146,13 @@ void system_call(uint8_t trapno) { uint32_t newpos = cpu.gpr[3]; if (newpos == 0) - cpu.gpr[4] = brkpos; + cpu.gpr[3] = brkpos; else if ((newpos < brkbase) || (newpos >= BRK_TOP)) - cpu.gpr[4] = -ENOMEM; + cpu.gpr[3] = -ENOMEM; else { brkpos = newpos; - cpu.gpr[4] = 0; + cpu.gpr[3] = 0; } break; } @@ -163,7 +163,7 @@ void system_call(uint8_t trapno) case 67: /* sigaction */ case 78: /* gettimeofday */ case 126: /* sigprocmask */ - cpu.gpr[4] = 0; + cpu.gpr[3] = 0; break; error: From 7ec9f54679af31216dcdf82acb10328cdd91f83e Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 17 Jun 2018 10:43:39 +0200 Subject: [PATCH 8/9] Turns out that andi and andis only have . forms. Fixed; another test passes. --- plat/linuxppc/emu/instructions.dat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plat/linuxppc/emu/instructions.dat b/plat/linuxppc/emu/instructions.dat index 862e7b091..9bd39af8e 100644 --- a/plat/linuxppc/emu/instructions.dat +++ b/plat/linuxppc/emu/instructions.dat @@ -107,8 +107,8 @@ # Logical instructions -<28--> cpu.gpr[RA] = reg(RS) & UI; -<29--> cpu.gpr[RA] = reg(RS) & (UI<<16); +<28--> setcr0(1, cpu.gpr[RA] = reg(RS) & UI); +<29--> setcr0(1, cpu.gpr[RA] = reg(RS) & (UI<<16)); <24--> cpu.gpr[RA] = reg(RS) | UI; <25--> cpu.gpr[RA] = reg(RS) | (UI<<16); <26--> cpu.gpr[RA] = reg(RS) ^ UI; From 89e8956bb2f174aac7e31c1170ca9c1c592efdb2 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 17 Jun 2018 11:00:01 +0200 Subject: [PATCH 9/9] Fix edge case in rlwnm when the mask is 32 bits wide. All tests now pass. --- plat/linuxppc/emu/emu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plat/linuxppc/emu/emu.c b/plat/linuxppc/emu/emu.c index ae1fb929f..90c9fd518 100644 --- a/plat/linuxppc/emu/emu.c +++ b/plat/linuxppc/emu/emu.c @@ -278,7 +278,7 @@ static uint32_t rotate(uint32_t i, uint32_t shift) static uint32_t rlwnm(uint32_t source, uint8_t shift, uint8_t mb, uint8_t me) { uint8_t masksize = 1 + me - mb; /* me and mb are inclusive */ - uint32_t mask = ((1<