////////////////////////////////////////////////////////////////////// // // // AddressSpace.pas: Common constants and types. // // This contains register addresses, types, and masks common to // // both the Mappy VM core and the Mappy VM user interface. // // // // The contents of this file are subject to the Bottled Light // // Public License Version 1.0 (the "License"); you may not use this // // file except in compliance with the License. You may obtain a // // copy of the License at http://www.bottledlight.com/BLPL/ // // // // Software distributed under the License is distributed on an // // "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or // // implied. See the License for the specific language governing // // rights and limitations under the License. // // // // The Original Code is the Mappy VM User Interface/Core, released // // April 1st, 2003. The Initial Developer of the Original Code is // // Bottled Light, Inc. Portions created by Bottled Light, Inc. are // // Copyright (C) 2001-2003 Bottled Light, Inc. All Rights Reserved. // // // // This file is common to both the Mappy VM user interface and the // // Mappy VM core projects, and is considered Original Code for both // // // // Author(s): // // Michael Noland (joat), michael@bottledlight.com // // // // Changelog: // // 1.0: First public release (April 1st, 2003) // // // // Notes: // // Todo: Add networking registers. // // // ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// unit AddressSpace; /////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// interface //////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// type uint8 = byte; int8 = shortint; Puint8 = ^uint8; Pint8 = ^int8; int16 = smallint; uint16 = word; Puint16 = ^uint16; Pint16 = ^int16; int32 = integer; uint32 = longword; Puint32 = ^uint32; Pint32 = ^int32; float = single; float32 = single; float64 = double; Pfloat32 = ^float32; Pfloat64 = ^float64; Pboolean = ^boolean; Puint8Array = ^Tuint8Array; Tuint8Array = array[0..MaxInt - 1] of uint8; Puint16Array = ^Tuint16Array; Tuint16Array = array[0..MaxInt shr 1 - 1] of uint16; ////////////////////////////////////////////////////////////////////// const // Display Control Register (RW) // [0..2]: Video mode (0-5) // [3]: CGB mode? fixme: is this the cart switch? // [4]: Display 2nd framebuffer (modes 4-5) // [5]: Enable access of OAM during H-Blank // [6]: Use 1D sprite mapping // [7]: Enable forced blank (disable rendering) // [8]: Enable BG0 // [9]: Enable BG1 // [10]: Enable BG2 // [11]: Enable BG3 // [12]: Enable sprites // [13]: Mask with window 0 // [14]: Mask with window 1 // [15]: Mask with sprite windows DISPLAY_CR = $00; DISPLAY_CR_MODEMASK = $7; DISPLAY_CR_FB = $10; DISPLAY_CR_NOHBLOBJS = $20; DISPLAY_CR_OBJ_1D = $40; DISPLAY_CR_NO_DISP = $80; DISPLAY_ACTIVE = $01; DISPLAY_ACTIVE_BG0 = $01; DISPLAY_ACTIVE_BG1 = $02; DISPLAY_ACTIVE_BG2 = $04; DISPLAY_ACTIVE_BG3 = $08; DISPLAY_ACTIVE_OBJ = $10; DISPLAY_ACTIVE_WIN0 = $20; DISPLAY_ACTIVE_WIN1 = $40; DISPLAY_ACTIVE_OBJW = $80; // Display Status Register (R/W) // [0]: In V-Blank // [1]: In H-Blank // [2]: Y trigger equals current scanline // [3]: V-Blank IRQ enable // [4]: H-Blank IRQ enable // [5]: Y trigger IRQ enable // [6..7]: Unknown // [8..15]: Scanline Y-trigger value DISPLAY_SR = $04; DISPLAY_SR_IN_VBL = 1 shl 0; DISPLAY_SR_IN_HBL = 1 shl 1; DISPLAY_SR_TRIGGERED = 1 shl 2; DISPLAY_SR_VBL_IRQ = 1 shl 3; DISPLAY_SR_HBL_IRQ = 1 shl 4; DISPLAY_SR_Y_TRIGGER_IRQ = 1 shl 5; DISPLAY_YTRIG = $05; // Current scanline (R) // [0..7]: Current scanline DISPLAY_Y = $06; BG0_CR = $08; BG1_CR = $0A; BG2_CR = $0C; BG3_CR = $0E; // Tiled BG Control Register // [0..1]: Priority (0 is highest) // [2..3]: Tile base (16 KB steps) // [4..5]: Always 0 // [6]: Enable mosaic // [7]: Single palette mode (256 colors) // [8..12]: Screen base (2 KB steps) // [13]: Enable map wrapping (rot/scale only) // [14..15]: Map size TEXT_BG_MOSAIC = 1 shl 6; // If set, apply mosaic to the background TEXT_BG_256COLORS = 1 shl 7; // If set, tiles are 8-bit, otherwise 4-bit RS_BG_WRAP = 1 shl 13; // If set, wrap the bg around, otherwise just go xparent TEXT_BG_XSIZE = 1 shl 14; // If set, X size is 512 rather than 256 TEXT_BG_YSIZE = 1 shl 15; // If set, Y size is 512 rather than 256 BG2_A = $20; // Horizontal dx for BG2 (8.8 fixed point, 16 bits) BG2_B = $22; // Vertical dx for BG2 (8.8 fixed point, 16 bits) BG2_C = $24; // Horizontal dy for BG2 (8.8 fixed point, 16 bits) BG2_D = $26; // Vertical dy for BG2 (8.8 fixed point, 16 bits) BG2_X = $28; // Horizontal offset of BG2 (20.8 fixed point, 28 bits) BG2_Y = $2C; // Vertical offset of BG2 (20.8 fixed point, 28 bits) BG0_X0 = $10; // Text mode BG0 horizontal scroll (9 bits) BG0_Y0 = $12; // Text mode BG0 vertical scroll (9 bits) BG1_X0 = $14; // Text mode BG1 horizontal scroll (9 bits) BG1_Y0 = $16; // Text mode BG1 vertical scroll (9 bits) BG2_X0 = $18; // Text mode BG2 horizontal scroll (9 bits) BG2_Y0 = $1A; // Text mode BG2 vertical scroll (9 bits) BG3_X0 = $1C; // Text mode BG3 horizontal scroll (9 bits) BG3_Y0 = $1E; // Text mode BG3 vertical scroll (9 bits) // scr[x,y] = framebuffer[bg_x + bg_a*x + bg_b*y, bg_y + bg_c*x + bg_d*y] BG3_A = $30; // Horizontal dx for BG3 (8.8 fixed point, 16 bits) BG3_B = $32; // Vertical dx for BG3 (8.8 fixed point, 16 bits) BG3_C = $34; // Horizontal dy for BG3 (8.8 fixed point, 16 bits) BG3_D = $36; // Vertical dy for BG3 (8.8 fixed point, 16 bits) BG3_X = $38; // Horizontal offset of BG3 (20.8 fixed point, 28 bits) BG3_Y = $3C; // Vertical offset of BG3 (20.8 fixed point, 28 bits) BG2_X_DIRTY = $420; BG2_Y_DIRTY = $421; BG3_X_DIRTY = $422; BG3_Y_DIRTY = $423; BG2_X_LATCH = $428; BG2_Y_LATCH = $42C; BG3_X_LATCH = $438; BG3_Y_LATCH = $43C; ////////////////////////////////////////////////////////////////////// // Sprites /////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Sprite attribute 0 // [0-7]: y-coordinate // [8]: when set, rot/scale the object // [9]: when set, use doublesize mode // [10-11]: Sprite mode // 00: normal // 01: apply blending to it // 10: window // 11: invalid // [12]: when set, apply a mosaic to it // [13]: when set, 256 color mode, otherwise 16x16 mode // [14-15]: Shape // 00: Square // 01: Horizontal // 10: Vertical // 11: Invalid const SPRITE_A_ROTSCALE = 1 shl 8; SPRITE_A_DOUBLESIZE = 1 shl 9; SPRITE_A_MOSAIC = 1 shl 12; SPRITE_A_256MODE = 1 shl 13; // Sprite attribute 1 // [0-8]: x-coordinate // [9-13]: rot/scale quad selection // [12]: horizontal flip // [13]: vertical flip // [14,15]: Object size SPRITE_B_FLIP_X = 1 shl 12; SPRITE_B_FLIP_Y = 1 shl 13; // Sprite attribute 2 // [0-9]: Tile number (in bitmap mode, numbers 0-511 are invalid) // (fixme: should we enforce this, or does it just render framebuffer junk when used?) // [10-11]: Priority // [12-15]: Palette (in 256 color mode, it's irrelevant) // Actual size of a sprite: (sh=shape, si=size) // sh si // 00 00 8x8 // 00 01 16x16 // 00 10 32x32 // 00 11 64x64 // 01 00 16x8 // 01 01 32x8 // 01 10 32x16 // 01 11 64x32 // 10 00 8x16 // 10 01 8x32 // 10 10 16x32 // 10 11 32x64 // 11 xx Invalid SpriteSizes: array[0..23] of byte = (8,8, 16,16, 32,32, 64,64, 16,8, 32,8, 32,16, 64,32, 8,16, 8,32, 16,32, 32,64); type TRotScaleSet = packed record a, b, c, d: int16; cx, cy: uint32; end; PRotScaleSet = ^TRotScaleSet; ////////////////////////////////////////////////////////////////////// // Display related registers and constants /////////////////////////// ////////////////////////////////////////////////////////////////////// type // The format of a sprite in OAM TSprite = packed record a, b, c, rs: uint16; end; PSprite = ^TSprite; ////////////////////////////////////////////////////////////////////// const // Framebuffer offsets DISP_FB0_START = $00000; DISP_FB1_START = $0A000; ////////////////////////////////////////////////////////////////////// // Window control registers ////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// WIN0_X0 = $41; WIN0_X1 = $40; WIN0_Y0 = $45; WIN0_Y1 = $44; WIN1_X0 = $43; WIN1_X1 = $42; WIN1_Y0 = $47; WIN1_Y1 = $46; WIN0_IN = $48; WIN1_IN = $49; WIN_OUT = $4A; SPR_WIN_IN = $4B; ////////////////////////////////////////////////////////////////////// // Mosaic registers ////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Mosaic Control Register // [0..3]: BG mosaic x repeat // [4..7]: BG mosaic y repeat // [8..11]: Sprite mosaic x repeat // [12..15]: Sprite mosaic y repeat BG_MOSAIC = $4C; SPR_MOSAIC = $4D; // BG tile format // [0..9]: Tile base (32 byte steps) // [10]: Horizontal flip // [11]: Vertical flip // [12..15]: Palette index ////////////////////////////////////////////////////////////////////// // Blend Registers /////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // bit 0-5 controls the 1st target selection, 4=oam, 5=background // bit 6-7 controls the blend mode BLEND_S1 = $50; // bit 0-5 controls the 2nd target selection ... BLEND_S2 = $51; // bit 0-4 control blend registers, if > 16 then = 16 COEFF_A = $52; COEFF_B = $53; COEFF_Y = $54; SYSTEM_ROM_MASK = $3FFF; EX_WRAM_MASK = $3FFFF; WRAM_MASK = $7FFF; REGISTERS_MASK = $FFF; PALETTE_MASK = $3FF; VRAM_MASK = $1FFFF; OAM_MASK = $3FF; SRAM_MASK = $FFFF; EEPROM_MASK = $1FFF; // Wait State Control Register (R/W) // [0..1]: Old cart bus speed ($0E000000 to $0FFFFFFF) // [2..4]: AD mux bus speed ($08000000 to $09FFFFFF) // [5..7]: AD mux bus speed ($0A000000 to $0BFFFFFF) // [8..10]: AD mux bus speed ($0C000000 to $0DFFFFFF) // [11..12]: Something to do with the PHI pin on the cart bus // [13]: Unknown // [14]: Enable the cart prefetch buffer // [15]: I think this is the value of the switch in the cart slot (R) // todo: test the switch theory and the PHI pin WAIT_STATE_CR = $204; WS_PREFETCH_BUFFER = 1 shl 14; WS_CART_SWITCH = 1 shl 15; // Waits for the AD mux cart bus (N, S bank 0, S bank 1, S bank 2) romWait: array[0..7, 0..3] of byte = ( (4,2,4,8),(3,2,4,8),(2,2,4,8),(8,2,4,8), (4,1,1,1),(3,1,1,1),(2,1,1,1),(8,1,1,1)); // Waits for the 8-bit cart bus (any type of access) sramWait: array[0..3] of byte = (4, 3, 2, 8); ////////////////////////////////////////////////////////////////////// // Timers //////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// const // Timer control registers: // [01]: Clock divider, fires every: // 00 1/1 // 01 1/64 // 10 1/256 // 11 1/1024 // [2]: when set, the lower timer cascades into this one, for long term timers // [6]: when set, trigger an IRQ on overflow // [7]: when set, the timer is active // Timer value is a halfword counter TIMER0 = $100; // Timer 0 value (16 bits) TIMER0_CR = $102; // Timer 0 control (8 bits) TIMER1 = $104; // Timer 1 value (16 bits) TIMER1_CR = $106; // Timer 1 control (8 bits) TIMER2 = $108; // Timer 2 value (16 bits) TIMER2_CR = $10A; // Timer 2 control (8 bits) TIMER3 = $10C; // Timer 3 value (16 bits) TIMER3_CR = $10E; // Timer 3 control (8 bits) TIMER0_LATCH = $500; TIMER1_LATCH = $504; TIMER2_LATCH = $508; TIMER3_LATCH = $50C; TIMER0_CYCLES = $510; TIMER1_CYCLES = $514; TIMER2_CYCLES = $518; TIMER3_CYCLES = $51C; TIMER0_SPEED = $520; TIMER1_SPEED = $521; TIMER2_SPEED = $522; TIMER3_SPEED = $523; TIMER_ENABLED = 1 shl 7; TIMER_IRQ = 1 shl 6; TIMER_CASCADE = 1 shl 2; ////////////////////////////////////////////////////////////////////// // DMA Registers ///////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// DMA0_SRC = $B0; // 26 bit source address DMA0_DEST = $B4; // 26 bit dest address DMA0_COUNT = $B8; // 14 bit word count DMA0_CR = $BA; // control register DMA1_SRC = $BC; // 26 bit source address DMA1_DEST = $C0; // 26 bit dest address DMA1_COUNT = $C4; // 14 bit word count DMA1_CR = $C6; // control register DMA2_SRC = $C8; // 26 bit source address DMA2_DEST = $CC; // 26 bit dest address DMA2_COUNT = $D0; // 14 bit word count DMA2_CR = $D2; // control register DMA3_SRC = $D4; // 26 bit source address DMA3_DEST = $D8; // 26 bit dest address DMA3_COUNT = $DC; // 16 bit word count DMA3_CR = $DE; // control register DMA_REPEAT = 1 shl 9; DMA_ENABLED = 1 shl 15; DMA_IRQ_REQ = 1 shl 14; ////////////////////////////////////////////////////////////////////// // Joystick registers //////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Key input register, clear when there is input // [0]: A // [1]: B // [2]: Select // [3]: Start // [4]: D-pad right // [5]: D-pad left // [6]: D-pad up // [7]: D-pad down // [8]: Shoulder right // [9]: Shoulder left KEYS = $130; // Key status (10 bits) KEY_IRQ_ENABLED = $4000; KEY_IRQ_AND = $8000; // if 1, KEYS and KEY_IRQ triggers, otherwise KEYS or KEY_IRQ KEY_IRQS = $132; // Key irq mask in bottom 10 ////////////////////////////////////////////////////////////////////// // Sound Registers /////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// const SOUNDA_FIFO = $0A0; // 32 bit sound data for DSound A SOUNDB_FIFO = $0A4; // 32 bit sound data for DSound B // Sound 1 is a square wave with sweep and envelope control SOUND1_SWEEP = $060; // Sound 1 sweep control (8 bits) SOUND_SWEEP_DECREASE = 1 shl 3; // 0: increase, 1: decrease SOUND1_LENGTH = $062; // Sound 1 length control (8 bits) SOUND1_ENVELOPE = $063; // Sound 1 envelope control (8 bits) SOUND_ENVELOPE_INCREASE = 1 shl 3; // 0: decrease, 1: increase SOUND1_FREQUENCY = $064; // Sound 1 frequency and control (16 bits) // Sound 2 is a square wave with envelope control SOUND2_LENGTH = $068; // Sound 2 length control (8 bits) SOUND2_ENVELOPE = $069; // Sound 2 envelope control (8 bits) SOUND2_FREQUENCY = $06C; // Sound 2 frequency and control (16 bits) // Sound 3 is a raw wave channel SOUND3_CR = $070; // Sound 3 control register (8 bits) SOUND3_64SAMPLES = $20; SOUND3_BANK1 = $40; SOUND3_ACTIVE = $80; SOUND3_LENGTH = $072; // Sound 3 length control (8 bits) SOUND3_VOLUME = $073; // Sound 3 volume control (8 bits) SOUND3_FREQUENCY = $074; // Sound 3 frequency and control (8 bits) // Sound 4 is a white noise channel with envelope control SOUND4_LENGTH = $078; // Sound 4 length control (8 bits) SOUND4_ENVELOPE = $079; // Sound 4 envelope control (8 bits) SOUND4_CR = $07C; // Sound 4 control register (16 bits) SOUND4_7_STEPS = $8; // Global sound control SOUND_VOLUME = $080; // Controls the playing volumes of the channels (8 bits) SOUND_ACTIVE = $081; // Controls how sounds are piped to the outputs (8 bits) SOUND_DSOUND_CR = $082; // Sound A/B control register (16 bits) SOUND_ENABLED = $084; // Top bit is master enable, low 4 are status bits (8 bits) SOUND_BIAS = $088; // Unknown ??? (16 bits) SOUND3_PATTERN = $90; // 16 bytes of 4 bit samples DSA_VOLUME_SH = 2; DSB_VOLUME_SH = 3; DSA_RIGHT = 1 shl 8; DSA_LEFT = 1 shl 9; DSA_TIMER = 1 shl 10; DSA_RESET = 1 shl 11; DSB_RIGHT = 1 shl 12; DSB_LEFT = 1 shl 13; DSB_TIMER = 1 shl 14; DSB_RESET = 1 shl 15; ////////////////////////////////////////////////////////////////////// /// IRQ registers //////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// const // IRQ registers IRQ_ENABLED = $200; // Bits for irq enabled as below IRQ_FLAGS = $202; // Bits for irq triggered as below IRQ_MASTER = $208; // Interrupt master enable PAUSE = $300; // Key irq control register ([0-9] are set when the // corresponding key might trigger an interrupt) // [14]: Key interrupt enable, the rest of the reg is ignored when cleared // [15]: clear = OR, set = AND. // An interrupt is only set if a key with the possibility bit is set, [14] is set, // and [15] is clear, or when all possibility bits are met, and [15] is set. // Capice. KEY_IRQ = $132; // 16 bits ////////////////////////////////////////////////////////////////////// const LAST_SWI = $2D; swiNames: array[$00..LAST_SWI] of string = ( 'SoftReset', 'RegisterRAMReset', 'Halt', 'Stop', 'IntrWait', 'VBlankIntrWait', 'Div', 'DivARM', 'Sqrt', 'ArcTan', 'ArcTan2', 'CPUSet', 'CPUFastSet', 'BIOSChecksum', 'BgAffineSet', 'ObjAffineSet', 'BitUnpack', 'LZ77UncompRAM', 'LZ77UncompVRAM', 'HuffUncomp', 'RLEUncompRAM', 'RLEUncompVRAM', 'Diff8bitUnfilterRAM', 'Diff8bitUnfilterVRAM', 'Diff16bitUnfilter', 'SoundBiasChange', 'SoundDriverInit', 'SoundDriverMode', 'SoundDriverMain', 'SoundDriverVSync', 'SoundChannelClear', 'MIDIKey2Freq', 'MusicPlayerOpen', 'MusicPlayerStart', 'MusicPlayerStop', 'MusicPlayerContinue', 'MusicPlayerFadeOut', 'Multiboot', '', '', 'SoundDriverVSyncOff', 'SoundDriverVSyncOn', '', '', '', 'BIOSBootSequence'); ////////////////////////////////////////////////////////////////////// // Interrupts //////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// const // IRQ flags IRQ_VBLANK = $0001; IRQ_HBLANK = $0002; IRQ_YLINE = $0004; IRQ_TIMER0 = $0008; IRQ_TIMER1 = $0010; IRQ_TIMER2 = $0020; IRQ_TIMER3 = $0040; IRQ_NETWORK = $0080; IRQ_DMA0 = $0100; IRQ_DMA1 = $0200; IRQ_DMA2 = $0400; IRQ_DMA3 = $0800; IRQ_KEY = $1000; IRQ_UNKNOWN = $2000; ////////////////////////////////////////////////////////////////////// // Exception vectors ///////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// RESET_VECTOR = $00000000; // Reset (Supervisor mode on entry) UNDEFINED_INST_VECTOR = $00000004; // Undefined instruction (no mode change?) SWI_VECTOR = $00000008; // Software interrupt (Supervisor mode on entry) ABORT_PREFETCH_VECTOR = $0000000C; // Abort (prefetch) (Abort mode on entry) ABORT_DATA_VECTOR = $00000010; // Abort (data) (Abort mode on entry) RESERVED_VECTOR = $00000014; // Reserved IRQ_VECTOR = $00000018; // IRQ (IRQ mode on entry) FIQ_VECTOR = $0000001C; // FIQ (FIQ mode on entry) ////////////////////////////////////////////////////////////////////// // Registers and shadows for other processor modes /////////////////// ////////////////////////////////////////////////////////////////////// R0 = 0; R1 = 1; R2 = 2; R3 = 3; R4 = 4; R5 = 5; R6 = 6; R7 = 7; R8 = 8; R8_fiq = 17; R9 = 9; R9_fiq = 18; R10 = 10; R10_fiq = 19; R11 = 11; R11_fiq = 20; R12 = 12; R12_fiq = 21; R13 = 13; R13_fiq = 22; R13_svc = 25; R13_abt = 28; R13_irq = 31; R13_und = 34; R14 = 14; R14_fiq = 23; R14_svc = 26; R14_abt = 29; R14_irq = 32; R14_und = 35; R15 = 15; CPSR = 16; SPSR_fiq = 24; SPSR_svc = 27; SPSR_abt = 30; SPSR_irq = 33; SPSR_und = 36; LR = R14; PIPELINE_0 = 37; PIPELINE_1 = 38; // Modes // Number of registers to swap MODE_USER = $10; // Shares regs with system MODE_FIQ = $11; FIQ_REGS = 7; MODE_IRQ = $12; IRQ_REGS = 2; MODE_SUPERVISOR = $13; SUPERVISOR_REGS = 2; MODE_ABORT = $17; ABORT_REGS = 2; MODE_UNDEFINED = $1B; UNDEFINED_REGS = 2; MODE_SYSTEM = $1F; // Shares regs with user ////////////////////////////////////////////////////////////////////// // ARM7TDMI CPU basic cycle timings ////////////////////////////////// ////////////////////////////////////////////////////////////////////// // These are long past being needed, I only keep them around // to tag different cycles in an equation as being of a particular // type. Delphi is smart enough to constant fold out any of these, // but it may be necessary on other compilers to do it manually. cycI = 1; // No memory access cycle cycS = 1; // Sequential memory access cycN = 1; // Non sequential access ////////////////////////////////////////////////////////////////////// // Condition codes /////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// EQ = $0; // Equal NE = $1; // Not equal CS = $2; // Unsigned higher or same CC = $3; // Unsigned lower MI = $4; // Negative PL = $5; // Positive or zero VS = $6; // Overflow VC = $7; // No overflow HI = $8; // Unsigned higher LS = $9; // Unsigned lower or same GE = $A; // Greater or equal LT = $B; // Less than GT = $C; // Greater than LE = $D; // Less than or equal AL = $E; // Always NV = $F; // Never, todo: is this depriciated on the arm7tdmi, or invalid ////////////////////////////////////////////////////////////////////// // Barrel Shifter Codes ////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// LSL = 0; // Logical shift left LSR = 1; // Logical shift right ASR = 2; // Arithmatic shift right ROR = 3; // Rotate right ////////////////////////////////////////////////////////////////////// // Bits in the CPSR register ///////////////////////////////////////// ////////////////////////////////////////////////////////////////////// SR_N = 2147483648; // 1 shl 31; fixme, why doesn't this work // negative SR_Z = 1 shl 30; // zero SR_C = 1 shl 29; // carry/borrow/extend SR_V = 1 shl 28; // overflow SR_I = 1 shl 7; // IRQ disable SR_F = 1 shl 6; // FIQ disable SR_T = 1 shl 5; // Thumb Mode if set ////////////////////////////////////////////////////////////////////// SOUND_RESTART = 1 shl 15; ////////////////////////////////////////////////////////////////////// // Instruction masks and signatures (currentOpcode and mask = sig) /// ////////////////////////////////////////////////////////////////////// const BX_MASK = $0FFFFFF0; // 0000 111111111111111111111111 0000 BX_SIG = $012FFF10; // 0000 000100101111111111110001 0000 ALU_SHIFT_BY_IMM_MASK = $0E000010; // 0000 111 0000 0 0000 0000 00000 00 1 0000 ALU_SHIFT_BY_IMM_SIG = $00000000; // 0000 000 0000 0 0000 0000 00000 00 0 0000 ALU_SHIFT_BY_REG_MASK = $0E000090; // 0000 111 0000 0 0000 0000 0000 1 00 1 0000 ALU_SHIFT_BY_REG_SIG = $00000010; // 0000 000 0000 0 0000 0000 0000 0 00 1 0000 ALU_IMM_ROT_MASK = $0E000000; // 0000 111 0000 0 0000 0000 0000 00000000 ALU_IMM_ROT_SIG = $02000000; // 0000 001 0000 0 0000 0000 0000 00000000 MULTIPLY_MASK = $0FC000F0; // 0000 111111 00 0000 0000 0000 1111 0000 MULTIPLY_SIG = $00000090; // 0000 000000 00 0000 0000 0000 1001 0000 MULTIPLY_LONG_MASK = $0F8000F0; // 0000 11111 000 0000 0000 0000 1111 0000 MULTIPLY_LONG_SIG = $00800090; // 0000 00001 000 0000 0000 0000 1001 0000 SINGLE_DATA_SWAP_MASK = $0FB00FF0; // 0000 11111 0 11 0000 0000 11111111 0000 SINGLE_DATA_SWAP_SIG = $01000090; // 0000 00010 0 00 0000 0000 00001001 0000 HW_XFER_REGOFS_MASK = $0E400F90; // 0000 111 00 1 00 0000 0000 11111 00 1 0000 HW_XFER_REGOFS_SIG = $00000090; // 0000 000 00 0 00 0000 0000 00001 00 1 0000 HW_XFER_IMMOFS_MASK = $0E400090; // 0000 111 00 1 00 0000 0000 0000 1 00 1 0000 HW_XFER_IMMOFS_SIG = $00400090; // 0000 000 00 1 00 0000 0000 0000 1 00 1 0000 SINGLE_DATA_XFER_MASK = $0C000000; // 0000 11 000000 0000 0000 000000000000 SINGLE_DATA_XFER_SIG = $04000000; // 0000 01 000000 0000 0000 000000000000 UNDEFINED_MASK = $0E000010; // 0000 111 00000 000000000000000 1 0000 UNDEFINED_SIG = $06000010; // 0000 011 00000 000000000000000 1 0000 BLOCK_DATA_XFER_MASK = $0E000000; // 0000 111 00000 0000 0000000000000000 BLOCK_DATA_XFER_SIG = $08000000; // 0000 100 00000 0000 0000000000000000 // BRANCH_MASK = $0E000000; // 0000 111 0 000000000000000000000000 BRANCH_SIG = $0A000000; // 0000 101 0 000000000000000000000000 COPRO_DATA_XFER_MASK = $0E000000; // 0000 111 00000 0000 0000 0000 00000000 COPRO_DATA_XFER_SIG = $0C000000; // 0000 110 00000 0000 0000 0000 00000000 COPRO_DATA_OP_MASK = $0F000010; // 0000 1111 0000 0000 0000 0000 000 1 0000 COPRO_DATA_OP_SIG = $0E000000; // 0000 1110 0000 0000 0000 0000 000 0 0000 COPRO_REG_XFER_MASK = $0F000010; // 0000 1111 000 0 0000 0000 0000 000 1 0000 COPRO_REG_XFER_SIG = $0E000010; // 0000 1110 000 0 0000 0000 0000 000 1 0000 SWI_MASK = $0F000000; // 0000 1111 000000000000000000000000 SWI_SIG = $0F000000; // 0000 1111 000000000000000000000000 ////////////////////////////////////////////////////////////////////// // ALU Opcodes /////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// AND_OPCODE = $0; // operand1 AND operand2 EOR_OPCODE = $1; // operand1 EOR operand2 SUB_OPCODE = $2; // operand1 - operand2 RSB_OPCODE = $3; // operand2 - operand1 ADD_OPCODE = $4; // operand1 + operand2 ADC_OPCODE = $5; // operand1 + operand2 + carry SBC_OPCODE = $6; // operand1 - operand2 + carry - 1 RSC_OPCODE = $7; // operand2 - operand1 + carry - 1 TST_OPCODE = $8; // as AND, but result is not written TEQ_OPCODE = $9; // as EOR, but result is not written CMP_OPCODE = $A; // as SUB, but result is not written CMN_OPCODE = $B; // as ADD, but result is not written ORR_OPCODE = $C; // operand1 OR operand2 MOV_OPCODE = $D; // operand2 (operand1 is ignored) BIC_OPCODE = $E; // operand1 AND NOT operand2 (Bit clear) MVN_OPCODE = $F; // NOT operand2 (operand1 is ignored) ////////////////////////////////////////////////////////////////////// type TSoundChannel1 = record enabled: boolean; // freq is the number of ticks before waveIndex is incremented freq: integer; index: integer; // index is the freq counter waveIndex: integer; waveDuty: integer; // If timed, then soundLength is the number of ticks before turning off timed: boolean; soundLength: integer; volume: integer; envIncrease: boolean; // env rate is the number of ticks before the envelope is modified envRate: integer; envIndex: integer; sweepDecrease: boolean; sweepStep: integer; // sweep rate is the number of ticks before the sweep is modified sweepRate: integer; sweepIndex: integer; end; TSoundChannel2 = record enabled: boolean; // freq is the number of ticks before waveIndex is incremented freq: integer; index: integer; // index is the freq counter waveIndex: integer; waveDuty: integer; // If timed, then soundLength is the number of ticks before turning off timed: boolean; soundLength: integer; volume: integer; envIncrease: boolean; // env rate is the number of ticks before the envelope is modified envRate: integer; envIndex: integer; end; TSoundChannel3 = record enabled: boolean; // freq is the number of ticks before waveIndex is incremented freq: integer; index: integer; // index is the freq counter waveIndex: integer; volume: integer; doubleLength: boolean; curBank: boolean; backBank: array[0..15] of byte; // If timed, then soundLength is the number of ticks before turning off timed: boolean; soundLength: integer; end; TSoundChannel4 = record enabled: boolean; index: integer; // index is the freq counter freq: integer; // freq is the number of cycles before clocking the shift register lfsr: integer; use7steps: boolean; // controls whether the LFSR is 7 or 15 bits // If timed, then soundLength is the number of ticks before turning off timed: boolean; soundLength: integer; volume: integer; envIncrease: boolean; // env rate is the number of ticks before the envelope is modified envRate: integer; envIndex: integer; end; TDSoundRecord = record writeIndex: integer; fifo: array[0..31] of int8; enabled: boolean; lvol, rvol: integer; timer: integer; latched: int8; end; ////////////////////////////////////////////////////////////////////// TBreakpointMode = (bpmHard, bpmSoft); TBreakpointModes = set of TBreakpointMode; TvmOpaqueChunk = record magic: array[0..7] of char; version: uint32; size: uint32; end; PvmOpaqueChunk = pointer; TvmRegisterFile = record regs: array[0..38] of uint32; end; TvmProfileToken = pointer; // totally opaque TvmMemoryLock1 = record version: uint16; // version number, should be 1 misc: uint16; // anything needed for the locking mechanism bios: Puint8Array; // 16 KB exwram: Puint8Array; // 256 KB wram: Puint8Array; // 32 KB iospace: Puint8Array; // 1 KB palette: Puint8Array; // 1 KB vram: Puint8Array; // 96 KB oam: Puint8Array; // 1 KB rom: Puint8Array; // specified by romsize romsize: uint32; reserved: array[0..23] of byte; // reserved end; ////////////////////////////////////////////////////////////////////// TvmOnSoundReady = procedure (data: pointer; length: integer); TvmOnVideoReady = procedure (y: integer; sline: Puint16); TvmOnConsoleReady = procedure (line: PChar); TvmSavestate1 = record magic: uint32; version: integer; size: integer; crc: uint32; cartLoaded: boolean; filename: array[0..255] of char; // Memory spaces systemROM: array[0..SYSTEM_ROM_MASK] of byte; // 00000000h..00003FFFh exWRAM: array[0..EX_WRAM_MASK] of byte; // 02000000h..0203FFFFh WRAM: array[0..WRAM_MASK] of byte; // 03000000h..03007FFFh registers: array[0..REGISTERS_MASK] of byte; // 04000000h.. palette: array[0..PALETTE_MASK] of byte; // 05000000h..050003FFh VRAM: array[0..VRAM_MASK] of byte; // 06000000h..06017FFFh OAM: array[0..OAM_MASK] of byte; // 07000000h..070003FFh cartRAM: array[0..SRAM_MASK] of byte; // 0E000000h.. cartRAMdirty: boolean; lastAddress: uint32; // CPU status cpuGlobalTicks: uint32; cpuStopped, cpuHalted: boolean; irqPending: boolean; regs: array[0..36+2] of uint32; SPSR: uint32; // Events HBlankEvent: integer; enteringHBlank: boolean; eventCycleDelta: integer; eventCyclesLeft: integer; // Sound soundA, soundB: TDSoundRecord; sound1: TSoundChannel1; sound2: TSoundChannel2; sound3: TSoundChannel3; sound4: TSoundChannel4; end; PvmSavestate = ^TvmSavestate1; ////////////////////////////////////////////////////////////////////// implementation /////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// end. //////////////////////////////////////////////////////////////////////