latest version of musashi engine includes floating point emulation (plus a few patches to add in missing opcodes needed by ack - see tags JFF & TBB) added a few missing linux syscalls in sim.c pascal now runs pretty well quick test with modula2 passes c gets the floating point numbers wrong, so more work needed here other languages untested plat/linux68k/emu/build.lua is probably not quite right - the softfloat directory is compiled in the wrong place
		
			
				
	
	
		
			321 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			321 lines
		
	
	
	
		
			8.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
    m68kmmu.h - PMMU implementation for 68851/68030/68040
 | 
						|
 | 
						|
    By R. Belmont
 | 
						|
 | 
						|
    Copyright Nicola Salmoria and the MAME Team.
 | 
						|
    Visit http://mamedev.org for licensing and usage restrictions.
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
	pmmu_translate_addr: perform 68851/68030-style PMMU address translation
 | 
						|
*/
 | 
						|
uint pmmu_translate_addr(uint addr_in)
 | 
						|
{
 | 
						|
	uint32 addr_out, tbl_entry = 0, tbl_entry2, tamode = 0, tbmode = 0, tcmode = 0;
 | 
						|
	uint root_aptr, root_limit, tofs, is, abits, bbits, cbits;
 | 
						|
	uint resolved, tptr, shift;
 | 
						|
 | 
						|
	resolved = 0;
 | 
						|
	addr_out = addr_in;
 | 
						|
 | 
						|
	// if SRP is enabled and we're in supervisor mode, use it
 | 
						|
	if ((m68ki_cpu.mmu_tc & 0x02000000) && (m68ki_get_sr() & 0x2000))
 | 
						|
	{
 | 
						|
		root_aptr = m68ki_cpu.mmu_srp_aptr;
 | 
						|
		root_limit = m68ki_cpu.mmu_srp_limit;
 | 
						|
	}
 | 
						|
	else	// else use the CRP
 | 
						|
	{
 | 
						|
		root_aptr = m68ki_cpu.mmu_crp_aptr;
 | 
						|
		root_limit = m68ki_cpu.mmu_crp_limit;
 | 
						|
	}
 | 
						|
 | 
						|
	// get initial shift (# of top bits to ignore)
 | 
						|
	is = (m68ki_cpu.mmu_tc>>16) & 0xf;
 | 
						|
	abits = (m68ki_cpu.mmu_tc>>12)&0xf;
 | 
						|
	bbits = (m68ki_cpu.mmu_tc>>8)&0xf;
 | 
						|
	cbits = (m68ki_cpu.mmu_tc>>4)&0xf;
 | 
						|
 | 
						|
//	fprintf(stderr,"PMMU: tcr %08x limit %08x aptr %08x is %x abits %d bbits %d cbits %d\n", m68ki_cpu.mmu_tc, root_limit, root_aptr, is, abits, bbits, cbits);
 | 
						|
 | 
						|
	// get table A offset
 | 
						|
	tofs = (addr_in<<is)>>(32-abits);
 | 
						|
 | 
						|
	// find out what format table A is
 | 
						|
	switch (root_limit & 3)
 | 
						|
	{
 | 
						|
		case 0:	// invalid, should cause MMU exception
 | 
						|
		case 1:	// page descriptor, should cause direct mapping
 | 
						|
			fatalerror("680x0 PMMU: Unhandled root mode\n");
 | 
						|
			break;
 | 
						|
 | 
						|
		case 2:	// valid 4 byte descriptors
 | 
						|
			tofs *= 4;
 | 
						|
//			fprintf(stderr,"PMMU: reading table A entry at %08x\n", tofs + (root_aptr & 0xfffffffc));
 | 
						|
			tbl_entry = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc));
 | 
						|
			tamode = tbl_entry & 3;
 | 
						|
//			fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 3: // valid 8 byte descriptors
 | 
						|
			tofs *= 8;
 | 
						|
//			fprintf(stderr,"PMMU: reading table A entries at %08x\n", tofs + (root_aptr & 0xfffffffc));
 | 
						|
			tbl_entry2 = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc));
 | 
						|
			tbl_entry = m68k_read_memory_32( tofs + (root_aptr & 0xfffffffc)+4);
 | 
						|
			tamode = tbl_entry2 & 3;
 | 
						|
