A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 177 lines 3.7 kB view raw
1 2 3 4#include "rockmacros.h" 5#include "defs.h" 6#include "cpu-gb.h" 7#include "hw.h" 8#include "regs.h" 9#include "lcd-gb.h" 10#include "mem.h" 11#include "fastmem.h" 12 13 14struct hw hw IBSS_ATTR; 15 16 17 18/* 19 * hw_interrupt changes the virtual interrupt lines included in the 20 * specified mask to the values the corresponding bits in i take, and 21 * in doing so, raises the appropriate bit of R_IF for any interrupt 22 * lines that transition from low to high. 23 */ 24 25void hw_interrupt(byte i, byte mask) 26{ 27 byte oldif = R_IF; 28 i &= 0x1F & mask; 29 R_IF |= i & (hw.ilines ^ i); 30 31 /* FIXME - is this correct? not sure the docs understand... */ 32 if ((R_IF & (R_IF ^ oldif) & R_IE) && cpu.ime) cpu.halt = 0; 33 /* if ((i & (hw.ilines ^ i) & R_IE) && cpu.ime) cpu.halt = 0; */ 34 /* if ((i & R_IE) && cpu.ime) cpu.halt = 0; */ 35 36 hw.ilines &= ~mask; 37 hw.ilines |= i; 38} 39 40 41/* 42 * hw_dma performs plain old memory-to-oam dma, the original dmg 43 * dma. Although on the hardware it takes a good deal of time, the cpu 44 * continues running during this mode of dma, so no special tricks to 45 * stall the cpu are necessary. 46 */ 47 48void hw_dma(byte b) 49{ 50 int i; 51 addr a; 52 53 a = ((addr)b) << 8; 54 for (i = 0; i < 160; i++, a++) 55 lcd.oam.mem[i] = readb(a); 56} 57 58void hw_hdma(void) 59{ 60 int cnt; 61 addr sa; 62 int da; 63 64 sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0); 65 da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0); 66 for (cnt=16; cnt>0; cnt--) 67 writeb(da++, readb(sa++)); 68 cpu_timers(16); 69 R_HDMA1 = sa >> 8; 70 R_HDMA2 = sa & 0xF0; 71 R_HDMA3 = 0x1F & (da >> 8); 72 R_HDMA4 = da & 0xF0; 73 R_HDMA5--; 74 hw.hdma--; 75} 76 77void hw_hdma_cmd(byte c) 78{ 79 int cnt; 80 addr sa; 81 int da; 82 83 /* Begin or cancel HDMA */ 84 if ((hw.hdma|c) & 0x80) 85 { 86 hw.hdma = c; 87 R_HDMA5 = c & 0x7f; 88 if ((R_STAT&0x03) == 0x00) hw_hdma(); 89 return; 90 } 91 92 /* Perform GDMA */ 93 sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0); 94 da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0); 95 cnt = (((int)c)+1) << 4; 96 /* FIXME - this should use cpu time! */ 97 /*cpu_timers(102 * cnt);*/ 98 cpu_timers((460>>cpu.speed)+cnt); /*dalias*/ 99 /*cpu_timers(228 + (16*cnt));*/ /* this should be right according to no$ */ 100 while (cnt--) 101 writeb(da++, readb(sa++)); 102 R_HDMA1 = sa >> 8; 103 R_HDMA2 = sa & 0xF0; 104 R_HDMA3 = 0x1F & (da >> 8); 105 R_HDMA4 = da & 0xF0; 106 R_HDMA5 = 0xFF; 107} 108 109 110/* 111 * pad_refresh updates the P1 register from the pad states, generating 112 * the appropriate interrupts (by quickly raising and lowering the 113 * interrupt line) if a transition has been made. 114 */ 115 116void pad_refresh(void) 117{ 118 byte oldp1; 119 oldp1 = R_P1; 120 R_P1 &= 0x30; 121 R_P1 |= 0xc0; 122 if (!(R_P1 & 0x10)) 123 R_P1 |= (hw.pad & 0x0F); 124 if (!(R_P1 & 0x20)) 125 R_P1 |= (hw.pad >> 4); 126 R_P1 ^= 0x0F; 127 if (oldp1 & ~R_P1 & 0x0F) 128 { 129 hw_interrupt(IF_PAD, IF_PAD); 130 hw_interrupt(0, IF_PAD); 131 } 132} 133 134 135/* 136 * These simple functions just update the state of a button on the 137 * pad. 138 */ 139 140static void pad_press(byte k) ICODE_ATTR; 141static void pad_press(byte k) 142{ 143 if (hw.pad & k) 144 return; 145 hw.pad |= k; 146 pad_refresh(); 147} 148 149static void pad_release(byte k) ICODE_ATTR; 150static void pad_release(byte k) 151{ 152 if (!(hw.pad & k)) 153 return; 154 hw.pad &= ~k; 155 pad_refresh(); 156} 157 158void pad_set(byte k, int st) 159{ 160 st ? pad_press(k) : pad_release(k); 161} 162 163void hw_reset(void) 164{ 165 hw.ilines = hw.pad = 0; 166 167 memset(ram.hi, 0, sizeof ram.hi); 168 169 R_P1 = 0xFF; 170 R_LCDC = 0x91; 171 R_BGP = 0xFC; 172 R_OBP0 = 0xFF; 173 R_OBP1 = 0xFF; 174 R_SVBK = 0x01; 175 R_HDMA5 = 0xFF; 176 R_VBK = 0xFE; 177}