view modules/x86.tp @ 175:20b6041a8b23

Small refactor in x86 module. Added a few more instructions.
author Mike Pavone <pavone@retrodev.com>
date Thu, 22 Aug 2013 15:12:15 -0700
parents 8b5829372ad1
children 75aca5f87969
line wrap: on
line source

{
	ireg <- :regnum {
		#{
			num <- { regnum }
			reg <- { regnum and 7u8}
			rm <- :tail { reg or 0xC0u8 | tail }
			validforSize? <- :size { true }
			isInteger? <- { false }
			register? <- { true }
			upper? <- { true }
			needsRex? <- { regnum >= 8u8 }
			rexBitReg <- {
				if: needsRex? {
					4u8
				} else: {
					0u8
				}
			}
			rexBitRM <- {
				if: needsRex? {
					1u8
				} else: {
					0u8
				}
			}
			= <- :other {
				(not: (other isInteger?)) && (other register?) && (not: (other upper?)) && regnum = (other num)
			}
		}
	}

	upper <- :regnum {
		#{
			num <- { regnum }
			reg <- { regnum }
			rm <- :tail { regnum or 0xC0u8 | tail }
			validforSize? <- :size {
				size = byte
			}
			isInteger? <- { false }
			register? <- { true }
			upper? <- { true }
			needsRex? <- { false }
			= <- :other {
				(not: (other isInteger?)) && (other register?) && (other upper?) && regnum = (other num)
			}
		}
	}
	fakesrc <- #{
		needsRex? <- { false }
		rexBitReg <- { 0u8 }
		rexBitRM <- { 0u8 }
	}
	size <- :s {
		#{
			num <- { s }
			= <- :other {
				s = (other num)
			}
			> <- :other {
				s > (other num)
			}
			>= <- :other {
				s >= (other num)
			}
			< <- :other {
				s < (other num)
			}
			<= <- :other {
				s <= (other num)
			}
			needsRex? <- { s = 3 }
			rexBit <- {
				if: needsRex? {
					0x08u8
				} else: {
					0u8
				}
			}
		}
	}
	byte <- size: 0
	word <- size: 1
	dword <- size: 2
	qword <- size: 3

	size_bit <- :opcode size {
		if: size = byte {
			opcode
		} else: {
			opcode or 2u8
		}
	}
	opex <- :val {
		#{
			reg <- { val }
		}
	}

	mod_rm:withTail <- :register regmem :end {
		l <- regmem rm: end
		(l value) or (register reg) | (l tail)
	}

	mod_rm <- :reg rm {
		mod_rm: reg rm withTail: []
	}

	int_op:withTail <- :value size :tail {
		if: size >= dword {
			tail <- (uint8: (value rshift: 16)) | (uint8: (value rshift: 24)) | tail
		}
		if: size >= word {
			tail <- (uint8: (value rshift: 8)) | tail
		}
		(uint8: value) | tail
	}
	int_op <- :value size {
		int_op: value size withTail: []
	}
	//used for mov instructions that support 64-bit immediate operands/offsets
	int_op64 <- :value size {
		tail <- []
		if: size = qword {
			tail <- (uint8: (value rshift: 32)) | (uint8: (value rshift: 40)) | (uint8: (value rshift: 48)) | (uint8: (value rshift: 56)) | tail
		}
		int_op: value size withTail: tail
	}

	prefix:withInstruction <- :reg rm size :inst {
		if: size = word {
			inst <- 0x66u8 | inst
		}
		if: (size needsRex?) || (reg needsRex?) || (rm needsRex?) {
			rex <- 0x40u8 or (size rexBit) or (reg rexBitReg) or (rm rexBitRM)
			inst <- rex | inst
		}
		inst
	}

	_rax <- ireg: 0u8
	_rcx <- ireg: 1u8
	_rdx <- ireg: 2u8
	_rbx <- ireg: 3u8
	_rsp <- ireg: 4u8
	_rbp <- ireg: 5u8
	_rsi <- ireg: 6u8
	_rdi <- ireg: 7u8
	_r8 <- ireg: 8u8
	_r9 <- ireg: 9u8
	_r10 <- ireg: 10u8
	_r11 <- ireg: 11u8
	_r12 <- ireg: 12u8
	_r13 <- ireg: 13u8
	_r14 <- ireg: 14u8
	_r15 <- ireg: 15u8
	_ah <- upper: 4u8
	_ch <- upper: 5u8
	_dh <- upper: 6u8
	_bh <- upper: 7u8

	op:withCode:withImmed:withOpEx <- :src dst size :normal :immed :myopex {
		reg <- src
		rm <- dst
		base <- if: (src isInteger?) {
			reg <- fakesrc
			(size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size))
		} else: {
			if: (src register?) {
				(size_bit: normal size) | (mod_rm: src dst)
			} else: {
				reg <- dst
				rm <- src
				(size_bit: normal or 0x02u8 size) | (mod_rm: dst src)
			}
		}
		prefix: reg rm size withInstruction: base
	}

	op:withCode:withImmed:withImmedRax:withOpEx:withByteExtend <- :src dst size :normal :immed :immedRax :myopex :byteExt {
		reg <- src
		rm <- dst
		if: (src isInteger?) {
			reg <- fakesrc
			base <- if: size > byte && (((src signed?) && src < 128 && src >= -128) || ((not: (src signed?)) && src < 256)) {
				0x83u8 | (mod_rm: (opex: myopex) dst withTail: [(uint8: src)])
			} else: {
				if: dst = _rax {
					(size_bit: immedRax size) | (int_op: src size)
				} else: {
					(size_bit: immed size) | (mod_rm: (opex: myopex) dst withTail: (int_op: src size))
				}
			}
			prefix: reg rm size withInstruction: base
		} else: {
			op: src dst size withCode: normal withImmed: immed withOpEx: myopex
		}

	}

	#{
		rax <- { _rax }
		rcx <- { _rcx }
		rdx <- { _rdx }
		rbx <- { _rbx }
		rsp <- { _rsp }
		rbp <- { _rbp }
		rsi <- { _rsi }
		rdi <- { _rdi }
		r8 <- { _r8 }
		r9 <- { _r9 }
		r10 <- { _r10 }
		r11 <- { _r11 }
		r12 <- { _r12 }
		r13 <- { _r13 }
		r14 <- { _r14 }
		r15 <- { _r15 }
		ah <- { _ah }
		ch <- { _ch }
		dh <- { _dh }
		bh <- { _bh }

		b <- { byte }
		w <- { word }
		d <- { dword }
		q <- { qword }

		add <- :src dst size {
			op: src dst size withCode: 0u8 withImmed: 0x80u8 withImmedRax: 0x04u8 withOpEx: 0u8 withByteExtend: 0x83u8
		}

		sub <- :src dst size {
			op: src dst size withCode: 0x28u8 withImmed: 0x80u8 withImmedRax: 0x2Cu8 withOpEx: 5u8 withByteExtend: 0x83u8
		}

		mov <- :src dst size {
			reg <- src
			rm <- dst
			if: (src isInteger?) && (dst register?) {
				opval <- if: size = byte { 0xB0u8 } else: { 0xB8u8 }
				base <- opval | (int_op64: src size)
				prefix: fakesrc rm size withInstruction: base
			} else: {
				op: src dst size withCode: 0x88u8 withImmed: 0xC6u8 withOpEx: 0u8
			}
		}

		ret <- { [ 0xC3u8 ] }


		main <- {
			print: ((add: rax r8 b) map: :el { hex: el })
			print: "\n"
			print: ((add: r9 rdx w) map: :el { hex: el })
			print: "\n"
			print: ((add: rax rbx q) map: :el { hex: el })
			print: "\n"
			print: ((add: 25 rax q) map: :el { hex: el })
			print: "\n"
			print: ((add: rcx rdx d) map: :el { hex: el })
			print: "\n"
			0
		}
	}
}