/* * Copyright (c) 2013, Peter Rutenbar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "../core/shoebill.h" #include "../core/mc68851.h" #define verify_supervisor() {if (!sr_s()) {throw_privilege_violation(); return;}} extern struct dis_t dis; extern uint16_t dis_op; void inst_mc68851_prestore() { printf("%s: Error, not implemented!\n", __func__); assert(!"blowup"); } void inst_mc68851_psave(){ printf("%s: Error, not implemented!\n", __func__); assert(!"blowup"); } void inst_mc68851_pbcc(){ printf("%s: Error, not implemented!\n", __func__); assert(!"blowup"); } void inst_mc68851_pdbcc(uint16_t cond){ printf("%s: Error, not implemented!\n", __func__); assert(!"blowup"); } void inst_mc68851_ptrapcc(uint16_t cond){ printf("%s: Error, not implemented!\n", __func__); assert(!"blowup"); } void inst_mc68851_pscc(uint16_t cond){ printf("%s: Error, not implemented!\n", __func__); assert(!"blowup"); } void inst_mc68851_pload(uint16_t ext){ printf("%s: Error, not implemented!\n", __func__); assert(!"blowup"); } void inst_mc68851_pvalid(uint16_t ext){ printf("%s: Error, not implemented!\n", __func__); assert(!"blowup"); } void inst_mc68851_pflushr(uint16_t ext){ verify_supervisor(); printf("pflushr!"); // Just nuke the entire cache bzero(shoe.pmmu_cache[0].valid_map, 512/8); bzero(shoe.pmmu_cache[1].valid_map, 512/8); } void inst_mc68851_pflush(uint16_t ext){ verify_supervisor(); printf("pflush!"); bzero(shoe.pmmu_cache[0].valid_map, 512/8); bzero(shoe.pmmu_cache[1].valid_map, 512/8); // printf("%s: Error, not implemented!\n", __func__); } void inst_mc68851_pmove(uint16_t ext){ verify_supervisor(); ~decompose(shoe.op, 1111 000 000 MMMMMM); ~decompose(ext, fff ppp w 0000 nnn 00); // instruction format #1 if (f == ~b(010)) { const uint8_t sizes[8] = {4, 8, 8, 8, 1, 1, 1, 2}; // if accessing d or a reg, and sz==8 bytes, that's bogus if (((M>>3) < 2) && (sizes[p]==8)) { throw_illegal_instruction(); return ; } if (!w) { // if we're reading from EA call_ea_read(M, sizes[p]); call_ea_read_commit(M, sizes[p]); } switch (p) { case 0: // tc if (!w) shoe.tc = shoe.dat & 0x83FFFFFF; else { shoe.dat = shoe.tc; //if (!tc_fcl()) assert(!"pmove->tc: function codes not supported\n"); } break; case 1: // drp if (!w) shoe.drp = shoe.dat & 0xffff0203ffffffff; else shoe.dat = shoe.drp; break; case 2: // srp if (!w) shoe.srp = shoe.dat & 0xffff0203ffffffff; else shoe.dat = shoe.srp; break; case 3: // crp if (!w) shoe.crp = shoe.dat & 0xffff0203ffffffff; else shoe.dat = shoe.crp; break; case 4: // cal if (!w) shoe.cal = shoe.dat & ~b(11100000); else shoe.dat = shoe.cal; break; case 5: // val if (!w) shoe.val = shoe.dat & ~b(11100000); else shoe.dat = shoe.val; break; case 6: // scc if (!w) shoe.scc = shoe.dat; else shoe.dat = shoe.scc; break; case 7: // ac if (!w) shoe.ac = shoe.dat & ~b(0000000010110011); else shoe.dat = shoe.ac; break; } if (w) call_ea_write(M, sizes[p]); return ; } else if (f == ~b(011)) { if (p == 0) { // psr if (!w) shoe.psr.word = shoe.dat & ~b(11111111 10000111); else shoe.dat = shoe.psr.word; } else if (p==1) { // pcsr if (!w) shoe.pcsr = shoe.dat; else shoe.dat = shoe.pcsr; } else { assert(!"Unknown register number for pmove format 3!\n"); throw_illegal_instruction(); } if (w) call_ea_write(M, 2); return ; } // TODO: implement instruction formats 2 and 3 (for BAD/BAC, etc.) assert(!"Unsupported pmove instruction format"); throw_illegal_instruction(); } static int64_t ptest_search(const uint32_t _logical_addr, const uint64_t rootp) { // const uint64_t rootp = (tc_sre() && sr_s()) ? shoe.srp : shoe.crp; uint8_t desc_level = 0; int64_t desc_addr = -1; // address of the descriptor (-1 -> register) uint8_t wp = 0; // Whether any descriptor in the search has wp (write protected) set uint8_t i; uint64_t desc = rootp; // Initial descriptor is the root pointer descriptor uint8_t desc_size = 1; // And the root pointer descriptor is always 8 bytes (1==8 bytes, 0==4 bytes) uint8_t used_bits = tc_is(); // Keep track of how many bits will be the effective "page size" // (If the table search terminates early (before used_bits == ts_ps()), // then this will be the effective page size. That is, the number of bits // we or into the physical addr from the virtual addr) shoe.psr.word = 0; desc_addr = -1; // address of the descriptor (-1 -> register) /* We'll keep shifting logical_addr such that its most significant bits are the next ti-index */ uint32_t logical_addr = _logical_addr << used_bits; // TODO: Check limit here // If root descriptor is invalid, throw a bus error if (rp_dt(rootp) == 0) { shoe.psr.bits.b = 1; // bus error shoe.psr.bits.n = 0; return desc_addr; } // desc is a page descriptor, skip right ahead to search_done: if (rp_dt(rootp) == 1) goto search_done; for (i=0; i < 4; i++) { // (the condition is unnecessary - just leaving it in for clarity) // desc must be a table descriptor here const uint8_t ti = tc_ti(i); used_bits += ti; // TODO: do the limit check here // Find the index into our current i-level table const uint32_t index = logical_addr >> (32-ti); logical_addr <<= ti; // load the child descriptor if (_logical_addr == 0) printf("Loading descriptor s=%llu from addr=0x%08x\n", desc_dt(desc, desc_size) & 1, (uint32_t)desc_table_addr(desc)); const uint32_t table_base_addr = desc_table_addr(desc); const uint8_t s = desc_dt(desc, desc_size) & 1; // desc = pget(table_base_addr + (4 << s)*index, (4 << s)); get_desc(table_base_addr + (4 << s)*index, (4 << s)); desc_size = s; // Desc may be a table descriptor, page descriptor, or indirect descriptor const uint8_t dt = desc_dt(desc, desc_size); if (_logical_addr == 0) printf("i=%u desc = 0x%llx dt=%u\n", i, desc, dt); // If this descriptor is invalid, throw a bus error if (dt == 0) { shoe.psr.bits.i = 1; // invalid assert(desc_level <= 7); shoe.psr.bits.n = desc_level; return desc_addr; } if (dt == 1) { // TODO: do a limit check here goto search_done; // it's a page descriptor } else if ((i==3) || (tc_ti(i+1)==0)) { desc_size = desc_dt(desc, s) & 1; /* Otherwise, if this is a leaf in the tree, it's an indirect descriptor. The size of the page descriptor is indicated by DT in the indirect descriptor. (or is it???) */ //desc = pget(desc & 0xfffffff0, (4 << desc_size)); get_desc(desc & 0xfffffff0, (4 << desc_size)); // I think it's possible for an indirect descriptor to point to an invalid descriptor... if (desc_dt(desc, desc_size) == 0) { shoe.psr.bits.i = 1; // invalid assert(desc_level <= 7); shoe.psr.bits.n = desc_level; return desc_addr; } goto search_done; } // Now it must be a table descriptor // TODO: set the U (used) bit in this table descriptor wp |= desc_wp(desc, desc_size); // or in the wp flag for this table descriptor } // never get here assert(!"translate_logical_addr: never get here"); search_done: // Desc must be a page descriptor // NOTE: The limit checks have been done already // TODO: check U (used) bit wp |= desc_wp(desc, desc_size); // or in the wp flag for this page descriptor shoe.psr.bits.w = wp; if (desc & (desc_size ? desc_m_long : desc_m_short)) shoe.psr.bits.m = 1; assert(desc_level <= 7); shoe.psr.bits.n = desc_level; return desc_addr; } void inst_mc68851_ptest(uint16_t ext){ verify_supervisor(); ~decompose(shoe.op, 1111 0000 00 MMMMMM); ~decompose(ext, 100 LLL R AAAA FFFFF); // Erata in 68kPRM - F is 6 bits, and A is 3 assert(tc_enable()); // XXX: Throws some exception if tc_enable isn't set assert(tc_fcl() == 0); // XXX: I can't handle function code lookups, and I don't want to assert(L == 7); // XXX: Not currently handling searching to a particular level // Find the function code uint8_t fc; if (F>>4) // Function code is the low 4 bits of F fc = F & 0xf; else if ((F >> 3) == 1) // Function code is in shoe.d[F & 7] fc = shoe.d[F & 7] & 0xf; else if (F == 1) // Function code is SFC fc = shoe.sfc; else if (F == 0) // Function code is DFC fc = shoe.dfc; else assert(!"ptest: unknown FC bits in instruction"); // Pick a root pointer based on the function code uint64_t rootp; if (fc == 1) rootp = shoe.crp; else if (fc == 5) rootp = shoe.srp; else { printf("ptest: I can't handle this FC: %u pc=0x%08x\n", fc, shoe.orig_pc); assert(!"ptest: I can't handle this FC"); } call_ea_addr(M); const int64_t desc_addr = ptest_search(shoe.dat, rootp); if ((desc_addr >= 0) && (A >> 3)) { shoe.a[A & 7] = (uint32_t)desc_addr; } // printf("%s: Error, not implemented!\n", __func__); } void dis_mc68851_prestore() { sprintf(dis.str, "prestore"); } void dis_mc68851_psave() { sprintf(dis.str, "psave"); } void dis_mc68851_pbcc() { sprintf(dis.str, "pbcc"); } void dis_mc68851_pdbcc(uint16_t cond) { sprintf(dis.str, "pdbcc"); } void dis_mc68851_ptrapcc(uint16_t cond) { sprintf(dis.str, "ptrapcc"); } void dis_mc68851_pscc(uint16_t cond) { sprintf(dis.str, "pscc"); } void dis_mc68851_pload(uint16_t ext) { sprintf(dis.str, "pload"); } void dis_mc68851_pvalid(uint16_t ext) { sprintf(dis.str, "pvalid"); } void dis_mc68851_pflush(uint16_t ext) { sprintf(dis.str, "pflush"); } void dis_mc68851_pmove(uint16_t ext) { ~decompose(dis_op, 1111 000 000 MMMMMM); ~decompose(ext, fff ppp w 0000 nnn 00); // instruction format #1 if (f == ~b(010)) { const uint8_t sizes[8] = {4, 8, 8, 8, 1, 1, 1, 2}; char *names[8] = { "tc", "drp", "srp", "crp", "cal", "val", "scc", "ac" }; if (w) sprintf(dis.str, "pmove %s,%s", names[p], decode_ea_rw(M, sizes[p])); else sprintf(dis.str, "pmove %s,%s", decode_ea_rw(M, sizes[p]), names[p]); return ; } else if (f == ~b(011)) { char *names[8] = {"psr" , "pcsr", "?", "?", "?", "?", "?", "?"}; if (w) sprintf(dis.str, "pmove %s,%s", names[p], decode_ea_rw(M, 2)); else sprintf(dis.str, "pmove %s,%s", decode_ea_rw(M, 2), names[p]); return ; } // TODO: implement instruction formats 2 and 3 (for BAD/BAC, etc.) sprintf(dis.str, "pmove ???"); } void dis_mc68851_ptest(uint16_t ext) { ~decompose(dis_op, 1111 0000 00 MMMMMM); ~decompose(ext, 100 LLL R AAAA FFFFF); // Erata in 68kPRM - F is 6 bits, and A is 3 if (A >> 3) sprintf(dis.str, "ptest%c 0x%x,%s,%u,a%u", "wr"[R], F, decode_ea_addr(M), L, A & 7); else sprintf(dis.str, "ptest%c 0x%x,%s,%u", "wr"[R], F, decode_ea_addr(M), L); } void dis_mc68851_pflushr(uint16_t ext) { sprintf(dis.str, "pflushr"); }