/* * 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 /* * core_api.c stuff */ typedef void (*shoebill_pram_callback_t) (void *param, const uint8_t addr, const uint8_t byte); typedef struct { uint32_t ram_size; const char *rom_path; const char *aux_kernel_path; // almost always "/unix" _Bool aux_verbose : 1; // Whether to boot A/UX in verbose mode _Bool aux_autoconfig : 1; // Whether to run A/UX autoconfig _Bool debug_mode : 1; // Whether to enable hacks that debugger depends on uint16_t root_ctrl, swap_ctrl; uint8_t root_drive, swap_drive; uint8_t root_partition, swap_partition; uint8_t root_cluster; /* Devices at the 7 possible target SCSI ids */ struct { const char *path; } scsi_devices[7]; // scsi id #7 is the initiator (can't be a target) /* Initialize pram[] with initial PRAM data */ uint8_t pram[256]; /* * This callback is called whenever a PRAM byte is changed. * It blocks the CPU, so try to return immediately. */ shoebill_pram_callback_t pram_callback; void *pram_callback_param; char error_msg[8192]; } shoebill_config_t; typedef struct { const uint8_t *buf; uint16_t width, height, scan_width, depth; } shoebill_video_frame_info_t; /* Take a shoebill_config_t structure and configure the global emulator context */ uint32_t shoebill_initialize(shoebill_config_t *params); void shoebill_restart (void); /* Call this after shoebill_initialize() to configure a video card */ uint32_t shoebill_install_video_card(shoebill_config_t *config, uint8_t slotnum, uint16_t width, uint16_t height, double refresh_rate); /* Get a video frame from a particular video card */ shoebill_video_frame_info_t shoebill_get_video_frame(uint8_t slotnum, _Bool just_params); /* Call this after rendering a video frame to send a VBL interrupt */ void shoebill_send_vbl_interrupt(uint8_t slotnum); /* * These keyboard modifier constants match the ones used * in NSEvent shifted right by 16 bits. */ enum { modCapsLock = 1 << 0, modShift = 1 << 1, modControl = 1 << 2, modOption = 1 << 3, modCommand = 1 << 4 }; void shoebill_key(uint8_t down, uint8_t key); void shoebill_key_modifier(uint8_t modifier_mask); void shoebill_mouse_move(int32_t x, int32_t y); void shoebill_mouse_move_delta (int32_t x, int32_t y); void shoebill_mouse_click(uint8_t down); void shoebill_start(); void shoebill_stop(); uint8_t* shoebill_extract_kernel(const char *disk_path, const char *kernel_path, char *error_str, uint32_t *len); /* * Internal shoebill stuff */ // -- 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 */ #define POOL_ALLOC_TYPE 0 #define POOL_CHILD_LINK 1 #define POOL_HEAD 2 typedef struct _alloc_pool_t { struct _alloc_pool_t *prev, *next; union { struct { uint64_t size; } alloc; struct { struct _alloc_pool_t *child; // pointer to the child's HEAD } child_link; struct { struct _alloc_pool_t *parent_link; // pointer to the parent's CHILD_LINK } head; } t; uint32_t type; uint32_t 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(alloc_pool_t *parent_pool); /* * redblack.c */ typedef uint32_t rb_key_t; typedef void* rb_value_t; typedef struct _rb_node { struct _rb_node *left, *right, *parent; rb_key_t key; rb_value_t value; uint8_t is_red : 1; } rb_node; typedef struct { rb_node *root; alloc_pool_t *pool; } rb_tree; rb_tree* rb_new(alloc_pool_t *pool); void rb_free (rb_tree *tree); uint8_t rb_insert (rb_tree *root, rb_key_t key, rb_value_t value, rb_value_t *old_value); uint8_t rb_find (rb_tree *tree, rb_key_t key, rb_value_t *value); uint8_t rb_index (rb_tree *tree, uint32_t index, rb_key_t *key, rb_value_t *value); uint32_t rb_count (rb_tree *tree); /* * coff.c */ typedef struct { char *name; uint32_t value; uint16_t scnum, type; uint8_t sclass, numaux; } coff_symbol; // informed by http://www.delorie.com/djgpp/doc/coff/scnhdr.html typedef struct { char name[8]; uint32_t p_addr; uint32_t v_addr; uint32_t sz; uint32_t data_ptr; uint32_t reloc_ptr; uint32_t line_ptr; uint16_t num_relocs; uint16_t num_lines; uint32_t flags; uint8_t *data; } coff_section; // data for this segment appears in the file, but shouldn't be copied into memory #define coff_copy 0x0010 #define coff_text 0x0020 #define coff_data 0x0040 #define coff_bss 0x0080 typedef struct { uint16_t magic; uint16_t num_sections; uint32_t timestamp; uint32_t symtab_offset; uint32_t num_symbols; uint16_t opt_header_len; uint16_t flags; uint8_t *opt_header; coff_section *sections; rb_tree *func_tree; coff_symbol *symbols; alloc_pool_t *pool; } coff_file; coff_symbol* coff_find_func(coff_file *coff, uint32_t addr); coff_symbol* coff_find_symbol(coff_file *coff, const char *name); coff_file* coff_parse(uint8_t *buf, uint32_t buflen, alloc_pool_t *parent_pool); coff_file* coff_parse_from_path(const char *path, alloc_pool_t *parent_pool); void coff_free(coff_file *coff); uint32_t be2native (uint8_t **dat, uint32_t bytes); void print_coff_info(coff_file *coff); 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; shoebill_pram_callback_t callback; void *callback_param; } pram_state_t; void init_via_state (uint8_t pram_data[256], shoebill_pram_callback_t callback, void *callback_param); void init_adb_state(); void init_scsi_bus_state(); void init_iwm_state(); void reset_via_state(); void reset_adb_state(); void reset_scsi_bus_state(); void reset_iwm_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; enum scsi_bus_phase { BUS_FREE = 0, ARBITRATION, SELECTION, RESELECTION, COMMAND, DATA_OUT, DATA_IN, STATUS, MESSAGE_IN, MESSAGE_OUT }; typedef struct { // Phase enum scsi_bus_phase phase; // Scsi bus signals uint8_t init_bsy:1; // BSY, driven by initiator uint8_t target_bsy:1; // BSY, driven by target uint8_t sel:1; // SEL, driven by both target and initiator uint8_t rst:1; // RST, driven by both target and initiator uint8_t cd:1; // C/D (control or data), driven by target uint8_t io:1; // I/O, driven by target uint8_t ack:1; // ACK, driven by initiator uint8_t msg:1; // MSG, driven by target uint8_t atn:1; // ATN, driven by initiator uint8_t req:1; // REQ, driven by target uint8_t data; // DB0-7, data lines, driven by both target and initiator // NCR 5380 registers uint8_t initiator_command; uint8_t mode; uint8_t target_command; uint8_t select_enable; // probably not implementing this... // Arbitration state uint8_t init_id; // initiator ID (as a bit mask) (usually 0x80) // Selection state uint8_t target_id; // target ID (as an int [0, 7]) // transfer buffers uint8_t buf[512 * 256]; uint32_t bufi; uint32_t in_len, in_i; uint32_t out_len, out_i; uint32_t write_offset; uint8_t status_byte; uint8_t message_byte; // only one-byte messages supported for now // hack uint8_t dma_send_written; // Gets set whenever register 5 (start_dma_send) is written to, and cleared randomly. // This is because aux 1.1.1 sends an extra byte after sending the write command, and that's not // part of the write data. start_dma_send will be written when the data is actually starting. uint8_t sent_status_byte_via_reg0; // Gets set when the status byte is red via register 0. // This lets us know it's safe to switch to the MESSAGE_IN phase } scsi_bus_state_t; typedef struct { uint8_t r, g, b, a; } video_ctx_color_t; typedef struct { video_ctx_color_t *direct_buf, *clut; uint8_t *indexed_buf, *rom; uint8_t *cur_buf; uint32_t pixels; uint16_t width, height, scanline_width; uint16_t depth, clut_idx; double refresh_rate; } shoebill_card_video_t; typedef struct { uint8_t *frame_buffer; } shoebill_card_tfb_t; typedef struct { // Doesn't exist yet } shoebill_card_ethernet_t; typedef enum { card_none = 0, // Empty slot card_toby_frame_buffer, // Original Macintosh II video card card_shoebill_video, // Fancy 21st-century Shoebill video card card_shoebill_ethernet // FIXME: doesn't exist yet } card_names_t; typedef struct { uint32_t (*read_func)(uint32_t, uint32_t, uint8_t); void (*write_func)(uint32_t, uint32_t, uint32_t, uint8_t); uint8_t slotnum; _Bool connected; _Bool interrupts_enabled; long double interrupt_rate, last_fired; // FIXME: probably don't need these? void *ctx; card_names_t card_type; } 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 { _Bool running; #define SHOEBILL_STATE_STOPPED (1 << 8) #define SHOEBILL_STATE_RETURN (1 << 9) // bits 0-6 are CPU interrupt priorities // bit 8 indicates that STOP was called volatile uint32_t cpu_thread_notifications; volatile uint32_t via_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); #endif // _SHOEBILL_H