/* * 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 //#include // void ring_print(const char *str); // extern char *ring_tmp; #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) // 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);} #define set_sr_mask(m) {shoe.sr &= (~(7<<8)); shoe.sr |= ((((uint16_t)(m))&7) << 8);} // 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) (chop(shoe.dat, (s))==0) // alloc_pool.c typedef struct _alloc_pool_t { struct _alloc_pool_t *prev, *next; uint32_t size, magic; } alloc_pool_t; void* p_alloc(alloc_pool_t *pool, uint64_t size); void* p_realloc(void *ptr, uint64_t size); void p_free(void *ptr); void p_free_pool(alloc_pool_t *pool); alloc_pool_t* p_new_pool(void); typedef struct dbg_breakpoint_t { struct dbg_breakpoint_t *next; uint32_t addr; uint64_t num; } dbg_breakpoint_t; typedef struct { // EditLine *el; uint8_t mode; uint8_t ignore_interrupts; uint8_t connected; uint64_t breakpoint_counter; dbg_breakpoint_t *breakpoints; } debugger_state_t; 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, ddrb, ddra, sr, acr, pcr; // uint8_t rega, regb; uint16_t t1c, t2c, t1l; uint8_t rega_input, regb_input; uint8_t rega_output, regb_output; long double t1_last_set, t2_last_set; } via_state_t; #define PRAM_READ 1 #define PRAM_WRITE 2 typedef struct { uint8_t data[256]; uint8_t last_bits; // FSM uint8_t command[8]; uint8_t byte, mode, command_i, bit_i; } pram_state_t; void init_via_state(); 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; 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<<8) // 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; // -- 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; _Bool abort; _Bool 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 _Bool logical_is_write; // <- boolean: true iff the operation is logical_set() uint8_t logical_fc; // logical function code // -- PMMU caching structures --- #define PMMU_CACHE_KEY_BITS 10 #define PMMU_CACHE_SIZE (1<> 28]() #define pset(addr, s, val) {shoe.physical_addr=(addr); shoe.physical_size=(s); shoe.physical_dat=(val); physical_set();} #define physical_get() physical_get_jump_table[shoe.physical_addr >> 28]() #define pget(addr, s) ({shoe.physical_addr=(addr); shoe.physical_size=(s); physical_get(); shoe.physical_dat;}) void 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 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) \ } typedef void (*_ea_func) (void); extern const _ea_func ea_read_jump_table[64]; extern const _ea_func ea_read_commit_jump_table[64]; extern const _ea_func ea_write_jump_table[64]; extern const _ea_func ea_addr_jump_table[64]; #define ea_read() ea_read_jump_table[shoe.mr]() #define ea_read_commit() ea_read_commit_jump_table[shoe.mr]() #define ea_write() ea_write_jump_table[shoe.mr]() #define ea_addr() ea_addr_jump_table[shoe.mr]() #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++; \ } // 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); 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 via_raise_interrupt(uint8_t vianum, uint8_t ifr_bit); void process_pending_interrupt(); void via_read_raw(); void via_write_raw(); 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); // debug_server.c void *debug_cpu_thread (void *arg); #endif // _SHOEBILL_H