/[gxemul]/trunk/src/devices/dev_sh4.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_sh4.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19926 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


1 /*
2 * Copyright (C) 2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_sh4.c,v 1.21 2006/11/02 05:43:44 debug Exp $
29 *
30 * SH4 processor specific memory mapped registers (0xf0000000 - 0xffffffff).
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "console.h"
38 #include "cpu.h"
39 #include "device.h"
40 #include "devices.h"
41 #include "machine.h"
42 #include "memory.h"
43 #include "misc.h"
44 #include "timer.h"
45
46 #include "sh4_bscreg.h"
47 #include "sh4_cache.h"
48 #include "sh4_exception.h"
49 #include "sh4_intcreg.h"
50 #include "sh4_mmu.h"
51 #include "sh4_scifreg.h"
52 #include "sh4_tmureg.h"
53
54
55 #define SH4_REG_BASE 0xff000000
56 #define SH4_TICK_SHIFT 14
57 #define N_SH4_TIMERS 3
58
59 /* #define debug fatal */
60
61 struct sh4_data {
62 int scif_console_handle;
63
64 /* Bus State Controller: */
65 uint32_t unknown_2c;
66 uint32_t unknown_30;
67
68 /* Timer Management Unit: */
69 struct timer *sh4_timer;
70 uint32_t tocr;
71 uint32_t tstr;
72 uint32_t tcnt[N_SH4_TIMERS];
73 uint32_t tcor[N_SH4_TIMERS];
74 uint32_t tcr[N_SH4_TIMERS];
75 int timer_interrupts_pending[N_SH4_TIMERS];
76 double timer_hz[N_SH4_TIMERS];
77 };
78
79
80 #define SH4_PSEUDO_TIMER_HZ 100.0
81
82
83 /*
84 * sh4_timer_tick():
85 *
86 * This function is called SH4_PSEUDO_TIMER_HZ times per real-world second.
87 * Its job is to update the SH4 timer counters, and if necessary, increase
88 * the number of pending interrupts.
89 */
90 static void sh4_timer_tick(struct timer *t, void *extra)
91 {
92 struct sh4_data *d = (struct sh4_data *) extra;
93 int i;
94
95 for (i=0; i<N_SH4_TIMERS; i++) {
96 int32_t old = d->tcnt[i];
97
98 /* printf("tcnt[%i] = %08x tcor[%i] = %08x\n",
99 i, d->tcnt[i], i, d->tcor[i]); */
100
101 /* Only update timers that are currently started: */
102 if (!(d->tstr & (TSTR_STR0 << i)))
103 continue;
104
105 /* Update the current count: */
106 d->tcnt[i] -= d->timer_hz[i] / SH4_PSEUDO_TIMER_HZ;
107
108 /* Has the timer underflowed? */
109 if ((int32_t)d->tcnt[i] < 0 && old >= 0) {
110 d->tcr[i] |= TCR_UNF;
111
112 if (d->tcr[i] & TCR_UNIE)
113 d->timer_interrupts_pending[i] ++;
114
115 /*
116 * Set tcnt[i] to tcor[i]. Note: Since this function
117 * is only called now and then, adding tcor[i] to
118 * tcnt[i] produces more correct values for long
119 * running timers.
120 */
121 d->tcnt[i] += d->tcor[i];
122
123 /* At least make sure that tcnt is non-negative... */
124 if ((int32_t)d->tcnt[i] < 0)
125 d->tcnt[i] = 0;
126 }
127 }
128 }
129
130
131 DEVICE_TICK(sh4)
132 {
133 struct sh4_data *d = (struct sh4_data *) extra;
134 int i;
135
136 for (i=0; i<N_SH4_TIMERS; i++)
137 if (d->timer_interrupts_pending[i] > 0) {
138 cpu_interrupt(cpu, SH_INTEVT_TMU0_TUNI0 + 0x20 * i);
139 d->tcr[i] |= TCR_UNF;
140 }
141 }
142
143
144 DEVICE_ACCESS(sh4_itlb_aa)
145 {
146 uint64_t idata = 0, odata = 0;
147 int e = (relative_addr & SH4_ITLB_E_MASK) >> SH4_ITLB_E_SHIFT;
148
149 if (writeflag == MEM_WRITE) {
150 int safe_to_invalidate = 0;
151 uint32_t old_hi = cpu->cd.sh.itlb_hi[e];
152 if ((cpu->cd.sh.itlb_lo[e] & SH4_PTEL_SZ_MASK)==SH4_PTEL_SZ_4K)
153 safe_to_invalidate = 1;
154
155 idata = memory_readmax64(cpu, data, len);
156 cpu->cd.sh.itlb_hi[e] &=
157 ~(SH4_PTEH_VPN_MASK | SH4_PTEH_ASID_MASK);
158 cpu->cd.sh.itlb_hi[e] |= (idata &
159 (SH4_ITLB_AA_VPN_MASK | SH4_ITLB_AA_ASID_MASK));
160 cpu->cd.sh.itlb_lo[e] &= ~SH4_PTEL_V;
161 if (idata & SH4_ITLB_AA_V)
162 cpu->cd.sh.itlb_lo[e] |= SH4_PTEL_V;
163
164 if (safe_to_invalidate)
165 cpu->invalidate_translation_caches(cpu,
166 old_hi & ~0xfff, INVALIDATE_VADDR);
167 else
168 cpu->invalidate_translation_caches(cpu,
169 0, INVALIDATE_ALL);
170 } else {
171 odata = cpu->cd.sh.itlb_hi[e] &
172 (SH4_ITLB_AA_VPN_MASK | SH4_ITLB_AA_ASID_MASK);
173 if (cpu->cd.sh.itlb_lo[e] & SH4_PTEL_V)
174 odata |= SH4_ITLB_AA_V;
175 memory_writemax64(cpu, data, len, odata);
176 }
177
178 return 1;
179 }
180
181
182 DEVICE_ACCESS(sh4_itlb_da1)
183 {
184 uint32_t mask = SH4_PTEL_SH | SH4_PTEL_C | SH4_PTEL_SZ_MASK |
185 SH4_PTEL_PR_MASK | SH4_PTEL_V | 0x1ffffc00;
186 uint64_t idata = 0, odata = 0;
187 int e = (relative_addr & SH4_ITLB_E_MASK) >> SH4_ITLB_E_SHIFT;
188
189 if (relative_addr & 0x800000) {
190 fatal("sh4_itlb_da1: TODO: da2 area\n");
191 exit(1);
192 }
193
194 if (writeflag == MEM_WRITE) {
195 int safe_to_invalidate = 0;
196 if ((cpu->cd.sh.itlb_lo[e] & SH4_PTEL_SZ_MASK)==SH4_PTEL_SZ_4K)
197 safe_to_invalidate = 1;
198
199 idata = memory_readmax64(cpu, data, len);
200 cpu->cd.sh.itlb_lo[e] &= ~mask;
201 cpu->cd.sh.itlb_lo[e] |= (idata & mask);
202
203 if (safe_to_invalidate)
204 cpu->invalidate_translation_caches(cpu,
205 cpu->cd.sh.itlb_hi[e] & ~0xfff, INVALIDATE_VADDR);
206 else
207 cpu->invalidate_translation_caches(cpu,
208 0, INVALIDATE_ALL);
209 } else {
210 odata = cpu->cd.sh.itlb_lo[e] & mask;
211 memory_writemax64(cpu, data, len, odata);
212 }
213
214 return 1;
215 }
216
217
218 DEVICE_ACCESS(sh4_utlb_aa)
219 {
220 uint64_t idata = 0, odata = 0;
221 int i, e = (relative_addr & SH4_UTLB_E_MASK) >> SH4_UTLB_E_SHIFT;
222 int a = relative_addr & SH4_UTLB_A;
223
224 if (writeflag == MEM_WRITE) {
225 int n_hits = 0;
226 int safe_to_invalidate = 0;
227 uint32_t vaddr_to_invalidate = 0;
228
229 idata = memory_readmax64(cpu, data, len);
230 if (a) {
231 for (i=-SH_N_ITLB_ENTRIES; i<SH_N_UTLB_ENTRIES; i++) {
232 uint32_t lo, hi;
233 uint32_t mask = 0xfffff000;
234 int sh;
235
236 if (i < 0) {
237 lo = cpu->cd.sh.itlb_lo[
238 i + SH_N_ITLB_ENTRIES];
239 hi = cpu->cd.sh.itlb_hi[
240 i + SH_N_ITLB_ENTRIES];
241 } else {
242 lo = cpu->cd.sh.utlb_lo[i];
243 hi = cpu->cd.sh.utlb_hi[i];
244 }
245
246 sh = lo & SH4_PTEL_SH;
247 if (!(lo & SH4_PTEL_V))
248 continue;
249
250 switch (lo & SH4_PTEL_SZ_MASK) {
251 case SH4_PTEL_SZ_1K: mask = 0xfffffc00; break;
252 case SH4_PTEL_SZ_64K: mask = 0xffff0000; break;
253 case SH4_PTEL_SZ_1M: mask = 0xfff00000; break;
254 }
255
256 if ((hi & mask) != (idata & mask))
257 continue;
258
259 if ((lo & SH4_PTEL_SZ_MASK) ==
260 SH4_PTEL_SZ_4K) {
261 safe_to_invalidate = 1;
262 vaddr_to_invalidate = hi & mask;
263 }
264
265 if (!sh && (hi & SH4_PTEH_ASID_MASK) !=
266 (cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK))
267 continue;
268
269 if (i < 0) {
270 cpu->cd.sh.itlb_lo[i] &= ~SH4_PTEL_V;
271 if (idata & SH4_UTLB_AA_V)
272 cpu->cd.sh.itlb_lo[i] |=
273 SH4_PTEL_V;
274 } else {
275 cpu->cd.sh.utlb_lo[i] &=
276 ~(SH4_PTEL_D | SH4_PTEL_V);
277 if (idata & SH4_UTLB_AA_D)
278 cpu->cd.sh.utlb_lo[i] |=
279 SH4_PTEL_D;
280 if (idata & SH4_UTLB_AA_V)
281 cpu->cd.sh.utlb_lo[i] |=
282 SH4_PTEL_V;
283 }
284
285 if (i >= 0)
286 n_hits ++;
287 }
288
289 if (n_hits > 1)
290 sh_exception(cpu,
291 EXPEVT_RESET_TLB_MULTI_HIT, 0, 0);
292 } else {
293 if ((cpu->cd.sh.utlb_lo[e] & SH4_PTEL_SZ_MASK) ==
294 SH4_PTEL_SZ_4K) {
295 safe_to_invalidate = 1;
296 vaddr_to_invalidate =
297 cpu->cd.sh.utlb_hi[e] & ~0xfff;
298 }
299
300 cpu->cd.sh.utlb_hi[e] &=
301 ~(SH4_PTEH_VPN_MASK | SH4_PTEH_ASID_MASK);
302 cpu->cd.sh.utlb_hi[e] |= (idata &
303 (SH4_UTLB_AA_VPN_MASK | SH4_UTLB_AA_ASID_MASK));
304
305 cpu->cd.sh.utlb_lo[e] &= ~(SH4_PTEL_D | SH4_PTEL_V);
306 if (idata & SH4_UTLB_AA_D)
307 cpu->cd.sh.utlb_lo[e] |= SH4_PTEL_D;
308 if (idata & SH4_UTLB_AA_V)
309 cpu->cd.sh.utlb_lo[e] |= SH4_PTEL_V;
310 }
311
312 if (safe_to_invalidate)
313 cpu->invalidate_translation_caches(cpu,
314 vaddr_to_invalidate, INVALIDATE_VADDR);
315 else
316 cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
317 } else {
318 odata = cpu->cd.sh.utlb_hi[e] &
319 (SH4_UTLB_AA_VPN_MASK | SH4_UTLB_AA_ASID_MASK);
320 if (cpu->cd.sh.utlb_lo[e] & SH4_PTEL_D)
321 odata |= SH4_UTLB_AA_D;
322 if (cpu->cd.sh.utlb_lo[e] & SH4_PTEL_V)
323 odata |= SH4_UTLB_AA_V;
324 memory_writemax64(cpu, data, len, odata);
325 }
326
327 return 1;
328 }
329
330
331 DEVICE_ACCESS(sh4_utlb_da1)
332 {
333 uint32_t mask = SH4_PTEL_WT | SH4_PTEL_SH | SH4_PTEL_D | SH4_PTEL_C
334 | SH4_PTEL_SZ_MASK | SH4_PTEL_PR_MASK | SH4_PTEL_V | 0x1ffffc00;
335 uint64_t idata = 0, odata = 0;
336 int e = (relative_addr & SH4_UTLB_E_MASK) >> SH4_UTLB_E_SHIFT;
337
338 if (relative_addr & 0x800000) {
339 fatal("sh4_utlb_da1: TODO: da2 area\n");
340 exit(1);
341 }
342
343 if (writeflag == MEM_WRITE) {
344 int safe_to_invalidate = 0;
345 if ((cpu->cd.sh.utlb_lo[e] & SH4_PTEL_SZ_MASK)==SH4_PTEL_SZ_4K)
346 safe_to_invalidate = 1;
347
348 idata = memory_readmax64(cpu, data, len);
349 cpu->cd.sh.utlb_lo[e] &= ~mask;
350 cpu->cd.sh.utlb_lo[e] |= (idata & mask);
351
352 if (safe_to_invalidate)
353 cpu->invalidate_translation_caches(cpu,
354 cpu->cd.sh.utlb_hi[e] & ~0xfff, INVALIDATE_VADDR);
355 else
356 cpu->invalidate_translation_caches(cpu,
357 0, INVALIDATE_ALL);
358 } else {
359 odata = cpu->cd.sh.utlb_lo[e] & mask;
360 memory_writemax64(cpu, data, len, odata);
361 }
362
363 return 1;
364 }
365
366
367 DEVICE_ACCESS(sh4)
368 {
369 struct sh4_data *d = (struct sh4_data *) extra;
370 uint64_t idata = 0, odata = 0;
371 int timer_nr = 0;
372
373 if (writeflag == MEM_WRITE)
374 idata = memory_readmax64(cpu, data, len);
375
376 relative_addr += SH4_REG_BASE;
377
378 switch (relative_addr) {
379
380 /*************************************************/
381
382 case SH4_PVR_ADDR:
383 odata = cpu->cd.sh.cpu_type.pvr;
384 break;
385
386 case SH4_PRR_ADDR:
387 odata = cpu->cd.sh.cpu_type.prr;
388 break;
389
390 case SH4_PTEH:
391 if (writeflag == MEM_READ)
392 odata = cpu->cd.sh.pteh;
393 else {
394 int old_asid = cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK;
395 cpu->cd.sh.pteh = idata;
396
397 if ((idata & SH4_PTEH_ASID_MASK) != old_asid) {
398 /* TODO: Don't invalidate everything? */
399 cpu->invalidate_translation_caches(
400 cpu, 0, INVALIDATE_ALL);
401 }
402 }
403 break;
404
405 case SH4_PTEL:
406 if (writeflag == MEM_READ)
407 odata = cpu->cd.sh.ptel;
408 else
409 cpu->cd.sh.ptel = idata;
410 break;
411
412 case SH4_TTB:
413 if (writeflag == MEM_READ)
414 odata = cpu->cd.sh.ttb;
415 else
416 cpu->cd.sh.ttb = idata;
417 break;
418
419 case SH4_TEA:
420 if (writeflag == MEM_READ)
421 odata = cpu->cd.sh.tea;
422 else
423 cpu->cd.sh.tea = idata;
424 break;
425
426 case SH4_PTEA:
427 if (writeflag == MEM_READ)
428 odata = cpu->cd.sh.ptea;
429 else
430 cpu->cd.sh.ptea = idata;
431 break;
432
433 case SH4_MMUCR:
434 if (writeflag == MEM_READ) {
435 odata = cpu->cd.sh.mmucr;
436 } else {
437 if (idata & SH4_MMUCR_TI) {
438 /* TLB invalidate. */
439
440 /* TODO: Only invalidate something specific?
441 And not everything? */
442 cpu->invalidate_translation_caches(cpu,
443 0, INVALIDATE_ALL);
444
445 /* Should always read back as 0. */
446 idata &= ~SH4_MMUCR_TI;
447 }
448
449 cpu->cd.sh.mmucr = idata;
450 }
451 break;
452
453 case SH4_CCR:
454 if (writeflag == MEM_READ) {
455 odata = cpu->cd.sh.ccr;
456 } else {
457 cpu->cd.sh.ccr = idata;
458 }
459 break;
460
461 case SH4_QACR0:
462 if (writeflag == MEM_READ) {
463 odata = cpu->cd.sh.qacr0;
464 } else {
465 cpu->cd.sh.qacr0 = idata;
466 }
467 break;
468
469 case SH4_QACR1:
470 if (writeflag == MEM_READ) {
471 odata = cpu->cd.sh.qacr1;
472 } else {
473 cpu->cd.sh.qacr1 = idata;
474 }
475 break;
476
477 case SH4_TRA:
478 if (writeflag == MEM_READ)
479 odata = cpu->cd.sh.tra;
480 else
481 cpu->cd.sh.tra = idata;
482 break;
483
484 case SH4_EXPEVT:
485 if (writeflag == MEM_READ)
486 odata = cpu->cd.sh.expevt;
487 else
488 cpu->cd.sh.expevt = idata;
489 break;
490
491 case SH4_INTEVT:
492 if (writeflag == MEM_READ)
493 odata = cpu->cd.sh.intevt;
494 else
495 cpu->cd.sh.intevt = idata;
496 break;
497
498
499 /********************************/
500 /* UBC: User Break Controller */
501
502 case 0xff200008: /* SH4_BBRA */
503 /* TODO */
504 break;
505
506
507 /********************************/
508 /* TMU: Timer Management Unit */
509
510 case SH4_TOCR:
511 /* Timer Output Control Register */
512 if (writeflag == MEM_WRITE) {
513 d->tocr = idata;
514 if (idata & TOCR_TCOE)
515 fatal("[ sh4 timer: TCOE not yet "
516 "implemented ]\n");
517 } else {
518 odata = d->tocr;
519 }
520 break;
521
522 case SH4_TSTR:
523 /* Timer Start Register */
524 if (writeflag == MEM_READ) {
525 odata = d->tstr;
526 } else {
527 if (idata & 1 && !(d->tstr & 1))
528 debug("[ sh4 timer: starting timer 0 ]\n");
529 if (idata & 2 && !(d->tstr & 2))
530 debug("[ sh4 timer: starting timer 1 ]\n");
531 if (idata & 4 && !(d->tstr & 4))
532 debug("[ sh4 timer: starting timer 2 ]\n");
533 if (!(idata & 1) && d->tstr & 1)
534 debug("[ sh4 timer: stopping timer 0 ]\n");
535 if (!(idata & 2) && d->tstr & 2)
536 debug("[ sh4 timer: stopping timer 1 ]\n");
537 if (!(idata & 4) && d->tstr & 4)
538 debug("[ sh4 timer: stopping timer 2 ]\n");
539 d->tstr = idata;
540 }
541 break;
542
543 case SH4_TCOR2:
544 timer_nr ++;
545 case SH4_TCOR1:
546 timer_nr ++;
547 case SH4_TCOR0:
548 /* Timer Constant Register */
549 if (writeflag == MEM_READ)
550 odata = d->tcor[timer_nr];
551 else
552 d->tcor[timer_nr] = idata;
553 break;
554
555 case SH4_TCNT2:
556 timer_nr ++;
557 case SH4_TCNT1:
558 timer_nr ++;
559 case SH4_TCNT0:
560 /* Timer Counter Register */
561 if (writeflag == MEM_READ)
562 odata = d->tcnt[timer_nr];
563 else
564 d->tcnt[timer_nr] = idata;
565 break;
566
567 case SH4_TCR2:
568 timer_nr ++;
569 case SH4_TCR1:
570 timer_nr ++;
571 case SH4_TCR0:
572 /* Timer Control Register */
573 if (writeflag == MEM_READ) {
574 odata = d->tcr[timer_nr];
575 } else {
576 if (cpu->cd.sh.pclock == 0) {
577 fatal("INTERNAL ERROR: pclock must be set"
578 " for this machine. Aborting.\n");
579 exit(1);
580 }
581
582 switch (idata & 3) {
583 case TCR_TPSC_P4:
584 d->timer_hz[timer_nr] = cpu->cd.sh.pclock/4.0;
585 break;
586 case TCR_TPSC_P16:
587 d->timer_hz[timer_nr] = cpu->cd.sh.pclock/16.0;
588 break;
589 case TCR_TPSC_P64:
590 d->timer_hz[timer_nr] = cpu->cd.sh.pclock/64.0;
591 break;
592 case TCR_TPSC_P256:
593 d->timer_hz[timer_nr] = cpu->cd.sh.pclock/256.0;
594 break;
595 }
596
597 debug("[ sh4 timer %i clock set to %f Hz ]\n",
598 timer_nr, d->timer_hz[timer_nr]);
599
600 if (idata & (TCR_ICPF | TCR_ICPE1 | TCR_ICPE0 |
601 TCR_CKEG1 | TCR_CKEG0 | TCR_TPSC2)) {
602 fatal("Unimplemented SH4 timer control"
603 " bits: 0x%08"PRIx32". Aborting.\n",
604 (int) idata);
605 exit(1);
606 }
607
608 if (d->tcr[timer_nr] & TCR_UNF && !(idata & TCR_UNF)) {
609 cpu_interrupt_ack(cpu, SH_INTEVT_TMU0_TUNI0
610 + 0x20 * timer_nr);
611 if (d->timer_interrupts_pending[timer_nr] > 0)
612 d->timer_interrupts_pending[timer_nr]--;
613 }
614
615 d->tcr[timer_nr] = idata;
616 }
617 break;
618
619
620 /*************************************************/
621 /* BSC: Bus State Controller */
622
623 case SH4_RFCR:
624 /* TODO */
625 fatal("[ SH4_RFCR: TODO ]\n");
626 odata = 0x11;
627 break;
628
629 #if 0
630 case SH4_UNKNOWN_2C:
631 /* Not really part of the BSC? The 2C and 30 registers
632 have to do with I/O pins... TODO */
633 /*
634 * TODO: Perhaps this isn't actually part of the Bus State
635 * controller? Marcus Comstedt's video.s tutorial on
636 * how to output video on the Dreamcast indicates that
637 * this is a way to sense which video cable is
638 * connected.
639 */
640 if (writeflag == MEM_WRITE) {
641 d->unknown_2c = idata;
642 d->unknown_30 = idata;
643 } else
644 odata = d->unknown_2c;
645 break;
646 #endif
647
648 #if 1
649 case SH4_UNKNOWN_30:
650 if (writeflag == MEM_WRITE)
651 d->unknown_30 = idata;
652 else {
653 odata = d->unknown_30;
654
655 /* SUPER-UGLY HACK! TODO */
656 d->unknown_30 ++;
657 }
658 break;
659 #endif
660
661
662 /*********************************/
663 /* INTC: Interrupt Controller */
664
665 case SH4_ICR:
666 if (writeflag == MEM_WRITE) {
667 if (idata & 0x80) {
668 fatal("SH4 INTC: IRLM not yet "
669 "supported. TODO\n");
670 exit(1);
671 }
672 }
673 break;
674
675 case SH4_IPRA:
676 if (writeflag == MEM_READ)
677 odata = cpu->cd.sh.intc_ipra;
678 else
679 cpu->cd.sh.intc_ipra = idata;
680 break;
681
682 case SH4_IPRB:
683 if (writeflag == MEM_READ)
684 odata = cpu->cd.sh.intc_iprb;
685 else
686 cpu->cd.sh.intc_iprb = idata;
687 break;
688
689 case SH4_IPRC:
690 if (writeflag == MEM_READ)
691 odata = cpu->cd.sh.intc_iprc;
692 else
693 cpu->cd.sh.intc_iprc = idata;
694 break;
695
696
697 /*************************************************/
698 /* SCIF: Serial Controller Interface with FIFO */
699
700 case SH4_SCIF_BASE + SCIF_FTDR:
701 if (writeflag == MEM_WRITE)
702 console_putchar(d->scif_console_handle, idata);
703 break;
704
705 case SH4_SCIF_BASE + SCIF_SSR:
706 /* TODO: Implement more of this. */
707 odata = SCSSR2_TDFE | SCSSR2_TEND;
708 if (console_charavail(d->scif_console_handle))
709 odata |= SCSSR2_DR;
710 break;
711
712 case SH4_SCIF_BASE + SCIF_FRDR:
713 {
714 int x = console_readchar(d->scif_console_handle);
715 if (x == 13)
716 x = 10;
717 odata = x < 0? 0 : x;
718 }
719 break;
720
721 case SH4_SCIF_BASE + SCIF_FDR:
722 odata = console_charavail(d->scif_console_handle);
723 break;
724
725 /*************************************************/
726
727 default:if (writeflag == MEM_READ) {
728 fatal("[ sh4: read from addr 0x%x ]\n",
729 (int)relative_addr);
730 } else {
731 fatal("[ sh4: write to addr 0x%x: 0x%x ]\n",
732 (int)relative_addr, (int)idata);
733 }
734 }
735
736 if (writeflag == MEM_READ)
737 memory_writemax64(cpu, data, len, odata);
738
739 return 1;
740 }
741
742
743 DEVINIT(sh4)
744 {
745 struct machine *machine = devinit->machine;
746 struct sh4_data *d = malloc(sizeof(struct sh4_data));
747 if (d == NULL) {
748 fprintf(stderr, "out of memory\n");
749 exit(1);
750 }
751 memset(d, 0, sizeof(struct sh4_data));
752
753 d->scif_console_handle = console_start_slave(devinit->machine,
754 "SH4 SCIF", 1);
755
756 memory_device_register(machine->memory, devinit->name,
757 SH4_REG_BASE, 0x01000000, dev_sh4_access, d, DM_DEFAULT, NULL);
758
759 /* On-chip RAM/cache: */
760 dev_ram_init(machine, 0x1e000000, 0x8000, DEV_RAM_RAM, 0x0);
761
762 /* 0xe0000000: Store queues: */
763 dev_ram_init(machine, 0xe0000000, 32 * 2, DEV_RAM_RAM, 0x0);
764
765 /*
766 * 0xf0000000 SH4_CCIA I-Cache address array
767 * 0xf1000000 SH4_CCID I-Cache data array
768 * 0xf4000000 SH4_CCDA D-Cache address array
769 * 0xf5000000 SH4_CCDD D-Cache data array
770 *
771 * TODO: Implement more correct cache behaviour?
772 */
773 dev_ram_init(machine, SH4_CCIA, SH4_ICACHE_SIZE, DEV_RAM_RAM, 0x0);
774 dev_ram_init(machine, SH4_CCID, SH4_ICACHE_SIZE, DEV_RAM_RAM, 0x0);
775 dev_ram_init(machine, SH4_CCDA, SH4_DCACHE_SIZE, DEV_RAM_RAM, 0x0);
776 dev_ram_init(machine, SH4_CCDD, SH4_DCACHE_SIZE, DEV_RAM_RAM, 0x0);
777
778 /* 0xf2000000 SH4_ITLB_AA */
779 memory_device_register(machine->memory, devinit->name, SH4_ITLB_AA,
780 0x01000000, dev_sh4_itlb_aa_access, d, DM_DEFAULT, NULL);
781
782 /* 0xf3000000 SH4_ITLB_DA1 */
783 memory_device_register(machine->memory, devinit->name, SH4_ITLB_DA1,
784 0x01000000, dev_sh4_itlb_da1_access, d, DM_DEFAULT, NULL);
785
786 /* 0xf6000000 SH4_UTLB_AA */
787 memory_device_register(machine->memory, devinit->name, SH4_UTLB_AA,
788 0x01000000, dev_sh4_utlb_aa_access, d, DM_DEFAULT, NULL);
789
790 /* 0xf7000000 SH4_UTLB_DA1 */
791 memory_device_register(machine->memory, devinit->name, SH4_UTLB_DA1,
792 0x01000000, dev_sh4_utlb_da1_access, d, DM_DEFAULT, NULL);
793
794 d->sh4_timer = timer_add(SH4_PSEUDO_TIMER_HZ, sh4_timer_tick, d);
795 machine_add_tickfunction(devinit->machine, dev_sh4_tick, d,
796 SH4_TICK_SHIFT, 0.0);
797
798 /* Initial Timer values, according to the SH7750 manual: */
799 d->tcor[0] = 0xffffffff; d->tcnt[0] = 0xffffffff;
800 d->tcor[1] = 0xffffffff; d->tcnt[1] = 0xffffffff;
801 d->tcor[2] = 0xffffffff; d->tcnt[2] = 0xffffffff;
802
803 return 1;
804 }
805

  ViewVC Help
Powered by ViewVC 1.1.26