/* * 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 "shoebill.h" #define SSW_IS_READ (1<<6) #define SSW_DF (1<<8) // throw the long-format (format 0xb) buss error. Mac II ROM expects to see this format for nubus bus errors. // FIXME: nearly all the fields here are bogus void throw_long_bus_error(uint32_t addr, uint8_t is_write) { if (shoe.suppress_exceptions) { shoe.abort = 1; return ; } // Save this value now, because lset() calls will reset it const uint8_t fc = shoe.logical_fc; //printf("throw_long_bus_error(): I'm throwing a LONG bus error (at pc = 0x%08x)!\n", shoe.orig_pc); // set supervisor bit set_sr_s(1); // inhibit tracing set_sr_t0(0); set_sr_t1(0); // compute vector offset const uint32_t vector_num = 2; const uint32_t vector_offset = vector_num * 4; // fetch vector handler address const uint32_t vector_addr = lget(shoe.vbr + vector_offset, 4); //printf("throw_long_bus_error(): shoe.vbr=0x%08x, vector_addr=0x%08x, offending addr=0x%08x, shoe.op=0x%04x\n", shoe.vbr, vector_addr, addr, shoe.op); assert(!shoe.abort); // FIXME: I can't handle another exception here const uint16_t ssw = SSW_DF | (is_write ? 0 : SSW_IS_READ) | fc; // Note: We're pushing frame format 0xA push_a7(0, 4); // internal registers, 18 words push_a7(0, 4); push_a7(0, 4); push_a7(0, 4); push_a7(0, 4); push_a7(0, 4); push_a7(0, 4); push_a7(0, 4); push_a7(0, 4); push_a7(0x0000, 2); // version + internal information push_a7(0, 2); // internal registers, 3 words push_a7(0, 4); push_a7(0, 4); // data input buffer push_a7(0, 4); // Internal register, 2 words push_a7(0, 4); // Stage B addr push_a7(0, 4); // Internal register, 4 words push_a7(0, 4); // push_a7(0, 4); // data output buffer push_a7(0, 4); // internal registers 3 and 2 push_a7(addr, 4); // data cycle fault address push_a7(0, 4); // instruction pipe stage B and C push_a7(ssw, 2); // special status word push_a7(0, 2); // internal register 1 push_a7(0xB000 | vector_offset, 2); // format word push_a7(shoe.orig_pc, 4); // PC for the current instruction push_a7(shoe.orig_sr, 2); // original status register shoe.pc = vector_addr; assert(!shoe.abort); // FIXME: again, can't handle an exception here shoe.abort = 1; } void throw_bus_error(uint32_t addr, uint8_t is_write) { if (shoe.suppress_exceptions) { shoe.abort = 1; return ; } // Save this value now, because lset() calls will reset it const uint8_t fc = shoe.logical_fc; //dbg_state.running = 0; //printf("throw_bus_error(): I'm throwing a bus error (at pc = 0x%08x)!\n", shoe.orig_pc); // set supervisor bit set_sr_s(1); // inhibit tracing set_sr_t0(0); set_sr_t1(0); // compute vector offset const uint32_t vector_num = 2; const uint32_t vector_offset = vector_num * 4; // fetch vector handler address const uint32_t vector_addr = lget(shoe.vbr + vector_offset, 4); //printf("throw_bus_error(): shoe.vbr=0x%08x, vector_addr=0x%08x, offending addr=0x%08x, shoe.op=0x%04x, a7=0x%08x", shoe.vbr, vector_addr, addr, shoe.op, shoe.a[7]); assert(!shoe.abort); // FIXME: I can't handle another exception here const uint16_t ssw = SSW_DF | // the cpu will rerun the memory access (is_write ? 0 : SSW_IS_READ) | // read or write fc; // a/ux 3.0.1 cares about this - the address space //printf(" fc=%u\n", shoe.logical_fc); // Note: We're pushing frame format 0xA push_a7(0, 4); // internal registers 5 and 4 push_a7(0, 4); // data output buffer push_a7(0, 4); // internal registers 3 and 2 push_a7(addr, 4); // data cycle fault address push_a7(0, 4); // instruction pipe stage B and C push_a7(ssw, 2); // special status word push_a7(0, 2); // internal register 1 push_a7(0xA000 | vector_offset, 2); // format word push_a7(shoe.orig_pc, 4); // PC for the current instruction push_a7(shoe.orig_sr, 2); // original status register shoe.pc = vector_addr; assert(!shoe.abort); // FIXME: again, can't handle an exception here shoe.abort = 1; } void throw_address_error() { printf("throw_address_error(): I'm throwing an address error!\n"); assert(!"address error"); shoe.abort = 1; } static void throw_frame_zero(uint16_t sr, uint32_t pc, uint16_t vector_num) { // set supervisor bit set_sr_s(1); // inhibit tracing set_sr_t0(0); set_sr_t1(0); const uint32_t vector_addr = lget(shoe.vbr + vector_num*4, 4); assert(!shoe.abort); // FIXME: I can't handle another exception here push_a7(vector_num*4, 2); push_a7(pc, 4); push_a7(sr, 2); shoe.pc = vector_addr; shoe.abort = 1; } void throw_frame_two (uint16_t sr, uint32_t next_pc, uint32_t vector_num, uint32_t orig_pc) { set_sr_s(1); // inhibit tracing set_sr_t0(0); set_sr_t1(0); const uint32_t vector_addr = lget(shoe.vbr + vector_num*4, 4); assert(!shoe.abort); // FIXME: can't handle exception here const uint16_t frame_word = 0x2000 | (vector_num*4); push_a7(orig_pc, 4); push_a7(frame_word, 2); push_a7(next_pc, 4); push_a7(sr, 2); shoe.pc = vector_addr; shoe.abort = 1; } void throw_illegal_instruction() { //printf("throw_illegal_instruction(): I'm throwing an illegal instruction exception! (shoe.pc = 0x%08x, op=0x%04x, a7=0x%08x)\n", shoe.orig_pc, shoe.op, shoe.a[7]); if ((shoe.op != 0xf010) && ((shoe.op >> 12) != 0xa)) //assert(!"illegal"); dbg_state.running = 0; // fetch vector number const uint32_t vector_num = ((shoe.op>>12) == 0xa) ? 10 : (((shoe.op>>12) == 0xf) ? 11 : 4); throw_frame_zero(shoe.orig_sr, shoe.orig_pc, vector_num); /*if ((shoe.op >> 12) == 0xa) { printf("Atrap: %s\n", atrap_names[shoe.op & 0xfff]?atrap_names[shoe.op & 0xfff]:"???"); } else dbg_state.running = 0;*/ shoe.abort = 1; } void throw_privilege_violation() { //printf("throw_privilege_violation(): I'm throwing a privilege violation exception! (shoe.orig_pc = 0x%08x op=0x%04x\n", shoe.orig_pc, shoe.op); throw_frame_zero(shoe.orig_sr, shoe.orig_pc, 8); shoe.abort = 1; } void throw_divide_by_zero() { printf("throw_divide_by_zero(): I'm throwing a divide-by-zero exception!\n"); assert(0); shoe.abort = 1; }