/* * 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. */ #ifndef _SHOEBILL_H #define _SHOEBILL_H #include #include #include #include #include "coff.h" // -- Global constants -- // bit manipulation #define bitchop(v, s) ({const uint32_t _v = (v), _s = 32 - (s); (_v << _s) >> _s;}) // #define bitchop(v, s) ((v) & (0xffffffff>>(32-(s)))) #define bitchop_64(v, s) ({const uint64_t _v = (v); const uint32_t _s = 64 - (s); (_v << _s) >> _s;}) // #define bitchop_64(v, s) ((v) & (0xffffffffffffffff>>(64-(s)))) #define chop(v, s) bitchop_64((v), (s)*8) #define mib(v, s) (((v)>>((s)*8-1))&1) #define lrot32(v, r) (uint32_t)(((((uint64_t)(v))<<(r)) | (((uint64_t)(v))>>(32-(r))))) #define rrot32(v, r) lrot32((v), 32-(r)) // set register #define set_reg__(reg, val, s) do { \ const uint32_t mask_v=(0xffffffff)>>(8*(4-(s))), mask_r=~mask_v; \ (reg) = ((reg)&mask_r) | ((val)&mask_v);\ } while (0) #define get_reg__(reg, s) chop(reg, s) #define get_d(n,s) get_reg__(shoe.d[n], s) #define get_a(n,s) get_reg__(shoe.a[n], s) #define set_d(n,val,s) set_reg__(shoe.d[n], val, s) // #define set_a(n,val,s) set_reg__(shoe.a[n], val, s) // address registers should always be set with sz==4 // sr masks #define sr_c() (shoe.sr&1) #define sr_v() ((shoe.sr>>1)&1) #define sr_z() ((shoe.sr>>2)&1) #define sr_n() ((shoe.sr>>3)&1) #define sr_x() ((shoe.sr>>4)&1) #define sr_mask() ((shoe.sr>>8)&7) #define sr_m() ((shoe.sr>>12)&1) #define sr_s() ((shoe.sr>>13)&1) #define sr_t0() ((shoe.sr>>14)&1) #define sr_t1() ((shoe.sr>>15)&1) // a7 can actually point to isp, msp, or usp, depending on bits in the status register. // So every time we modify those bits, save a7 to the correct internal register. #define make_stack_pointers_valid() { \ if (sr_s() && sr_m()) \ shoe.msp = shoe.a[7]; \ else if (sr_s()) \ shoe.isp = shoe.a[7]; \ else \ shoe.usp = shoe.a[7]; \ } // Load the correct stack pointer into a7 based on bits in sr #define load_stack_pointer() { \ if (sr_s() && sr_m()) \ shoe.a[7] = shoe.msp; \ else if (sr_s()) \ shoe.a[7] = shoe.isp; \ else \ shoe.a[7] = shoe.usp; \ } // set the status register, swapping a7 if necessary #define set_sr(newsr) { \ make_stack_pointers_valid(); \ shoe.sr = newsr & 0xf71f; \ load_stack_pointer(); \ } #define set_sr_c(b) {shoe.sr &= (~(1<<0)); shoe.sr |= (((b)!=0)<<0);} #define set_sr_v(b) {shoe.sr &= (~(1<<1)); shoe.sr |= (((b)!=0)<<1);} #define set_sr_z(b) {shoe.sr &= (~(1<<2)); shoe.sr |= (((b)!=0)<<2);} #define set_sr_n(b) {shoe.sr &= (~(1<<3)); shoe.sr |= (((b)!=0)<<3);} #define set_sr_x(b) {shoe.sr &= (~(1<<4)); shoe.sr |= (((b)!=0)<<4);} // Be careful when setting these bits #define set_sr_m(b) {make_stack_pointers_valid(); shoe.sr &= (~(1<<12)); shoe.sr |= (((b)!=0)<<12); load_stack_pointer();} #define set_sr_s(b) {make_stack_pointers_valid(); shoe.sr &= (~(1<<13)); shoe.sr |= (((b)!=0)<<13); load_stack_pointer();} #define set_sr_t0(b) {shoe.sr &= (~(1<<14)); shoe.sr |= (((b)!=0)<<14);} #define set_sr_t1(b) {shoe.sr &= (~(1<<15)); shoe.sr |= (((b)!=0)<<15);} // MMU #define tc_enable() (shoe.tc >> 31) #define tc_sre() ((shoe.tc >> 25) & 1) #define tc_fcl() ((shoe.tc >> 24) & 1) #define tc_ps() ((shoe.tc >> 20) & 0xf) #define tc_is() ((shoe.tc >> 16) & 0xf) #define tc_tia() ((shoe.tc >> 12) & 0xf) #define tc_tib() ((shoe.tc >> 8) & 0xf) #define tc_tic() ((shoe.tc >> 4) & 0xf) #define tc_tid() (shoe.tc & 0xf) #define tc_ti(n) ((shoe.tc >> ((3-(n))*4)) & 0xf) #define rp_lu(x) ((uint32_t)(((x) >> 63) & 1)) #define rp_limit(x) ((uint32_t)(((x) >> 48) & 0x7fff)) #define rp_sg(x) ((uint32_t)(((x) >> 41) & 1)) #define rp_dt(x) ((uint32_t)(((x) >> 32) & 3)) #define rp_addr(x) ((uint32_t)(((x) >> 0) & 0xfffffff0)) // misc #define ea_n(s) ((shoe.dat>>((s)*8-1))&1) #define ea_z(s) ((shoe.dat&((0xffffffff)>>(8*(4-(s)))))==0) typedef struct dbg_breakpoint_t { struct dbg_breakpoint_t *next; uint32_t addr; uint64_t num; } dbg_breakpoint_t; struct dbg_state_t { EditLine *el; uint8_t running; uint64_t breakpoint_counter; dbg_breakpoint_t *breakpoints; }; extern struct dbg_state_t dbg_state; typedef enum { adb_talk, adb_listen, adb_reset, adb_flush } adb_command_type_t; typedef struct { adb_command_type_t command_type; uint8_t command_byte; // The command byte passed in during state 0 uint8_t command_device_id; // the device id in the command byte uint8_t command_reg; // the register in the command byte uint8_t service_request, timeout; uint16_t pending_service_requests; uint8_t pending_poll; uint8_t poll; // a poll is in progress uint8_t state; // State machine state (0 => host send command, 1 => even byte, 2 => odd byte, 3 => idle uint8_t data_i, data_len; uint8_t data[8]; pthread_mutex_t lock; } adb_state_t; typedef struct { uint8_t ifr, ier, rega, regb, ddrb, ddra, sr; } via_state_t; typedef struct { uint8_t scsi_id; uint32_t num_blocks, block_size; FILE *f; const char *image_path; } scsi_device_t; #define KEYBOARD_STATE_MAX_KEYS 128 typedef struct { struct { uint8_t code_a, code_b; } keys[KEYBOARD_STATE_MAX_KEYS]; int down_modifiers; // Modifiers that we've already told the OS are down (shift, ctrl, uint32_t key_i; uint8_t last_modifier_mask; } keyboard_state_t; typedef struct { int32_t old_x, old_y; int32_t delta_x, delta_y; uint8_t button_down; uint8_t changed; } mouse_state_t; typedef struct { uint8_t *buf_base; uint32_t buf_size; uint32_t h_offset; // offset in bytes for each horizontal line uint8_t vsync; // unit8_t via_interrupt_flag; uint8_t depth; uint8_t clut[256 * 3]; uint32_t clut_idx; } video_state_t; typedef struct { // lsb==phase0, msb==L7 uint8_t latch; // Registers uint8_t data, status, mode, handshake; } iwm_state_t; typedef struct { uint32_t (*read_func)(uint32_t, uint32_t, uint8_t); void (*write_func)(uint32_t, uint32_t, uint32_t, uint8_t); void *ctx; uint8_t slotnum, connected, interrupts_enabled; int32_t glut_window_id; long double interrupt_rate, last_fired; } nubus_card_t; typedef struct { uint32_t logical_value : 24; // At most the high 24 bits of the logical address uint32_t used_bits : 5; uint32_t wp : 1; // whether the page is write protected uint32_t modified : 1; // whether the page has been modified uint32_t unused1 : 1; uint32_t unused2 : 8; uint32_t physical_addr : 24; } pmmu_cache_entry_t; typedef struct { uint64_t emu_start_time; struct timeval last_60hz_tick; // for via1 ca1 } via_clock_t; typedef struct { #define SHOEBILL_STATE_STOPPED (1<<9) #define SHOEBILL_STATE_SWITCH_MODE (1<<10) // bits 0-6 are CPU interrupt priorities // bit 8 indicates that STOP was called volatile uint32_t cpu_thread_notifications; pthread_mutex_t cpu_thread_lock; pthread_mutex_t via_clock_thread_lock; pthread_mutex_t cpu_freeze_lock; #define CPU_MODE_FAST 0 #define CPU_MODE_DEBUG 1 #define CPU_MODE_STEPI 2 #define CPU_MODE_STEPI_COMPLETE 3 #define CPU_MODE_FREEZE 4 uint32_t cpu_mode; // -- PMMU caching structures --- struct { pmmu_cache_entry_t entry[512]; uint8_t valid_map[512 / 8]; } pmmu_cache[2]; // -- Assorted CPU state variables -- uint16_t op; // the first word of the instruction we're currently running uint16_t orig_sr; // the sr before we began executing the instruction uint32_t orig_pc; // the address of the instruction we're currently running uint16_t exception; uint16_t abort; uint32_t suppress_exceptions; // -- Physical memory -- uint8_t *physical_mem_base; uint32_t physical_mem_size; uint8_t *physical_rom_base; uint32_t physical_rom_size; uint32_t physical_size; // <- Size of transfer uint32_t logical_size; // <- Size of transfer uint32_t physical_addr; // <- Address for physical reads/writes uint32_t logical_addr; // <- Address for logical reads/writes uint64_t physical_dat; // <- Data for physical fetches is put/stored here uint64_t logical_dat; // <- Data for logical fetches is put/stored here uint8_t logical_is_write; // <- boolean: true iff the operation is logical_set() uint8_t logical_fc; // logical function code // -- Interrupts/VIA chips -- // uint8_t stopped; // whether STOP was called // uint8_t pending_interrupt; // (0 -> no pending interrupt, >0 -> interrupt priority (autovector)) via_state_t via[2]; adb_state_t adb; keyboard_state_t key; mouse_state_t mouse; iwm_state_t iwm; nubus_card_t slots[16]; // video_state_t video; // -- Registers -- uint32_t d[8]; uint32_t a[8]; uint32_t pc; uint32_t vbr; // vector base register uint32_t sfc; // source function code uint32_t dfc; // destination function code uint32_t cacr; // cache control register uint32_t usp; // user stack pointer uint32_t isp; // interrupt stack pointer uint32_t msp; // master stack pointer uint16_t sr; // status register (use a macro to modify sr!) // 68851 registers uint64_t crp, srp, drp; // user/supervisor/DMA root pointers uint32_t tc; // translation control uint16_t pcsr; // PMMU cache status uint16_t ac; // access control uint16_t bad[8]; // breakpoint acknowledge data registers uint16_t bac[8]; // breakpoint acknowledge control registers uint8_t cal; // current access level uint8_t val; // validate access level uint8_t scc; // stack change control union { uint16_t word; struct { uint16_t n : 3; // number-of-levels uint16_t unused : 4; // (zeroed out) uint16_t c : 1; // globally shared uint16_t g : 1; // gate uint16_t m : 1; // modified uint16_t i : 1; // invalid uint16_t w : 1; // write-protected uint16_t a : 1; // access level violation uint16_t s : 1; // supervisor-only uint16_t l : 1; // limit violation uint16_t b : 1; // bus error } bits; } psr; // FPU registers uint32_t fpiar; // FPU iaddr union { // fpcr, fpu control register struct { // Mode control byte uint16_t mc_zero : 4; // zero/dummy uint16_t mc_rnd : 2; // rounding mode uint16_t mc_prec : 2; // rounding precision // Exception enable byte uint16_t ee_inex1 : 1; // inexact decimal input uint16_t ee_inex2 : 1; // inxact operation uint16_t ee_dz : 1; // divide by zero uint16_t ee_unfl : 1; // underflow uint16_t ee_ovfl : 1; // overflow uint16_t ee_operr : 1; // operand error uint16_t ee_snan : 1; // signalling not a number uint16_t ee_bsun : 1; // branch/set on unordered } b; uint16_t raw; } fpcr; union { // fpsr, fpu status register struct { // Accrued exception byte uint32_t dummy1 : 3; // dummy/zero uint32_t ae_inex : 1; // inexact uint32_t ae_dz : 1; // divide by zero uint32_t ae_unfl : 1; // underflow uint32_t ae_ovfl : 1; // overflow uint32_t ae_iop : 1; // invalid operation // Exception status byte uint32_t es_inex1 : 1; // inexact decimal input uint32_t es_inex2 : 1; // inxact operation uint32_t es_dz : 1; // divide by zero uint32_t es_unfl : 1; // underflow uint32_t es_ovfl : 1; // overflow uint32_t es_operr : 1; // operand error uint32_t es_snan : 1; // signalling not a number uint32_t es_bsun : 1; // branch/set on unordered // Quotient byte uint32_t qu_quotient : 7; uint32_t qu_s : 1; // Condition code byte uint32_t cc_nan : 1; // not a number uint32_t cc_i : 1; // infinity uint32_t cc_z : 1; // zero uint32_t cc_n : 1; // negative uint32_t dummy2 : 4; // dummy/zero } b; uint32_t raw; } fpsr; long double fp[8]; // 80 bit floating point general registers // -- EA state -- uint32_t uncommitted_ea_read_pc; // set by ea_read(). It's the PC that ea_read_commit will set. uint64_t dat; // the raw input/output for the transaction uint32_t extended_addr; // EA returned by ea_decode_extended() uint32_t extended_len; // number of instruction bytes used by ea_decode_extended() uint8_t sz; // the size of the EA transaction uint8_t mr; // a 6-bit mode/reg pair via_clock_t via_clocks; uint32_t dbg; struct timeval start_time; // when the emulator started (for computing timer interrupts) uint64_t total_ticks; // how many 60hz ticks have been generated coff_file *coff; // Data/symbols from the unix kernel coff_file *launch; // FIXME: delete me: coff symbols from aux 1.1.1 launch binary scsi_device_t scsi_devices[8]; // SCSI devices } global_shoebill_context_t; extern global_shoebill_context_t shoe; // declared in cpu.c // fpu.c functions void inst_fpu_decode(void); void dis_fpu_decode(void); void fpu_setup_jump_table(); // cpu.c fuctions void cpu_step (void); inline void inst_decode (void); // exception.c functions void throw_bus_error(uint32_t addr, uint8_t is_write); void throw_long_bus_error(uint32_t addr, uint8_t is_write); void throw_address_error(); void throw_illegal_instruction(); void throw_privilege_violation(); void throw_divide_by_zero(); void throw_frame_two (uint16_t sr, uint32_t next_pc, uint32_t vector_num, uint32_t orig_pc); // mem.c functions void inline physical_get (void); #define pget(addr, s) ({shoe.physical_addr=(addr); shoe.physical_size=(s); physical_get(); shoe.physical_dat;}) void inline logical_get (void); #define lget_fc(addr, s, fc) ({ \ shoe.logical_addr=(addr); \ shoe.logical_size=(s); \ shoe.logical_fc = (fc); \ logical_get(); \ shoe.logical_dat; \ }) #define lget(addr, s) ({ \ shoe.logical_addr=(addr); \ shoe.logical_size=(s); \ shoe.logical_fc = (sr_s() ? 5 : 1); \ logical_get(); \ shoe.logical_dat; \ }) void inline physical_set (void); #define pset(addr, s, val) {shoe.physical_addr=(addr); shoe.physical_size=(s); shoe.physical_dat=(val); physical_set();} void inline logical_set (void); #define lset_fc(addr, s, val, fc) {\ shoe.logical_addr=(addr); \ shoe.logical_size=(s); \ shoe.logical_dat=(val); \ shoe.logical_fc = (fc); \ logical_set();\ } #define lset(addr, s, val) { \ lset_fc((addr), (s), (val), sr_s() ? 5 : 1) \ } void ea_read(); void ea_read_commit(); void ea_write(); void ea_addr(); #define call_ea_read(M, s) {shoe.mr=(M);shoe.sz=(s);ea_read();if (shoe.abort) return;} #define call_ea_write(M, s) {shoe.mr=(M);shoe.sz=(s);ea_write();if (shoe.abort) return;} #define call_ea_read_commit(M, s) {shoe.mr=(M);shoe.sz=(s);ea_read_commit();if (shoe.abort) return;} #define call_ea_addr(M) {shoe.mr=(M);ea_addr();if (shoe.abort) return;} #define push_a7(_dat, _sz) {shoe.a[7]-=(_sz);lset(shoe.a[7], (_sz), (_dat));} // 68851 MMU stuff #define desc_dt(d,s) (((d) >> (32 * (s))) & 3) #define desc_table_addr(d) ((uint32_t)((d) & 0xFFFFFFF0)) #define desc_page_addr(d) ((uint32_t)((d) & 0xffffff00)) #define desc_wp(d,s) ((((d) >> (32 * (s))) >> 2) & 1) #define desc_m(d,s) ((((d) >> (32 * (s))) >> 4) & 1) #define desc_m_long (((uint64_t)1) << 36) #define desc_m_short (((uint64_t)1) << 4) #define get_desc(_addr, _size) { \ desc = pget((_addr), (_size)); \ desc_addr = (_addr); \ desc_level++; \ } // if (shoe.dbg) \ // printf("desc_addr *0x%08x = 0x%llx\n", (uint32_t)(_addr), desc); \ // } // dis.c functions void disassemble_inst(uint8_t binary[24], uint32_t orig_pc, char *str, uint32_t *instlen); char* decode_ea_rw (uint8_t mr, uint8_t sz); char* decode_ea_addr (uint8_t mr); inline void dis_decode(void); uint16_t dis_next_word (void); char* decode_ea_addr (uint8_t mr); char* decode_ea_rw (uint8_t mr, uint8_t sz); struct dis_t { // static uint8_t binary[24]; // raw instruction (up to 24 bytes) uint32_t orig_pc; // the PC when disassemble_inst() was called // volatile char ea_str_internal[1024]; // data for storing decoded ea strings (ring buffer) uint32_t ea_last_pos_internal; uint32_t pos; // the current computed length of the instruction // return char *str; // the final returned string }; // IWM / floppy uint8_t iwm_dma_read(); void iwm_dma_write(); // ncr5380 (scsi) void scsi_reg_read(); void scsi_reg_write(); uint8_t scsi_dma_read(); uint32_t scsi_dma_read_long(); void scsi_dma_write(uint8_t byte); void scsi_dma_write_long(uint32_t dat); // via1 & via2 (+ CPU interrupts) void check_time(); void via_raise_interrupt(uint8_t vianum, uint8_t ifr_bit); void process_pending_interrupt(); void via_reg_read(); void via_reg_write(); void *via_clock_thread(void *arg); // VIA registers #define VIA_ORB 0 #define VIA_ORA 1 #define VIA_DDRB 2 #define VIA_DDRA 3 #define VIA_T1C_LO 4 #define VIA_T1C_HI 5 #define VIA_T1L_LO 6 #define VIA_T1L_HI 7 #define VIA_T2C_LO 8 #define VIA_T2C_HI 9 #define VIA_SR 10 #define VIA_ACR 11 #define VIA_PCR 12 #define VIA_IFR 13 #define VIA_IER 14 #define VIA_ORA_AUX 15 // IFR interrupt bits #define IFR_CA2 0 #define IFR_CA1 1 #define IFR_SHIFT_REG 2 #define IFR_CB2 3 #define IFR_CB1 4 #define IFR_TIMER1 5 #define IFR_TIMER2 6 #define IFR_IRQ 7 // adb / keyboard / mouse stuff void adb_handle_state_change(uint8_t old_state, uint8_t new_state); void adb_request_service_request(uint8_t id); extern const char *atrap_names[4096]; struct macii_rom_symbols_t { uint32_t addr; const char *name; }; extern const struct macii_rom_symbols_t macii_rom_symbols[]; // Emulated Toby Frame Buffer nubus card void nubus_tfb_init(uint8_t slotnum); uint32_t nubus_tfb_read_func(uint32_t, uint32_t, uint8_t); void nubus_tfb_write_func(uint32_t, uint32_t, uint32_t, uint8_t); // Shoebill Virtual Video Card void nubus_video_init(void *_ctx, uint8_t slotnum, uint16_t width, uint16_t height, uint16_t scanline_width, double refresh_rate); uint32_t nubus_video_read_func(const uint32_t rawaddr, const uint32_t size, const uint8_t slotnum); void nubus_video_write_func(const uint32_t rawaddr, const uint32_t size, const uint32_t data, const uint8_t slotnum); #endif // _SHOEBILL_H