#include "stdafx.h" #include "PPUProgramCompiler.h" using namespace PPU_instr; template InstrBase* GetInstruction(T* list, const wxString& str) { for(int i=0; icount; ++i) { auto instr = list->get_instr_info(i); if(instr) { if(instr->GetName().Cmp(str) == 0) { return instr; } } } return nullptr; } template InstrBase* GetInstruction(const wxString& str) { if(auto res = GetInstruction(main_list, str)) return res; if(auto res = GetInstruction(g04_list, str)) return res; if(auto res = GetInstruction(g04_0_list, str)) return res; if(auto res = GetInstruction(g13_list, str)) return res; if(auto res = GetInstruction(g1e_list, str)) return res; if(auto res = GetInstruction(g1f_list, str)) return res; if(auto res = GetInstruction(g3a_list, str)) return res; if(auto res = GetInstruction(g3b_list, str)) return res; if(auto res = GetInstruction(g3e_list, str)) return res; if(auto res = GetInstruction(g3f_list, str)) return res; if(auto res = GetInstruction(g3f_0_list, str)) return res; return nullptr; } s64 FindOp(const wxString& text, const wxString& op, s64 from) { if(text.Len() < op.Len()) return -1; for(s64 i=from; i= text.Len() || text[i + op.Len()] == '\n' || CompilePPUProgram::IsSkip(text[i + op.Len()])) return i; } } return -1; } ArrayF sections_list; u32 section_name_offs = 0; u32 section_offs = 0; SectionInfo::SectionInfo(const wxString& _name) : name(_name) { memset(&shdr, 0, sizeof(Elf64_Shdr)); section_num = sections_list.Add(this); shdr.sh_offset = section_offs; shdr.sh_name = section_name_offs; section_name_offs += name.GetCount() + 1; } void SectionInfo::SetDataSize(u32 size, u32 align) { if(align) shdr.sh_addralign = align; if(shdr.sh_addralign) size = Memory.AlignAddr(size, shdr.sh_addralign); if(code.GetCount()) { for(u32 i=section_num + 1; iWriteText(text); } } void CompilePPUProgram::WriteError(const wxString& error) { if(m_err_list) { m_err_list->WriteText(wxString::Format("line %lld: %s\n", m_line, error.mb_str())); } } bool CompilePPUProgram::IsSkip(const char c) { return c == ' ' || c == '\t'; } bool CompilePPUProgram::IsCommit(const char c) { return c == '#'; } bool CompilePPUProgram::IsEnd() const { return p >= m_asm.Len(); } bool CompilePPUProgram::IsEndLn(const char c) const { return c == '\n' || p - 1 >= m_asm.Len(); } char CompilePPUProgram::NextChar() { return *m_asm(p++, 1); } void CompilePPUProgram::NextLn() { while( !IsEndLn(NextChar()) ); if(!IsEnd()) m_line++; } void CompilePPUProgram::EndLn() { NextLn(); p--; m_line--; } void CompilePPUProgram::FirstChar() { p = 0; m_line = 1; m_branch_pos = 0; } void CompilePPUProgram::PrevArg() { while( --p >= 0 && (IsSkip(m_asm[p]) || m_asm[p] == ',')); while( --p >= 0 && !IsSkip(m_asm[p]) && !IsEndLn(m_asm[p]) ); if(IsEndLn(m_asm[p])) p++; } bool CompilePPUProgram::GetOp(wxString& result) { s64 from = -1; for(;;) { const char cur_char = NextChar(); const bool skip = IsSkip(cur_char); const bool commit = IsCommit(cur_char); const bool endln = IsEndLn(cur_char); if(endln) p--; if(from == -1) { if(endln || commit) return false; if(!skip) from = p - 1; continue; } if(skip || endln || commit) { const s64 to = (endln ? p : p - 1) - from; result = m_asm(from, to); return true; } } return false; } int CompilePPUProgram::GetArg(wxString& result, bool func) { s64 from = -1; for(char cur_char = NextChar(); !m_error; cur_char = NextChar()) { const bool skip = IsSkip(cur_char); const bool commit = IsCommit(cur_char); const bool endln = IsEndLn(cur_char); const bool end = cur_char == ',' || (func && cur_char == ']'); if(endln) p--; if(from == -1) { if(endln || commit || end) return 0; if(!skip) from = p - 1; continue; } const bool text = m_asm[from] == '"'; const bool end_text = cur_char == '"'; if((text ? end_text : (skip || commit || end)) || endln) { if(text && p > 2 && m_asm[p - 2] == '\\' && (p <= 3 || m_asm[p - 3] != '\\')) { continue; } if(text && !end_text) { WriteError(wxString::Format("'\"' not found.")); m_error = true; } const s64 to = ((endln || text) ? p : p - 1) - from; int ret = 1; if(skip || text) { for(char cur_char = NextChar(); !m_error; cur_char = NextChar()) { const bool skip = IsSkip(cur_char); const bool commit = IsCommit(cur_char); const bool endln = IsEndLn(cur_char); const bool end = cur_char == ',' || (func && cur_char == ']'); if(skip) continue; if(end) break; if(commit) { EndLn(); ret = -1; break; } if(endln) { p--; break; } WriteError(wxString::Format("Bad symbol '%c'", cur_char)); m_error = true; break; } } result = m_asm(from, to); if(text) { for(u32 pos = 0; (s32)(pos = result.find('\\', pos)) >= 0;) { if(pos + 1 < result.Len() && result[pos + 1] == '\\') { pos += 2; continue; } const char v = result[pos + 1]; switch(v) { case 'n': result = result(0, pos) + '\n' + result(pos+2, result.Len()-(pos+2)); break; case 'r': result = result(0, pos) + '\r' + result(pos+2, result.Len()-(pos+2)); break; case 't': result = result(0, pos) + '\t' + result(pos+2, result.Len()-(pos+2)); break; } pos++; } } return ret; } } return 0; } bool CompilePPUProgram::CheckEnd(bool show_err) { if(m_error) { NextLn(); return false; } while(true) { const char cur_char = NextChar(); const bool skip = IsSkip(cur_char); const bool commit = IsCommit(cur_char); const bool endln = IsEndLn(cur_char); if(skip) continue; if(commit) { NextLn(); return true; } if(endln) { p--; NextLn(); return true; } WriteError(wxString::Format("Bad symbol '%c'", cur_char)); NextLn(); return false; } return false; } void CompilePPUProgram::DetectArgInfo(Arg& arg) { const wxString str = arg.string.GetPtr(); if(str.Len() <= 0) { arg.type = ARG_ERR; return; } if(GetInstruction(str)) { arg.type = ARG_INSTR; return; } if(str.Len() > 1) { for(u32 i=0; i '9') { arg.type = ARG_ERR; return; } } u32 reg; sscanf(str(1, str.Len() - 1), "%d", ®); if(reg >= 32) { arg.type = ARG_ERR; return; } switch(str[0]) { case 'r': arg.type = ARG_REG_R; break; case 'f': arg.type = ARG_REG_F; break; case 'v': arg.type = ARG_REG_V; break; default: arg.type = ARG_ERR; break; } arg.value = reg; return; case 'c': if(str.Len() > 2 && str[1] == 'r') { for(u32 i=2; i '9') { arg.type = ARG_ERR; return; } } u32 reg; sscanf(str, "cr%d", ®); if(reg < 8) { arg.type = ARG_REG_CR; arg.value = reg; } else { arg.type = ARG_ERR; } return; } break; case '"': if(str.Len() < 2) { arg.type = ARG_ERR; return; } if(str[str.Len() - 1] != '"') { arg.type = ARG_ERR; return; } arg.string = str(1, str.Len() - 2); arg.type = ARG_TXT; return; } if(str.Len() > 2 && str(0, 2).Cmp("0x") == 0) { for(u32 i=2; i= '0' && str[i] <= '9') || (str[i] >= 'a' && str[i] <= 'f') || (str[i] >= 'A' && str[i] <= 'F') ) continue; arg.type = ARG_ERR; return; } u32 val; sscanf(str, "0x%x", &val); arg.type = ARG_NUM16; arg.value = val; return; } for(u32 i= str[0] == '-' ? 1 : 0; i '9') { arg.type = ARG_ERR; return; } } u32 val; sscanf(str, "%d", &val); arg.type = ARG_NUM; arg.value = val; } void CompilePPUProgram::LoadArgs() { m_args.Clear(); m_cur_arg = 0; wxString str; while(int r = GetArg(str)) { Arg* arg = new Arg(str); DetectArgInfo(*arg); m_args.Add(arg); if(r == -1) break; } m_end_args = m_args.GetCount() > 0; } u32 CompilePPUProgram::GetBranchValue(const wxString& branch) { for(u32 i=0; i= 0) return m_text_addr + m_branches[i].m_pos * 4; return m_branches[i].m_addr; } return 0; } bool CompilePPUProgram::SetNextArgType(u32 types, bool show_err) { if(m_error) return false; if(m_cur_arg >= m_args.GetCount()) { if(show_err) { WriteError(wxString::Format("%d arg not found", m_cur_arg + 1)); m_error = true; } return false; } const Arg& arg = m_args[m_cur_arg]; if(arg.type & types) { m_cur_arg++; return true; } if(show_err) { WriteError(wxString::Format("Bad arg '%s'", &arg.string[0])); m_error = true; } return false; } bool CompilePPUProgram::SetNextArgBranch(u8 aa, bool show_err) { const u32 pos = m_cur_arg; const bool ret = SetNextArgType(ARG_BRANCH | ARG_IMM, show_err); if(!aa && pos < m_args.GetCount()) { switch(m_args[pos].type) { case ARG_NUM: m_args[pos].value += m_text_addr + m_branch_pos * 4; break; case ARG_BRANCH: m_args[pos].value -= m_text_addr + m_branch_pos * 4; break; } } return ret; } bool CompilePPUProgram::IsBranchOp(const wxString& op) { return op.Len() > 1 && op[op.Len() - 1] == ':'; } bool CompilePPUProgram::IsFuncOp(const wxString& op) { return op.Len() >= 1 && op[0] == '['; } CompilePPUProgram::SP_TYPE CompilePPUProgram::GetSpType(const wxString& op) { if(op.Cmp(".int") == 0) return SP_INT; if(op.Cmp(".string") == 0) return SP_STRING; if(op.Cmp(".strlen") == 0) return SP_STRLEN; if(op.Cmp(".buf") == 0) return SP_BUF; if(op.Cmp(".srl") == 0) return SP_SRL; if(op.Cmp(".srr") == 0) return SP_SRR; if(op.Cmp(".mul") == 0) return SP_MUL; if(op.Cmp(".div") == 0) return SP_DIV; if(op.Cmp(".add") == 0) return SP_ADD; if(op.Cmp(".sub") == 0) return SP_SUB; if(op.Cmp(".and") == 0) return SP_AND; if(op.Cmp(".or") == 0) return SP_OR; if(op.Cmp(".xor") == 0) return SP_XOR; if(op.Cmp(".not") == 0) return SP_NOT; if(op.Cmp(".nor") == 0) return SP_NOR; return SP_ERR; } wxString CompilePPUProgram::GetSpStyle(const SP_TYPE sp) { switch(sp) { case SP_INT: case SP_STRING: case SP_STRLEN: case SP_NOT: return "[dst, src]"; case SP_BUF: return "[dst, size]"; case SP_SRL: case SP_SRR: case SP_MUL: case SP_DIV: case SP_ADD: case SP_SUB: case SP_AND: case SP_OR: case SP_XOR: case SP_NOR: return "[dst, src1, src2]"; } return "error"; } bool CompilePPUProgram::IsSpOp(const wxString& op) { return GetSpType(op) != SP_ERR; } CompilePPUProgram::Branch& CompilePPUProgram::GetBranch(const wxString& name) { for(u32 i=0; i 0 && m_asm[p] != '[') p--; p++; wxString dst; if(!GetArg(dst)) { if(m_analyze) WriteHex("error\n"); WriteError(wxString::Format("dst not found. style: %s", GetSpStyle(sp).mb_str())); m_error = true; NextLn(); return; } Arg a_dst(dst); DetectArgInfo(a_dst); Branch* dst_branch = NULL; switch(a_dst.type) { case ARG_BRANCH: { Branch& b = GetBranch(dst); if(b.m_addr >= 0 && b.m_id < 0 && b.m_pos < 0) dst_branch = &b; } break; case ARG_ERR: { m_branches.Move(new Branch(wxEmptyString, -1, 0)); dst_branch = &m_branches[m_branches.GetCount() - 1]; } break; } if(!dst_branch) { if(m_analyze) WriteHex("error\n"); WriteError(wxString::Format("bad dst type. style: %s", GetSpStyle(sp).mb_str())); m_error = true; NextLn(); return; } switch(sp) { case SP_INT: case SP_STRING: case SP_STRLEN: case SP_BUF: case SP_NOT: { wxString src1; if(!GetArg(src1, true)) { if(m_analyze) WriteHex("error\n"); WriteError(wxString::Format("src not found. style: %s", GetSpStyle(sp).mb_str())); m_error = true; NextLn(); return; } Arg a_src1(src1); DetectArgInfo(a_src1); if(sp == SP_STRLEN ? ~(ARG_TXT | ARG_BRANCH) & a_src1.type : sp == SP_STRING ? ~ARG_TXT & a_src1.type : ~(ARG_IMM | ARG_BRANCH) & a_src1.type) { if(m_analyze) WriteHex("error\n"); WriteError(wxString::Format("bad src type. style: %s", GetSpStyle(sp).mb_str())); m_error = true; NextLn(); return; } if(m_asm[p - 1] != ']') { if(m_analyze) WriteHex("error\n"); WriteError(wxString::Format("']' not found. style: %s", GetSpStyle(sp).mb_str())); m_error = true; NextLn(); return; } if(!CheckEnd()) { if(m_analyze) WriteHex("error\n"); return; } if(sp == SP_STRING) { src1 = src1(1, src1.Len()-2); bool founded = false; for(u32 i=0; i> a_src2.value); break; case SP_MUL: *dst_branch = Branch(dst, -1, a_src1.value * a_src2.value); break; case SP_DIV: *dst_branch = Branch(dst, -1, a_src1.value / a_src2.value); break; case SP_ADD: *dst_branch = Branch(dst, -1, a_src1.value + a_src2.value); break; case SP_SUB: *dst_branch = Branch(dst, -1, a_src1.value - a_src2.value); break; case SP_AND: *dst_branch = Branch(dst, -1, a_src1.value & a_src2.value); break; case SP_OR: *dst_branch = Branch(dst, -1, a_src1.value | a_src2.value); break; case SP_XOR: *dst_branch = Branch(dst, -1, a_src1.value ^ a_src2.value); break; case SP_NOR: *dst_branch = Branch(dst, -1, ~(a_src1.value | a_src2.value)); break; } } break; } if(m_analyze) WriteHex("\n"); } void CompilePPUProgram::Compile() { if(m_err_list) { m_err_list->Freeze(); m_err_list->Clear(); } if(m_analyze && m_hex_list) { m_hex_list->Freeze(); m_hex_list->Clear(); } m_code.Clear(); for(u32 i=0; i m_imports; Module(const wxString& name, u32 import) : m_name(name) { Add(import); } void Add(u32 import) { m_imports.AddCpy(import); } void Clear() { m_name.Clear(); m_imports.Clear(); } }; Array modules; FirstChar(); while(!IsEnd()) { wxString op; if(!GetOp(op) || !IsFuncOp(op)) { NextLn(); continue; } while(p > 0 && m_asm[p] != '[') p--; p++; wxString module, name, id; if(!GetArg(module)) { WriteError("module not found. style: [module, name, id]"); m_error = true; NextLn(); continue; } Arg a_module(module); DetectArgInfo(a_module); if(~ARG_ERR & a_module.type) { WriteError("bad module type. style: [module, name, id]"); m_error = true; NextLn(); continue; } if(!GetArg(name)) { WriteError("name not found. style: [module, name, id]"); m_error = true; NextLn(); continue; } Arg a_name(name); DetectArgInfo(a_name); if(~ARG_ERR & a_name.type) { WriteError("bad name type. style: [module, name, id]"); m_error = true; NextLn(); continue; } if(!GetArg(id, true)) { WriteError("id not found. style: [module, name, id]"); m_error = true; NextLn(); continue; } Arg a_id(id); DetectArgInfo(a_id); if(~ARG_IMM & a_id.type) { WriteError("bad id type. style: [module, name, id]"); m_error = true; NextLn(); continue; } if(m_asm[p - 1] != ']') { WriteError("']' not found. style: [module, name, id]"); m_error = true; NextLn(); continue; } if(!CheckEnd()) continue; m_branches.Move(new Branch(name, a_id.value, 0)); const u32 import = m_branches.GetCount() - 1; bool founded = false; for(u32 i=0; i(op); if(instr) { uint type[] = { ARG_IMM, ARG_REG_R, ARG_REG_F, ARG_REG_V, ARG_REG_CR, }; for(uint i=0; iGetArgCount(); ++i) { switch(instr->GetArg(i).m_type) { case FIELD_BRANCH: SetNextArgBranch(0); //TODO break; default: SetNextArgType(type[instr->GetArg(i).m_type]); break; } } } else { WriteError(wxString::Format("unknown instruction '%s'", op.mb_str())); EndLn(); m_error = true; } CheckEnd(); if(m_error) { if(m_analyze) { WriteHex("error\n"); m_error = false; continue; } break; } u32 code; { Array args; args.SetCount(m_args.GetCount()); for(uint i=0; i> 16)); Write32(f, LWZ(12, 12, addr)); Write32(f, STD(2, 1, 40)); Write32(f, LWZ(0, 12, 0)); Write32(f, LWZ(2, 12, 4)); Write32(f, MTSPR(0x009, 0)); Write32(f, BCCTR(20, 0, 0, 0)); } f.Seek(s_lib_stub_top.sh_offset); f.Seek(s_lib_stub_top.sh_size, wxFromCurrent); f.Seek(s_lib_stub.sh_offset); for(u32 i=0, nameoffs=4, dataoffs=0; iThaw(); if(m_analyze) { if(m_hex_list) { m_hex_list->Thaw(); } } else { system("make_fself.cmd"); } }