mirror of
				https://github.com/TomHarte/CLK.git
				synced 2025-10-30 14:16:04 +00:00 
			
		
		
		
	Compare commits
	
		
			26 Commits
		
	
	
		
			OptionalFu
			...
			OpDumper
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | f8eb7dd015 | ||
|  | 716153cf0a | ||
|  | 821b5358ea | ||
|  | fa1139acb3 | ||
|  | 3a42b0ac3d | ||
|  | 14ff3162cf | ||
|  | 768f47198f | ||
|  | b4bb7cdaf9 | ||
|  | 3673f931b8 | ||
|  | 3dce673b37 | ||
|  | f7932d8583 | ||
|  | b6c91035f4 | ||
|  | 7f030bc282 | ||
|  | 32f946b3f0 | ||
|  | 939f015007 | ||
|  | 20d54c0397 | ||
|  | 950fddebf9 | ||
|  | 47d5d65633 | ||
|  | be1cec8f55 | ||
|  | 6207f2ab41 | ||
|  | e30a02a0c0 | ||
|  | c7097274c9 | ||
|  | e82f2a3810 | ||
|  | cbf6ae81d0 | ||
|  | 7a6fab72fe | ||
|  | 4005506e42 | 
| @@ -31,6 +31,8 @@ namespace MC68000 { | ||||
| #define d8PCXn	0x13 | ||||
| #define Imm		0x14 | ||||
|  | ||||
| #define Quick	0x20 | ||||
|  | ||||
| struct ProcessorStorageConstructor { | ||||
| 	ProcessorStorageConstructor(ProcessorStorage &storage) : storage_(storage) {} | ||||
|  | ||||
| @@ -479,6 +481,7 @@ struct ProcessorStorageConstructor { | ||||
| 		assert(value == values.end()); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	/*! | ||||
| 		Disassembles the instruction @c instruction and inserts it into the | ||||
| 		appropriate lookup tables. | ||||
| @@ -837,14 +840,331 @@ struct ProcessorStorageConstructor { | ||||
| #define bw(x)		(x) | ||||
| #define l(x)		(0x10000 | (x)) | ||||
|  | ||||
| #define NoOperand ~0 | ||||
| 		struct InstructionDumper { | ||||
| 			public: | ||||
| 				InstructionDumper(uint16_t opcode) : | ||||
| 					opcode_(opcode) {} | ||||
|  | ||||
| 				~InstructionDumper() { | ||||
| 					const char *opname = "???"; | ||||
| 					if(opcode_ == 0x4e71) { | ||||
| 						opname = "NOP"; | ||||
| 					} else { | ||||
| 						switch(operation_) { | ||||
| 							default: | ||||
| 								printf("%d\n", int(operation_)); | ||||
| 								assert(false); | ||||
| 							break; | ||||
| #define DirectMap(x)	case Operation::x:	opname = #x;	break | ||||
|  | ||||
| 							DirectMap(None); | ||||
| 							DirectMap(ABCD); | ||||
| 							DirectMap(SBCD); | ||||
| 							DirectMap(NBCD); | ||||
|  | ||||
| 							case Operation::ADDQb: | ||||
| 							case Operation::ADDb:	opname = "ADD.b";	break; | ||||
| 							case Operation::ADDQw: | ||||
| 							case Operation::ADDw:	opname = "ADD.w";	break; | ||||
| 							case Operation::ADDQl: | ||||
| 							case Operation::ADDl:	opname = "ADD.l";	break; | ||||
| 							case Operation::ADDQAw: | ||||
| 							case Operation::ADDAw:	opname = "ADDA.w";	break; | ||||
| 							case Operation::ADDQAl: | ||||
| 							case Operation::ADDAl:	opname = "ADDA.l";	break; | ||||
| 							case Operation::ADDXb:	opname = "ADDX.b";	break; | ||||
| 							case Operation::ADDXw:	opname = "ADDX.w";	break; | ||||
| 							case Operation::ADDXl:	opname = "ADDX.l";	break; | ||||
|  | ||||
| 							case Operation::SUBQb: | ||||
| 							case Operation::SUBb:	opname = "SUB.b";	break; | ||||
| 							case Operation::SUBQw: | ||||
| 							case Operation::SUBw:	opname = "SUB.w";	break; | ||||
| 							case Operation::SUBQl: | ||||
| 							case Operation::SUBl:	opname = "SUB.l";	break; | ||||
| 							case Operation::SUBQAw: | ||||
| 							case Operation::SUBAw:	opname = "SUBA.w";	break; | ||||
| 							case Operation::SUBQAl: | ||||
| 							case Operation::SUBAl:	opname = "SUBA.l";	break; | ||||
| 							case Operation::SUBXb:	opname = "SUBX.b";	break; | ||||
| 							case Operation::SUBXw:	opname = "SUBX.w";	break; | ||||
| 							case Operation::SUBXl:	opname = "SUBX.l";	break; | ||||
|  | ||||
| 							case Operation::MOVEb:	opname = "MOVE.b";	break; | ||||
| 							case Operation::MOVEw:	opname = "MOVE.w";	break; | ||||
| 							case Operation::MOVEl:	opname = "MOVE.l";	break; | ||||
| 							case Operation::MOVEq:	opname = "MOVE.q";	break; | ||||
|  | ||||
| 							case Operation::MOVEAw:	opname = "MOVEA.w";	break; | ||||
| 							case Operation::MOVEAl: | ||||
| 								// A bunch of things are multiplexed onto MOVEA.l; | ||||
| 								// disambiguate here. | ||||
| 								if((opcode_ & 0xf1c0) == 0x41c0) { | ||||
| 									opname = "LEA"; | ||||
| 								} else if ((opcode_ & 0xfff8) == 0x4e68) { | ||||
| 									opname = "MOVEfromUSP"; | ||||
| 								} else if ((opcode_ & 0xfff8) == 0x4e60) { | ||||
| 									opname = "MOVEtoUSP"; | ||||
| 								} else { | ||||
| 									opname = "MOVEA.l"; | ||||
| 								} | ||||
| 							break; | ||||
|  | ||||
| 							case Operation::PEA:	opname = "PEA";		break; | ||||
|  | ||||
| 							DirectMap(MOVEtoSR); | ||||
| 							DirectMap(MOVEfromSR); | ||||
| 							DirectMap(MOVEtoCCR); | ||||
|  | ||||
| 							DirectMap(ORItoSR); | ||||
| 							DirectMap(ORItoCCR); | ||||
| 							DirectMap(ANDItoSR); | ||||
| 							DirectMap(ANDItoCCR); | ||||
| 							DirectMap(EORItoSR); | ||||
| 							DirectMap(EORItoCCR); | ||||
|  | ||||
| 							case Operation::BTSTb:	opname = "BTST";	break; | ||||
| 							case Operation::BTSTl:	opname = "BTST";	break; | ||||
| 							case Operation::BCLRb:	opname = "BCLR";	break; | ||||
| 							case Operation::BCLRl:	opname = "BCLR";	break; | ||||
|  | ||||
| 							case Operation::CMPb:	opname = "CMP.b";	break; | ||||
| 							case Operation::CMPw: | ||||
| 								opname = "CMP.w"; | ||||
| 							break; | ||||
| 							case Operation::CMPl: | ||||
| 								opname = (dest_ == An) ? "CMPA.l" : "CMP.l"; | ||||
| 							break; | ||||
| 							case Operation::CMPAw:	opname = "CMPA.w";	break; | ||||
| 							case Operation::TSTb:	opname = "TST.b";	break; | ||||
| 							case Operation::TSTw:	opname = "TST.w";	break; | ||||
| 							case Operation::TSTl:	opname = "TST.l";	break; | ||||
|  | ||||
| 							case Operation::JMP: | ||||
| 								if(opcode_ & 0x40) { | ||||
| 									opname = "JMP"; | ||||
| 								} else { | ||||
| 									opname = "JSR"; | ||||
| 								} | ||||
| 							break; | ||||
| 							case Operation::Bcc: | ||||
| 								if((opcode_ & 0xf00) == 0x100) { | ||||
| 									opname = "BSR"; | ||||
| 								} else { | ||||
| 									opname = "Bcc"; | ||||
| 								} | ||||
| 							break; | ||||
|  | ||||
| 							DirectMap(RTS); | ||||
| 							DirectMap(BRA); | ||||
| 							DirectMap(DBcc); | ||||
| 							DirectMap(Scc); | ||||
|  | ||||
| 							case Operation::CLRb:	opname = "CLR.b";	break; | ||||
| 							case Operation::CLRw:	opname = "CLR.w";	break; | ||||
| 							case Operation::CLRl:	opname = "CLR.l";	break; | ||||
|  | ||||
| 							case Operation::NEGXb:	opname = "NEGX.b";	break; | ||||
| 							case Operation::NEGXw:	opname = "NEGX.w";	break; | ||||
| 							case Operation::NEGXl:	opname = "NEGX.l";	break; | ||||
|  | ||||
| 							case Operation::NEGb:	opname = "NEG.b";	break; | ||||
| 							case Operation::NEGw:	opname = "NEG.w";	break; | ||||
| 							case Operation::NEGl:	opname = "NEG.l";	break; | ||||
|  | ||||
| 							case Operation::ASLb:	opname = "ASL.b";	break; | ||||
| 							case Operation::ASLm: | ||||
| 							case Operation::ASLw:	opname = "ASL.w";	break; | ||||
| 							case Operation::ASLl:	opname = "ASL.l";	break; | ||||
|  | ||||
| 							case Operation::ASRb:	opname = "ASR.b";	break; | ||||
| 							case Operation::ASRm: | ||||
| 							case Operation::ASRw:	opname = "ASR.w";	break; | ||||
| 							case Operation::ASRl:	opname = "ASR.l";	break; | ||||
|  | ||||
| 							case Operation::LSLb:	opname = "LSL.b";	break; | ||||
| 							case Operation::LSLm: | ||||
| 							case Operation::LSLw:	opname = "LSL.w";	break; | ||||
| 							case Operation::LSLl:	opname = "LSL.l";	break; | ||||
|  | ||||
| 							case Operation::LSRb:	opname = "LSR.b";	break; | ||||
| 							case Operation::LSRm: | ||||
| 							case Operation::LSRw:	opname = "LSR.w";	break; | ||||
| 							case Operation::LSRl:	opname = "LSR.l";	break; | ||||
|  | ||||
| 							case Operation::ROLb:	opname = "ROL.b";	break; | ||||
| 							case Operation::ROLm: | ||||
| 							case Operation::ROLw:	opname = "ROL.w";	break; | ||||
| 							case Operation::ROLl:	opname = "ROL.l";	break; | ||||
|  | ||||
| 							case Operation::RORb:	opname = "ROR.b";	break; | ||||
| 							case Operation::RORm: | ||||
| 							case Operation::RORw:	opname = "ROR.w";	break; | ||||
| 							case Operation::RORl:	opname = "ROR.l";	break; | ||||
|  | ||||
| 							case Operation::ROXLb:	opname = "ROXL.b";	break; | ||||
| 							case Operation::ROXLm: | ||||
| 							case Operation::ROXLw:	opname = "ROXL.w";	break; | ||||
| 							case Operation::ROXLl:	opname = "ROXL.l";	break; | ||||
|  | ||||
| 							case Operation::ROXRb:	opname = "ROXR.b";	break; | ||||
| 							case Operation::ROXRm: | ||||
| 							case Operation::ROXRw:	opname = "ROXR.w";	break; | ||||
| 							case Operation::ROXRl:	opname = "ROXR.l";	break; | ||||
|  | ||||
| 							case Operation::MOVEMtoMl: | ||||
| 							case Operation::MOVEMtoRl:	opname = "MOVEM.l";	break; | ||||
| 							case Operation::MOVEMtoMw: | ||||
| 							case Operation::MOVEMtoRw:	opname = "MOVEM.w";	break; | ||||
|  | ||||
| 							case Operation::MOVEPtoMl: | ||||
| 							case Operation::MOVEPtoRl:	opname = "MOVEP.l";	break; | ||||
| 							case Operation::MOVEPtoMw: | ||||
| 							case Operation::MOVEPtoRw:	opname = "MOVEP.w";	break; | ||||
|  | ||||
| 	//						DirectMap(MOVEMtoRl); | ||||
| 	//						DirectMap(MOVEMtoRw); | ||||
| 	//						DirectMap(MOVEMtoMl); | ||||
| 	//						DirectMap(MOVEMtoMw); | ||||
|  | ||||
| 							case Operation::ANDb:	opname = "AND.b";	break; | ||||
| 							case Operation::ANDw:	opname = "AND.w";	break; | ||||
| 							case Operation::ANDl:	opname = "AND.l";	break; | ||||
|  | ||||
| 							case Operation::EORb:	opname = "EOR.b";	break; | ||||
| 							case Operation::EORw:	opname = "EOR.w";	break; | ||||
| 							case Operation::EORl:	opname = "EOR.l";	break; | ||||
|  | ||||
| 							case Operation::NOTb:	opname = "NOT.b";	break; | ||||
| 							case Operation::NOTw:	opname = "NOT.w";	break; | ||||
| 							case Operation::NOTl:	opname = "NOT.l";	break; | ||||
|  | ||||
| 							case Operation::ORb:	opname = "OR.b";	break; | ||||
| 							case Operation::ORw:	opname = "OR.w";	break; | ||||
| 							case Operation::ORl:	opname = "OR.l";	break; | ||||
|  | ||||
| 							DirectMap(MULU); | ||||
| 							DirectMap(MULS); | ||||
| 							DirectMap(DIVU); | ||||
| 							DirectMap(DIVS); | ||||
|  | ||||
| 							case Operation::RTE_RTR: | ||||
| 								opname = (opcode_ == 0x4e77) ? "RTR" : "RTE"; | ||||
| 							break; | ||||
|  | ||||
| 							DirectMap(TRAP); | ||||
| 							DirectMap(TRAPV); | ||||
| 							DirectMap(CHK); | ||||
| 							DirectMap(EXG); | ||||
| 							DirectMap(SWAP); | ||||
|  | ||||
| 							case Operation::BCHGb:	opname = "BCHG";	break; | ||||
| 							case Operation::BCHGl:	opname = "BCHG";	break; | ||||
| 							case Operation::BSETb:	opname = "BSET";	break; | ||||
| 							case Operation::BSETl:	opname = "BSET";	break; | ||||
|  | ||||
| 							DirectMap(TAS); | ||||
| 							case Operation::EXTbtow:	opname = "EXT.w";	break; | ||||
| 							case Operation::EXTwtol:	opname = "EXT.l";	break; | ||||
| 							DirectMap(LINK); | ||||
| 							DirectMap(UNLINK); | ||||
| 							DirectMap(STOP); | ||||
| 						} | ||||
| 					} | ||||
| #undef DirectMap | ||||
|  | ||||
| 					printf("\"%04x\": \"%s", opcode_, opname); | ||||
| 					if(source_ != NoOperand) { | ||||
| 						printf(" %s", modename(source_, source_reg_)); | ||||
| 					} | ||||
| 					if(dest_ != NoOperand) { | ||||
| 						printf(", %s", modename(dest_, dest_reg_)); | ||||
| 					} | ||||
|  | ||||
| 					printf("\",\n"); | ||||
| 				} | ||||
|  | ||||
| 				void set_operation(Operation op)		{ operation_ = op;						} | ||||
| 				void set_source(int type, int reg = 0)	{ source_ = type; source_reg_ = reg;	} | ||||
| 				void set_dest(int type, int reg = 0) 	{ dest_ = type;	dest_reg_ = reg;		} | ||||
| 				void set_source_dest(int s, int sr, int d, int dr)	{ | ||||
| 					set_source(s, sr); | ||||
| 					set_dest(d, dr); | ||||
| 				} | ||||
|  | ||||
| 				void reset() { | ||||
| 					operation_ = Operation::None; | ||||
| 					source_ = dest_ = NoOperand; | ||||
| 				} | ||||
|  | ||||
| 			private: | ||||
| 				uint16_t opcode_ = 0; | ||||
| 				Operation operation_ = Operation::None; | ||||
|  | ||||
| 				int source_ = NoOperand; | ||||
| 				int dest_ = NoOperand; | ||||
| 				int source_reg_ = 0; | ||||
| 				int dest_reg_ = 0; | ||||
|  | ||||
| 				char tbuf[20]; | ||||
| 				const char *modename(int mode, int reg) { | ||||
| 					switch(mode) { | ||||
| 						default: | ||||
| 							assert(false); | ||||
| 							return "?"; | ||||
| 						case XXXl:		return "(xxx).l"; | ||||
| 						case XXXw:		return "(xxx).w"; | ||||
| 						case d16PC:		return "(d16, PC)"; | ||||
| 						case d8PCXn:	return "(d8, PC, Xn)"; | ||||
| 						case Imm:		return "#"; | ||||
| 						case Dn:		sprintf(tbuf, "D%d", reg);				break; | ||||
| 						case An:		sprintf(tbuf, "A%d", reg);				break; | ||||
| 						case Ind:		sprintf(tbuf, "(A%d)", reg);			break; | ||||
| 						case PostInc:	sprintf(tbuf, "(A%d)+", reg);			break; | ||||
| 						case PreDec:	sprintf(tbuf, "-(A%d)", reg);			break; | ||||
| 						case d16An:		sprintf(tbuf, "(d16, A%d)", reg);		break; | ||||
| 						case d8AnXn:	sprintf(tbuf, "(d8, A%d, Xn)", reg);	break; | ||||
| 						case Quick: | ||||
| 							if(operation_ == Operation::MOVEq) { | ||||
| 								sprintf(tbuf, "%d", int8_t(opcode_)); | ||||
| 							} else if(operation_ == Operation::Bcc || operation_ == Operation::BRA) { | ||||
| 								const int8_t val = int8_t(opcode_); | ||||
| 								if(!val) { | ||||
| 									return "#"; | ||||
| 								} else { | ||||
| 									sprintf(tbuf, "%d", val); | ||||
| 								} | ||||
| 							} else if(operation_ == Operation::TRAP) { | ||||
| 								sprintf(tbuf, "%d", opcode_ & 15); | ||||
| 							} else { | ||||
| 								const auto val = ((opcode_ >> 9)&7); | ||||
| 								sprintf(tbuf, "%d", val ? val : 8); | ||||
| 							} | ||||
| 						break; | ||||
| 					} | ||||
| 					return tbuf; | ||||
| 				} | ||||
| 		}; | ||||
|  | ||||
| #undef NoOperand | ||||
|  | ||||
| 		// Perform a linear search of the mappings above for this instruction. | ||||
| 		for(ssize_t instruction = 65535; instruction >= 0; --instruction)	{ | ||||
| 			if(instruction == 0x54c8) { | ||||
| 				printf(""); | ||||
| 			} | ||||
|  | ||||
| 			InstructionDumper dumper{uint16_t(instruction)}; | ||||
| #ifndef NDEBUG | ||||
| 			int hits = 0; | ||||
| #endif | ||||
| 			for(const auto &mapping: mappings) { | ||||
| 				dumper.reset(); | ||||
|  | ||||
| 				if((instruction & mapping.mask) == mapping.value) { | ||||
| 					auto operation = mapping.operation; | ||||
| 					dumper.set_operation(operation); | ||||
| 					const auto micro_op_start = storage_.all_micro_ops_.size(); | ||||
|  | ||||
| 					// The following fields are used commonly enough to be worth pulling out here. | ||||
| @@ -868,17 +1188,21 @@ struct ProcessorStorageConstructor { | ||||
| 					switch(mapping.decoder) { | ||||
| 						case Decoder::STOP: { | ||||
| 							program.set_requires_supervisor(true); | ||||
| 							dumper.set_source(Imm); | ||||
| 							op(Action::None, seq("n")); | ||||
| 							op(Action::PerformOperation); | ||||
| 						} break; | ||||
|  | ||||
| 						case Decoder::LINK: { | ||||
| 							program.set_source(storage_, An, ea_register); | ||||
| 							dumper.set_source(An, ea_register); | ||||
| 							dumper.set_dest(Imm); | ||||
| 							op(Action::PerformOperation, seq("np nW+ nw np", { ea(1), ea(1) })); | ||||
| 						} break; | ||||
|  | ||||
| 						case Decoder::UNLINK: { | ||||
| 							program.set_destination(storage_, An, ea_register); | ||||
| 							dumper.set_source(An, ea_register); | ||||
| 							op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("nRd+ nrd np", { ea(1), ea(1) })); | ||||
| 							op(Action::PerformOperation); | ||||
| 						} break; | ||||
| @@ -886,6 +1210,8 @@ struct ProcessorStorageConstructor { | ||||
| 						case Decoder::TAS: { | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							program.set_destination(storage_, ea_mode, ea_register); | ||||
|  | ||||
| 							dumper.set_source(mode, ea_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -932,10 +1258,12 @@ struct ProcessorStorageConstructor { | ||||
| 							if(instruction & 0x100) { | ||||
| 								// The bit is nominated by a register. | ||||
| 								program.set_source(storage_, Dn, data_register); | ||||
| 								dumper.set_source_dest(Dn, data_register, mode, ea_register); | ||||
| 							} else { | ||||
| 								// The bit is nominated by a constant, that will be obtained right here. | ||||
| 								program.set_source(storage_, Imm, 0); | ||||
| 								op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np")); | ||||
| 								dumper.set_source_dest(Imm, 0, mode, ea_register); | ||||
| 							} | ||||
|  | ||||
| 							switch(mode) { | ||||
| @@ -978,11 +1306,13 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_requires_supervisor(!!(instruction & 0x40)); | ||||
| 							op(Action::None, seq("np nn nn")); | ||||
| 							op(Action::PerformOperation, seq("np np")); | ||||
| 							dumper.set_source(Imm); | ||||
| 						} break; | ||||
|  | ||||
| 						case Decoder::EXT_SWAP: { | ||||
| 							program.set_destination(storage_, Dn, ea_register); | ||||
| 							op(Action::PerformOperation, seq("np")); | ||||
| 							dumper.set_source(Dn, ea_register); | ||||
| 						} break; | ||||
|  | ||||
| 						case Decoder::EXG: { | ||||
| @@ -992,16 +1322,19 @@ struct ProcessorStorageConstructor { | ||||
| 								case 0x08: | ||||
| 									program.set_source(storage_, Dn, data_register); | ||||
| 									program.set_destination(storage_, Dn, ea_register); | ||||
| 									dumper.set_source_dest(Dn, data_register, Dn, ea_register); | ||||
| 								break; | ||||
|  | ||||
| 								case 0x09: | ||||
| 									program.set_source(storage_, An, data_register); | ||||
| 									program.set_destination(storage_, An, ea_register); | ||||
| 									dumper.set_source_dest(An, data_register, An, ea_register); | ||||
| 								break; | ||||
|  | ||||
| 								case 0x11: | ||||
| 									program.set_source(storage_, Dn, data_register); | ||||
| 									program.set_destination(storage_, An, ea_register); | ||||
| 									dumper.set_source_dest(Dn, data_register, An, ea_register); | ||||
| 								break; | ||||
| 							} | ||||
|  | ||||
| @@ -1037,6 +1370,7 @@ struct ProcessorStorageConstructor { | ||||
| 							if(to_ea) { | ||||
| 								program.set_destination(storage_, ea_mode, ea_register); | ||||
| 								program.set_source(storage_, Dn, data_register); | ||||
| 								dumper.set_source_dest(Dn, data_register, mode, ea_register); | ||||
|  | ||||
| 								// Only EOR takes Dn as a destination effective address. | ||||
| 								if(!is_eor && mode == Dn) continue; | ||||
| @@ -1104,6 +1438,7 @@ struct ProcessorStorageConstructor { | ||||
|  | ||||
| 								program.set_source(storage_, ea_mode, ea_register); | ||||
| 								program.set_destination(storage_, Dn, data_register); | ||||
| 								dumper.set_source_dest(mode, ea_register, Dn, data_register); | ||||
|  | ||||
| 								switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| 									default: continue; | ||||
| @@ -1185,6 +1520,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, Dn, data_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source_dest(mode, ea_register, Dn, data_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -1232,6 +1568,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, Dn, data_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source_dest(mode, ea_register, Dn, data_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -1281,6 +1618,7 @@ struct ProcessorStorageConstructor { | ||||
| 							// destination is going to be in the write address unit. | ||||
| 							program.set_source(storage_, Imm, 0); | ||||
| 							program.set_destination(storage_, mode, ea_register); | ||||
| 							dumper.set_source_dest(Imm, 0, mode, ea_register); | ||||
|  | ||||
| 							switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| 								default: continue; | ||||
| @@ -1378,6 +1716,7 @@ struct ProcessorStorageConstructor { | ||||
| 							if(reverse_source_destination) { | ||||
| 								program.set_destination(storage_, Dn, data_register); | ||||
| 								program.set_source(storage_, Imm, ea_register); | ||||
| 								dumper.set_source_dest(mode, ea_register, Dn, data_register); | ||||
|  | ||||
| 								// Perform [ADD/SUB].blw <ea>, Dn | ||||
| 								switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| @@ -1482,6 +1821,7 @@ struct ProcessorStorageConstructor { | ||||
| 								const auto destination_register = ea_register; | ||||
| 								program.set_destination(storage_, Ind, destination_register); | ||||
| 								program.set_source(storage_, Dn, data_register); | ||||
| 								dumper.set_source_dest(Dn, data_register, mode, ea_register); | ||||
|  | ||||
| 								// Perform [ADD/SUB].blw Dn, <ea> | ||||
| 								switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| @@ -1550,6 +1890,7 @@ struct ProcessorStorageConstructor { | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							is_long_word_access = op_mode_high_bit; | ||||
| 							dumper.set_source_dest(mode, ea_register, An, data_register); | ||||
|  | ||||
| 							switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| 								default: continue; | ||||
| @@ -1634,6 +1975,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, ea_mode, ea_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source_dest(Quick, 0, mode, ea_register); | ||||
|  | ||||
| 							// If the destination is an address register then byte mode isn't allowed, and | ||||
| 							// flags shouldn't be affected (so, a different operation is used). | ||||
| @@ -1713,8 +2055,9 @@ struct ProcessorStorageConstructor { | ||||
| 						case Decoder::ADDX_SUBX: { | ||||
| 							if(instruction & 0x8) { | ||||
| 								// Use predecrementing address registers. | ||||
| 								program.set_source(storage_, Ind, ea_register); | ||||
| 								program.set_destination(storage_, Ind, data_register); | ||||
| 								program.set_source(storage_, PreDec, ea_register); | ||||
| 								program.set_destination(storage_, PreDec, data_register); | ||||
| 								dumper.set_source_dest(PreDec, ea_register, PreDec, data_register); | ||||
|  | ||||
| 								if(is_long_word_access) { | ||||
| 									// Access order is very atypical here: it's lower parts each for both words, | ||||
| @@ -1740,6 +2083,7 @@ struct ProcessorStorageConstructor { | ||||
| 								// Use data registers. | ||||
| 								program.set_source(storage_, Dn, ea_register); | ||||
| 								program.set_destination(storage_, Dn, data_register); | ||||
| 								dumper.set_source_dest(Dn, ea_register, Dn, data_register); | ||||
|  | ||||
| 								if(is_long_word_access) { | ||||
| 									op(Action::PerformOperation, seq("np nn")); | ||||
| @@ -1753,6 +2097,7 @@ struct ProcessorStorageConstructor { | ||||
| 						// This decoder actually decodes nothing; it just schedules a PerformOperation followed by an empty step. | ||||
| 						case Decoder::Bcc_BSR: { | ||||
| 							const int condition = (instruction >> 8) & 0xf; | ||||
| 							dumper.set_source(Quick); | ||||
| 							if(condition == 1) { | ||||
| 								// This is BSR, which is unconditional and means pushing a return address to the stack first. | ||||
|  | ||||
| @@ -1768,6 +2113,7 @@ struct ProcessorStorageConstructor { | ||||
| 						// A little artificial, there's nothing really to decode for BRA. | ||||
| 						case Decoder::BRA: { | ||||
| 							op(Action::PerformOperation, seq("n np np")); | ||||
| 							dumper.set_source(Quick); | ||||
| 						} break; | ||||
|  | ||||
| 						// Decodes a BTST, potential mutating the operation into a BTSTl, | ||||
| @@ -1780,6 +2126,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, ea_mode, ea_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source_dest(Dn, data_register, mode, ea_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -1842,6 +2189,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, ea_mode, ea_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source_dest(Imm, 0, mode, ea_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -1905,17 +2253,25 @@ struct ProcessorStorageConstructor { | ||||
| 								op(MicroOp::SourceMask | dec(ea_register), seq("n nr", { a(ea_register) }, false )); | ||||
| 								op(MicroOp::DestinationMask | dec(data_register), seq("nrd np", { a(data_register) }, false )); | ||||
| 								op(Action::PerformOperation, seq("nw", { a(data_register) }, false)); | ||||
| 								dumper.set_source_dest(PreDec, ea_register, PreDec, data_register); | ||||
| 							} else { | ||||
| 								// [A/S]BCD Dn, Dn | ||||
| 								program.set_source(storage_, Dn, ea_register); | ||||
| 								program.set_destination(storage_, Dn, data_register); | ||||
|  | ||||
| 								op(Action::PerformOperation, seq("np n")); | ||||
| 								dumper.set_source_dest(Dn, ea_register, Dn, data_register); | ||||
| 							} | ||||
| 						} break; | ||||
|  | ||||
| 						case Decoder::ASLR_LSLR_ROLR_ROXLRr: { | ||||
| 							program.set_destination(storage_, 0, ea_register); | ||||
| 							dumper.set_dest(Dn, ea_register); | ||||
| 							if(instruction & 0x20) { | ||||
| 								dumper.set_source(Dn, data_register); | ||||
| 							} else { | ||||
| 								dumper.set_source(Quick); | ||||
| 							} | ||||
|  | ||||
| 							// All further decoding occurs at runtime; that's also when the proper number of | ||||
| 							// no-op cycles will be scheduled. | ||||
| @@ -1933,6 +2289,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, ea_mode, ea_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source(mode, ea_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -1967,6 +2324,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, ea_mode, ea_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source(mode, ea_register); | ||||
| 							switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2043,6 +2401,7 @@ struct ProcessorStorageConstructor { | ||||
| 							} | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source_dest(mode, ea_register, Dn, data_register); | ||||
| 							switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2135,6 +2494,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, An, data_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register, true); | ||||
| 							dumper.set_source_dest(combined_mode(ea_mode, ea_register), ea_register, An, data_register); | ||||
| 							switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2219,6 +2579,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, destination_mode, destination_register); | ||||
|  | ||||
| 							const int mode = combined_mode(destination_mode, destination_register); | ||||
| 							dumper.set_source_dest(Imm, 0, mode, destination_register); | ||||
| 							switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2308,6 +2669,7 @@ struct ProcessorStorageConstructor { | ||||
| 						case Decoder::CMPM: { | ||||
| 							program.set_source(storage_, PostInc, ea_register); | ||||
| 							program.set_destination(storage_, PostInc, data_register); | ||||
| 							dumper.set_source_dest(PostInc, ea_register, PostInc, data_register); | ||||
|  | ||||
| 							const bool is_byte_operation = operation == Operation::CMPb; | ||||
|  | ||||
| @@ -2340,6 +2702,9 @@ struct ProcessorStorageConstructor { | ||||
| 								// This is a DBcc. Decode as such. | ||||
| 								operation = Operation::DBcc; | ||||
| 								program.set_source(storage_, Dn, ea_register); | ||||
| 								dumper.set_source(Dn, ea_register); | ||||
| 								dumper.set_dest(Imm); | ||||
| 								dumper.set_operation(operation); | ||||
|  | ||||
| 								// Jump straight into deciding what steps to take next, | ||||
| 								// which will be selected dynamically. | ||||
| @@ -2357,6 +2722,7 @@ struct ProcessorStorageConstructor { | ||||
| 								is_long_word_access = false; | ||||
|  | ||||
| 								const int mode = combined_mode(ea_mode, ea_register); | ||||
| 								dumper.set_source(mode, ea_register); | ||||
| 								switch(mode) { | ||||
| 									default: continue; | ||||
|  | ||||
| @@ -2404,6 +2770,7 @@ struct ProcessorStorageConstructor { | ||||
| 							// calculation that might be a function of A7 needs to be done before PrepareJSR. | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source(mode, ea_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
| 								case Ind:		// JSR (An) | ||||
| @@ -2445,6 +2812,7 @@ struct ProcessorStorageConstructor { | ||||
| 						case Decoder::JMP: { | ||||
| 							program.set_source(storage_, ea_mode, ea_register); | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source(mode, ea_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
| 								case Ind:		// JMP (An) | ||||
| @@ -2478,6 +2846,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_destination(storage_, Imm, 7);	// Immediate destination => store to the destination bus latch. | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source(mode, ea_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2518,6 +2887,7 @@ struct ProcessorStorageConstructor { | ||||
| 									&storage_.address_[ea_register] : | ||||
| 									&storage_.effective_address_[0]); | ||||
|  | ||||
| 							dumper.set_source_dest(mode, ea_register, An, data_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
| 								case Ind:		// LEA (An), An		(i.e. MOVEA) | ||||
| @@ -2549,6 +2919,7 @@ struct ProcessorStorageConstructor { | ||||
| 							is_long_word_access = false; | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source(mode, ea_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2593,6 +2964,7 @@ struct ProcessorStorageConstructor { | ||||
| 							/* DEVIATION FROM YACHT.TXT: it has all of these reading an extra word from the PC; | ||||
| 							this looks like a mistake so I've padded with nil cycles in the middle. */ | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source(mode, ea_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2636,6 +3008,7 @@ struct ProcessorStorageConstructor { | ||||
| 						case Decoder::MOVEq: { | ||||
| 							program.set_destination(storage_, Dn, data_register); | ||||
| 							op(Action::PerformOperation, seq("np")); | ||||
| 							dumper.set_source_dest(Quick, 0, Dn, data_register); | ||||
| 						} break; | ||||
|  | ||||
| 						case Decoder::MOVEP: { | ||||
| @@ -2650,22 +3023,26 @@ struct ProcessorStorageConstructor { | ||||
| 								case Operation::MOVEPtoMw: | ||||
| 									op(Action::PerformOperation); | ||||
| 									op(int(Action::CalcD16An) | MicroOp::DestinationMask, seq("np nW+ nw np", { ea(1), ea(1) }, false)); | ||||
| 									dumper.set_source_dest(Dn, data_register, d16An, ea_register); | ||||
| 								break; | ||||
|  | ||||
| 								case Operation::MOVEPtoMl: | ||||
| 									op(Action::PerformOperation); | ||||
| 									op(int(Action::CalcD16An) | MicroOp::DestinationMask, seq("np nW+ nWr+ nw+ nwr np", { ea(1), ea(1), ea(1), ea(1) }, false)); | ||||
| 									dumper.set_source_dest(Dn, data_register, d16An, ea_register); | ||||
| 								break; | ||||
|  | ||||
| 								case Operation::MOVEPtoRw: | ||||
| 									op(int(Action::CalcD16An) | MicroOp::DestinationMask, seq("np nRd+ nrd np", { ea(1), ea(1) }, false)); | ||||
| 									op(Action::PerformOperation); | ||||
| 									dumper.set_source_dest(d16An, ea_register, Dn, data_register); | ||||
| 								break; | ||||
|  | ||||
| 								case Operation::MOVEPtoRl: | ||||
| 									// TODO: nR+ increments EA(0), not EA(1). Fix. | ||||
| 									op(int(Action::CalcD16An) | MicroOp::DestinationMask, seq("np nRd+ nR+ nrd+ nr np", { ea(1), ea(1), ea(1), ea(1) }, false)); | ||||
| 									op(Action::PerformOperation); | ||||
| 									dumper.set_source_dest(d16An, ea_register, Dn, data_register); | ||||
| 								break; | ||||
| 							} | ||||
| 						} break; | ||||
| @@ -2682,6 +3059,14 @@ struct ProcessorStorageConstructor { | ||||
| 							// Do whatever is necessary to calculate the proper start address. | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							const bool is_to_m = (operation == Operation::MOVEMtoMl || operation == Operation::MOVEMtoMw); | ||||
|  | ||||
| 							if(is_to_m) { | ||||
| 								dumper.set_source(Imm); | ||||
| 								dumper.set_dest(mode, ea_register); | ||||
| 							} else { | ||||
| 								dumper.set_source(mode, ea_register); | ||||
| 								dumper.set_dest(Imm); | ||||
| 							} | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2717,6 +3102,7 @@ struct ProcessorStorageConstructor { | ||||
|  | ||||
| 						case Decoder::MOVEUSP: { | ||||
| 							program.set_requires_supervisor(true); | ||||
| 							dumper.set_source(An, ea_register); | ||||
|  | ||||
| 							// Observation here: because this is a privileged instruction, the user stack pointer | ||||
| 							// definitely isn't currently [copied into] A7. | ||||
| @@ -2751,18 +3137,22 @@ struct ProcessorStorageConstructor { | ||||
| 									continue; | ||||
| 								} | ||||
| 								operation = is_long_word_access ? Operation::MOVEAl : Operation::MOVEAw; | ||||
| 								dumper.set_operation(operation); | ||||
| 							} | ||||
|  | ||||
| 							// ... there are also no byte moves from address registers. | ||||
| 							if(ea_mode == An && is_byte_access) continue; | ||||
|  | ||||
| 							// Perform the MOVE[A]'s fetch.. | ||||
| 							const int combined_source_mode = combined_mode(ea_mode, ea_register, true); | ||||
| 							// Perform the MOVE[A]'s fetch... | ||||
| 							const int combined_source_mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source(combined_source_mode, ea_register); | ||||
| 							switch(is_long_word_access ? l(combined_source_mode) : bw(combined_source_mode)) { | ||||
| 								default: continue; | ||||
|  | ||||
| 								case l(Dn):			// MOVE[A].l [An/Dn], <ea> | ||||
| 								case bw(Dn):		// MOVE[A].bw [An/Dn], <ea> | ||||
| 								case l(An):			// MOVE[A].l [An/Dn], <ea> | ||||
| 								case bw(An):		// MOVE[A].bw [An/Dn], <ea> | ||||
| 								break; | ||||
|  | ||||
| 								case bw(PreDec):	// MOVE[A].bw -(An), <ea> | ||||
| @@ -2826,6 +3216,9 @@ struct ProcessorStorageConstructor { | ||||
|  | ||||
| 							// Perform the MOVE[A]'s store. | ||||
| 							const int combined_destination_mode = combined_mode(destination_mode, data_register, true); | ||||
| 							dumper.set_dest( | ||||
| 								(combined_destination_mode == Dn && destination_mode == An) ? An : combined_destination_mode, | ||||
| 								data_register); | ||||
| 							switch(is_long_word_access ? l(combined_destination_mode) : bw(combined_destination_mode)) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2923,6 +3316,7 @@ struct ProcessorStorageConstructor { | ||||
| 						break; | ||||
|  | ||||
| 						case Decoder::TRAP: { | ||||
| 							dumper.set_source(Quick); | ||||
| 							// TRAP involves some oddly-sequenced stack writes, so is calculated | ||||
| 							// at runtime; also the same sequence is used for illegal instructions. | ||||
| 							// So the entirety is scheduled at runtime. | ||||
| @@ -2941,6 +3335,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_source(storage_, ea_mode, ea_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source_dest(mode, ea_register, Dn, data_register); | ||||
| 							switch(mode) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -2985,6 +3380,7 @@ struct ProcessorStorageConstructor { | ||||
| 							program.set_source(storage_, ea_mode, ea_register); | ||||
|  | ||||
| 							const int mode = combined_mode(ea_mode, ea_register); | ||||
| 							dumper.set_source(mode, ea_register); | ||||
| 							switch(is_long_word_access ? l(mode) : bw(mode)) { | ||||
| 								default: continue; | ||||
|  | ||||
| @@ -3086,12 +3482,12 @@ struct ProcessorStorageConstructor { | ||||
|  | ||||
| 					// Don't search further through the list of possibilities, unless this is a debugging build, | ||||
| 					// in which case verify there are no double mappings. | ||||
| #ifndef NDEBUG | ||||
| 					++hits; | ||||
| 					assert(hits == 1); | ||||
| #else | ||||
| //#ifndef NDEBUG | ||||
| //					++hits; | ||||
| //					assert(hits == 1); | ||||
| //#else | ||||
| 					break; | ||||
| #endif | ||||
| //#endif | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user