diff options
author | Jens Arnold <amiconn@rockbox.org> | 2005-03-02 23:49:38 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2005-03-02 23:49:38 +0000 |
commit | 384de102469fee4e0792df8fe38586d3206774ed (patch) | |
tree | ee5342103e17738acfb8421328ea7c57433f55e6 /apps/plugins/rockboy/hw.c | |
parent | 48dad47df98bdec632e8930b6a97359dc2c428f5 (diff) | |
download | rockbox-384de102469fee4e0792df8fe38586d3206774ed.tar.gz rockbox-384de102469fee4e0792df8fe38586d3206774ed.zip |
Rockboy - gameboy emulation for rockbox, based on gnuboy. Still a bit early, but already playable on iRiver H1xx and the simulators. The archos recorder version is currently rather slow...
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6104 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/rockboy/hw.c')
-rw-r--r-- | apps/plugins/rockboy/hw.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/apps/plugins/rockboy/hw.c b/apps/plugins/rockboy/hw.c new file mode 100644 index 0000000000..c287e24f8a --- /dev/null +++ b/apps/plugins/rockboy/hw.c | |||
@@ -0,0 +1,183 @@ | |||
1 | |||
2 | |||
3 | |||
4 | #include "rockmacros.h" | ||
5 | #include "defs.h" | ||
6 | #include "cpu.h" | ||
7 | #include "hw.h" | ||
8 | #include "regs.h" | ||
9 | #include "lcd.h" | ||
10 | #include "mem.h" | ||
11 | #include "fastmem.h" | ||
12 | |||
13 | |||
14 | struct hw hw; | ||
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 | |||
25 | void 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 | |||
48 | void 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 | |||
58 | |||
59 | |||
60 | void hw_hdma_cmd(byte c) | ||
61 | { | ||
62 | int cnt; | ||
63 | addr sa; | ||
64 | int da; | ||
65 | |||
66 | /* Begin or cancel HDMA */ | ||
67 | if ((hw.hdma|c) & 0x80) | ||
68 | { | ||
69 | hw.hdma = c; | ||
70 | R_HDMA5 = c & 0x7f; | ||
71 | return; | ||
72 | } | ||
73 | |||
74 | /* Perform GDMA */ | ||
75 | sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0); | ||
76 | da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0); | ||
77 | cnt = ((int)c)+1; | ||
78 | /* FIXME - this should use cpu time! */ | ||
79 | /*cpu_timers(102 * cnt);*/ | ||
80 | cnt <<= 4; | ||
81 | while (cnt--) | ||
82 | writeb(da++, readb(sa++)); | ||
83 | R_HDMA1 = sa >> 8; | ||
84 | R_HDMA2 = sa & 0xF0; | ||
85 | R_HDMA3 = 0x1F & (da >> 8); | ||
86 | R_HDMA4 = da & 0xF0; | ||
87 | R_HDMA5 = 0xFF; | ||
88 | } | ||
89 | |||
90 | |||
91 | void hw_hdma(void) | ||
92 | { | ||
93 | int cnt; | ||
94 | addr sa; | ||
95 | int da; | ||
96 | |||
97 | sa = ((addr)R_HDMA1 << 8) | (R_HDMA2&0xf0); | ||
98 | da = 0x8000 | ((int)(R_HDMA3&0x1f) << 8) | (R_HDMA4&0xf0); | ||
99 | cnt = 16; | ||
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--; | ||
107 | hw.hdma--; | ||
108 | } | ||
109 | |||
110 | |||
111 | /* | ||
112 | * pad_refresh updates the P1 register from the pad states, generating | ||
113 | * the appropriate interrupts (by quickly raising and lowering the | ||
114 | * interrupt line) if a transition has been made. | ||
115 | */ | ||
116 | |||
117 | void pad_refresh() | ||
118 | { | ||
119 | byte oldp1; | ||
120 | oldp1 = R_P1; | ||
121 | R_P1 &= 0x30; | ||
122 | R_P1 |= 0xc0; | ||
123 | if (!(R_P1 & 0x10)) | ||
124 | R_P1 |= (hw.pad & 0x0F); | ||
125 | if (!(R_P1 & 0x20)) | ||
126 | R_P1 |= (hw.pad >> 4); | ||
127 | R_P1 ^= 0x0F; | ||
128 | if (oldp1 & ~R_P1 & 0x0F) | ||
129 | { | ||
130 | hw_interrupt(IF_PAD, IF_PAD); | ||
131 | hw_interrupt(0, IF_PAD); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | |||
136 | /* | ||
137 | * These simple functions just update the state of a button on the | ||
138 | * pad. | ||
139 | */ | ||
140 | |||
141 | void pad_press(byte k) | ||
142 | { | ||
143 | if (hw.pad & k) | ||
144 | return; | ||
145 | hw.pad |= k; | ||
146 | pad_refresh(); | ||
147 | } | ||
148 | |||
149 | void pad_release(byte k) | ||
150 | { | ||
151 | if (!(hw.pad & k)) | ||
152 | return; | ||
153 | hw.pad &= ~k; | ||
154 | pad_refresh(); | ||
155 | } | ||
156 | |||
157 | void pad_set(byte k, int st) | ||
158 | { | ||
159 | st ? pad_press(k) : pad_release(k); | ||
160 | } | ||
161 | |||
162 | void hw_reset() | ||
163 | { | ||
164 | hw.ilines = hw.pad = 0; | ||
165 | |||
166 | memset(ram.hi, 0, sizeof ram.hi); | ||
167 | |||
168 | R_P1 = 0xFF; | ||
169 | R_LCDC = 0x91; | ||
170 | R_BGP = 0xFC; | ||
171 | R_OBP0 = 0xFF; | ||
172 | R_OBP1 = 0xFF; | ||
173 | R_SVBK = 0x01; | ||
174 | R_HDMA5 = 0xFF; | ||
175 | R_VBK = 0xFE; | ||
176 | } | ||
177 | |||
178 | |||
179 | |||
180 | |||
181 | |||
182 | |||
183 | |||