//			fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs);
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	// get table B offset and pointer
 | 
						|
	tofs = (addr_in<<(is+abits))>>(32-bbits);
 | 
						|
	tptr = tbl_entry & 0xfffffff0;
 | 
						|
 | 
						|
	// find out what format table B is, if any
 | 
						|
	switch (tamode)
 | 
						|
	{
 | 
						|
		case 0: // invalid, should cause MMU exception
 | 
						|
			fatalerror("680x0 PMMU: Unhandled Table A mode %d (addr_in %08x)\n", tamode, addr_in);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 2: // 4-byte table B descriptor
 | 
						|
			tofs *= 4;
 | 
						|
//			fprintf(stderr,"PMMU: reading table B entry at %08x\n", tofs + tptr);
 | 
						|
			tbl_entry = m68k_read_memory_32( tofs + tptr);
 | 
						|
			tbmode = tbl_entry & 3;
 | 
						|
//			fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 3: // 8-byte table B descriptor
 | 
						|
			tofs *= 8;
 | 
						|
//			fprintf(stderr,"PMMU: reading table B entries at %08x\n", tofs + tptr);
 | 
						|
			tbl_entry2 = m68k_read_memory_32( tofs + tptr);
 | 
						|
			tbl_entry = m68k_read_memory_32( tofs + tptr + 4);
 | 
						|
			tbmode = tbl_entry2 & 3;
 | 
						|
//			fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
 | 
						|
			break;
 | 
						|
 | 
						|
		case 1:	// early termination descriptor
 | 
						|
			tbl_entry &= 0xffffff00;
 | 
						|
 | 
						|
			shift = is+abits;
 | 
						|
			addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
 | 
						|
			resolved = 1;
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	// if table A wasn't early-out, continue to process table B
 | 
						|
	if (!resolved)
 | 
						|
	{
 | 
						|
		// get table C offset and pointer
 | 
						|
		tofs = (addr_in<<(is+abits+bbits))>>(32-cbits);
 | 
						|
		tptr = tbl_entry & 0xfffffff0;
 | 
						|
 | 
						|
		switch (tbmode)
 | 
						|
		{
 | 
						|
			case 0:	// invalid, should cause MMU exception
 | 
						|
				fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, REG_PC);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 2: // 4-byte table C descriptor
 | 
						|
				tofs *= 4;
 | 
						|
//				fprintf(stderr,"PMMU: reading table C entry at %08x\n", tofs + tptr);
 | 
						|
				tbl_entry = m68k_read_memory_32(tofs + tptr);
 | 
						|
				tcmode = tbl_entry & 3;
 | 
						|
//				fprintf(stderr,"PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 3: // 8-byte table C descriptor
 | 
						|
				tofs *= 8;
 | 
						|
//				fprintf(stderr,"PMMU: reading table C entries at %08x\n", tofs + tptr);
 | 
						|
				tbl_entry2 = m68k_read_memory_32(tofs + tptr);
 | 
						|
				tbl_entry = m68k_read_memory_32(tofs + tptr + 4);
 | 
						|
				tcmode = tbl_entry2 & 3;
 | 
						|
//				fprintf(stderr,"PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 1: // termination descriptor
 | 
						|
				tbl_entry &= 0xffffff00;
 | 
						|
 | 
						|
				shift = is+abits+bbits;
 | 
						|
				addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
 | 
						|
				resolved = 1;
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!resolved)
 | 
						|
	{
 | 
						|
		switch (tcmode)
 | 
						|
		{
 | 
						|
			case 0:	// invalid, should cause MMU exception
 | 
						|
			case 2: // 4-byte ??? descriptor
 | 
						|
			case 3: // 8-byte ??? descriptor
 | 
						|
				fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, REG_PC);
 | 
						|
				break;
 | 
						|
 | 
						|
			case 1: // termination descriptor
 | 
						|
				tbl_entry &= 0xffffff00;
 | 
						|
 | 
						|
				shift = is+abits+bbits+cbits;
 | 
						|
				addr_out = ((addr_in<<shift)>>shift) + tbl_entry;
 | 
						|
				resolved = 1;
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
//	fprintf(stderr,"PMMU: [%08x] => [%08x]\n", addr_in, addr_out);
 | 
						|
 | 
						|
	return addr_out;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 | 
						|
	m68881_mmu_ops: COP 0 MMU opcode handling
 | 
						|
 | 
						|
*/
 | 
						|
 | 
						|
void m68881_mmu_ops()
 | 
						|
{
 | 
						|
	uint16 modes;
 | 
						|
	uint32 ea = m68ki_cpu.ir & 0x3f;
 | 
						|
	uint64 temp64;
 | 
						|
 | 
						|
	// catch the 2 "weird" encodings up front (PBcc)
 | 
						|
	if ((m68ki_cpu.ir & 0xffc0) == 0xf0c0)
 | 
						|
	{
 | 
						|
		fprintf(stderr,"680x0: unhandled PBcc\n");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	else if ((m68ki_cpu.ir & 0xffc0) == 0xf080)
 | 
						|
	{
 | 
						|
		fprintf(stderr,"680x0: unhandled PBcc\n");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	else	// the rest are 1111000xxxXXXXXX where xxx is the instruction family
 | 
						|
	{
 | 
						|
		switch ((m68ki_cpu.ir>>9) & 0x7)
 | 
						|
		{
 | 
						|
			case 0:
 | 
						|
				modes = OPER_I_16();
 | 
						|
 | 
						|
				if ((modes & 0xfde0) == 0x2000)	// PLOAD
 | 
						|
				{
 | 
						|
					fprintf(stderr,"680x0: unhandled PLOAD\n");
 | 
						|
					return;
 | 
						|
				}
 | 
						|
				else if ((modes & 0xe200) == 0x2000)	// PFLUSH
 | 
						|
				{
 | 
						|
					fprintf(stderr,"680x0: unhandled PFLUSH PC=%x\n", REG_PC);
 | 
						|
					return;
 | 
						|
				}
 | 
						|
				else if (modes == 0xa000)	// PFLUSHR
 | 
						|
				{
 | 
						|
					fprintf(stderr,"680x0: unhandled PFLUSHR\n");
 | 
						|
					return;
 | 
						|
				}
 | 
						|
				else if (modes == 0x2800)	// PVALID (FORMAT 1)
 | 
						|
				{
 | 
						|
					fprintf(stderr,"680x0: unhandled PVALID1\n");
 | 
						|
					return;
 | 
						|
				}
 | 
						|
				else if ((modes & 0xfff8) == 0x2c00)	// PVALID (FORMAT 2)
 | 
						|
				{
 | 
						|
					fprintf(stderr,"680x0: unhandled PVALID2\n");
 | 
						|
					return;
 | 
						|
				}
 | 
						|
				else if ((modes & 0xe000) == 0x8000)	// PTEST
 | 
						|
				{
 | 
						|
					fprintf(stderr,"680x0: unhandled PTEST\n");
 | 
						|
					return;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					switch ((modes>>13) & 0x7)
 | 
						|
					{
 | 
						|
						case 0:	// MC68030/040 form with FD bit
 | 
						|
						case 2:	// MC68881 form, FD never set
 | 
						|
							if (modes & 0x200)
 | 
						|
							{
 | 
						|
							 	switch ((modes>>10) & 7)
 | 
						|
								{
 | 
						|
									case 0:	// translation control register
 | 
						|
										WRITE_EA_32(ea, m68ki_cpu.mmu_tc);
 | 
						|
										break;
 | 
						|
 | 
						|
									case 2: // supervisor root pointer
 | 
						|
										WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_srp_limit<<32 | (uint64)m68ki_cpu.mmu_srp_aptr);
 | 
						|
										break;
 | 
						|
 | 
						|
									case 3: // CPU root pointer
 | 
						|
										WRITE_EA_64(ea, (uint64)m68ki_cpu.mmu_crp_limit<<32 | (uint64)m68ki_cpu.mmu_crp_aptr);
 | 
						|
										break;
 | 
						|
 | 
						|
									default:
 | 
						|
										fprintf(stderr,"680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, REG_PC);
 | 
						|
										break;
 | 
						|
								}
 | 
						|
							}
 | 
						|
							else
 | 
						|
							{
 | 
						|
							 	switch ((modes>>10) & 7)
 | 
						|
								{
 | 
						|
									case 0:	// translation control register
 | 
						|
										m68ki_cpu.mmu_tc = READ_EA_32(ea);
 | 
						|
 | 
						|
										if (m68ki_cpu.mmu_tc & 0x80000000)
 | 
						|
										{
 | 
						|
											m68ki_cpu.pmmu_enabled = 1;
 | 
						|
										}
 | 
						|
										else
 | 
						|
										{
 | 
						|
											m68ki_cpu.pmmu_enabled = 0;
 | 
						|
										}
 | 
						|
										break;
 | 
						|
 | 
						|
									case 2:	// supervisor root pointer
 | 
						|
										temp64 = READ_EA_64(ea);
 | 
						|
										m68ki_cpu.mmu_srp_limit = (temp64>>32) & 0xffffffff;
 | 
						|
										m68ki_cpu.mmu_srp_aptr = temp64 & 0xffffffff;
 | 
						|
										break;
 | 
						|
 | 
						|
									case 3:	// CPU root pointer
 | 
						|
										temp64 = READ_EA_64(ea);
 | 
						|
										m68ki_cpu.mmu_crp_limit = (temp64>>32) & 0xffffffff;
 | 
						|
										m68ki_cpu.mmu_crp_aptr = temp64 & 0xffffffff;
 | 
						|
										break;
 | 
						|
 | 
						|
									default:
 | 
						|
										fprintf(stderr,"680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, REG_PC);
 | 
						|
										break;
 | 
						|
								}
 | 
						|
							}
 | 
						|
							break;
 | 
						|
 | 
						|
						case 3:	// MC68030 to/from status reg
 | 
						|
							if (modes & 0x200)
 | 
						|
							{
 | 
						|
								WRITE_EA_32(ea, m68ki_cpu.mmu_sr);
 | 
						|
							}
 | 
						|
							else
 | 
						|
							{
 | 
						|
								m68ki_cpu.mmu_sr = READ_EA_32(ea);
 | 
						|
							}
 | 
						|
							break;
 | 
						|
 | 
						|
						default:
 | 
						|
							fprintf(stderr,"680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, REG_PC);
 | 
						|
							break;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			default:
 | 
						|
				fprintf(stderr,"680x0: unknown PMMU instruction group %d\n", (m68ki_cpu.ir>>9) & 0x7);
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 |