Generalize with perform_load and perform_store, use bit_set for cpu flags
This commit is contained in:
		
							parent
							
								
									831a307975
								
							
						
					
					
						commit
						df105ea3cf
					
				
							
								
								
									
										195
									
								
								execution.odin
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								execution.odin
									
									
									
									
									
								
							| @ -23,7 +23,7 @@ get_effective_address_value :: proc(cpu: ^Cpu, id: u8) -> i16 { | ||||
|     return -1 | ||||
| } | ||||
| 
 | ||||
| get_operand_value :: proc(cpu: ^Cpu, operand: Operand) -> i16 { | ||||
| perform_load :: proc(cpu: ^Cpu, operand: Operand, is_word: bool) -> i16 { | ||||
|     #partial switch opr in operand { | ||||
|     case Immediate: | ||||
|         return i16(opr.value) | ||||
| @ -36,139 +36,74 @@ get_operand_value :: proc(cpu: ^Cpu, operand: Operand) -> i16 { | ||||
|             return i16(reg_val.full) | ||||
|         } | ||||
|     case DirectAddress: | ||||
|         value := i16(u16(cpu.memory[opr+1] << 8) | u16(cpu.memory[opr])) | ||||
|         value: i16 | ||||
|         if is_word { | ||||
|             value = i16(u16(cpu.memory[opr+1] << 8) | u16(cpu.memory[opr])) | ||||
|         } else { | ||||
|             value = i16(cpu.memory[opr]) | ||||
|         } | ||||
|         return value | ||||
|     case MemoryAddr: | ||||
|         value: i16 | ||||
|         idx := get_effective_address_value(cpu, opr.addr_id) + opr.displacement | ||||
|         value := i16(u16(cpu.memory[idx+1] << 8) | u16(cpu.memory[idx])) | ||||
|         // fmt.println("Checking", idx) | ||||
|         // for i in 0..<6 { | ||||
|         //     fmt.printf("%04x ", cpu.memory[int(idx)-3+i]) | ||||
|         // } | ||||
|         // fmt.println() | ||||
|         if is_word { | ||||
|             value = i16(u16(cpu.memory[idx+1] << 8) | u16(cpu.memory[idx])) | ||||
|         } else { | ||||
|             value = i16(cpu.memory[idx]) | ||||
|         } | ||||
|         return value | ||||
|     } | ||||
|     return 0 | ||||
| } | ||||
| 
 | ||||
| set_register_value :: proc(cpu: ^Cpu, reg: RegisterId, value: i16) { | ||||
|     switch reg.access { | ||||
|     case .Low: | ||||
|         cpu.registers[reg.name].low = u8(value) | ||||
|     case .High: | ||||
|         cpu.registers[reg.name].high = u8(value) | ||||
|     case .Full: | ||||
|         cpu.registers[reg.name].full = i16(value) | ||||
| check_flags :: proc(cpu: ^Cpu, flags: bit_set[Flag], dst: i16, src: i16, result: i16, is_add: bool) { | ||||
|     if .ZF in flags do cpu.flags[.ZF] = result == 0 | ||||
|     if .SF in flags do cpu.flags[.SF] = (result >> 15) & 0x1 == 1 | ||||
|     if .CF in flags { | ||||
|         cpu.flags[.CF] = is_add ? u32(dst) + u32(src) > 0xFFFF : src > dst | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| get_cpu_register_by_name :: proc(cpu: ^Cpu, name: string) -> ^RegisterValue { | ||||
|     reg,_ := reflect.enum_from_name(Register, name) | ||||
|     return &cpu.registers[reg] | ||||
| } | ||||
| 
 | ||||
| check_zero_flag :: proc(cpu: ^Cpu, value: i16) { | ||||
|     cpu.flags[.ZF] = value == 0 | ||||
| } | ||||
| 
 | ||||
| check_sign_flag :: proc(cpu: ^Cpu, value: i16) { | ||||
|     cpu.flags[.SF] = (value >> 15) & 0x1 == 1 | ||||
| } | ||||
| 
 | ||||
| check_carry_flag :: proc(cpu: ^Cpu, dst: i16, src: i16, is_add: bool) { | ||||
|     cpu.flags[.CF] = is_add ? u32(dst) + u32(src) > 0xFFFF : src > dst | ||||
| } | ||||
| 
 | ||||
| check_parity_flag :: proc(cpu: ^Cpu, value: i16) { | ||||
|     val := value | ||||
|     bit_count := 0 | ||||
|     val &= 0x00FF | ||||
|     for val != 0 { | ||||
|         if val & 0x1 == 1 { | ||||
|             bit_count += 1 | ||||
|     if .AF in flags { | ||||
|         lhs, rhs := dst & 0xF, src & 0xF | ||||
|         cpu.flags[.AF] = is_add ? lhs + rhs > 15 : lhs < rhs | ||||
|     } | ||||
|     if .PF in flags { | ||||
|         val := result | ||||
|         bit_count := 0 | ||||
|         val &= 0x00FF | ||||
|         for val != 0 { | ||||
|             if val & 0x1 == 1 { | ||||
|                 bit_count += 1 | ||||
|             } | ||||
|             val >>= 1 | ||||
|         } | ||||
|         val >>= 1 | ||||
|         cpu.flags[.PF] = bit_count % 2 == 0 | ||||
|     } | ||||
|     cpu.flags[.PF] = bit_count % 2 == 0 | ||||
| } | ||||
| 
 | ||||
| check_auxiliary_carry_flag :: proc(cpu: ^Cpu, dst: i16, src: i16, is_add: bool) { | ||||
|     lhs, rhs := dst & 0xF, src & 0xF | ||||
|     cpu.flags[.AF] = is_add ? lhs + rhs > 15 : lhs < rhs | ||||
| } | ||||
| 
 | ||||
| check_flags :: proc(cpu: ^Cpu, value: i16) { | ||||
|     check_zero_flag(cpu, value) | ||||
|     check_sign_flag(cpu, value) | ||||
|     check_parity_flag(cpu, value) | ||||
| perform_store :: proc(cpu: ^Cpu, value: i16, operand: Operand, is_word: bool) { | ||||
|     #partial switch opr in operand { | ||||
|     case RegisterId: | ||||
|         switch opr.access { | ||||
|         case .Low: | ||||
|             cpu.registers[opr.name].low = u8(value) | ||||
|         case .High: | ||||
|             cpu.registers[opr.name].high = u8(value) | ||||
|         case .Full: | ||||
|             cpu.registers[opr.name].full = i16(value) | ||||
|         } | ||||
|     case DirectAddress: | ||||
|         cpu.memory[opr] = u8(value) | ||||
|         if is_word do cpu.memory[opr+1] = u8((u16(value) & 0xFF00) >> 8) | ||||
|     case MemoryAddr: | ||||
|         effective_addr_val := get_effective_address_value(cpu, opr.addr_id) | ||||
|         addr := effective_addr_val + opr.displacement | ||||
|         cpu.memory[addr] = u8(value) | ||||
|         if is_word do cpu.memory[addr+1] = u8((u16(value) & 0xFF00) >> 8) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| execute_instruction :: proc(cpu: ^Cpu, inst: Instruction) { | ||||
|     if reg,ok := inst.dst.(RegisterId); ok { | ||||
|         #partial switch inst.opname { | ||||
|         case .MOV: | ||||
|             src_val := get_operand_value(cpu, inst.src) | ||||
|             set_register_value(cpu, reg, src_val) | ||||
|         case .ADD: | ||||
|             src_val := get_operand_value(cpu, inst.src) | ||||
|             dst_val := get_operand_value(cpu, inst.dst) | ||||
|             val := i16(cpu.registers[reg.name].full) + src_val | ||||
|             set_register_value(cpu, reg, val) | ||||
|             check_flags(cpu, val) | ||||
|             check_auxiliary_carry_flag(cpu, dst_val, src_val, true) | ||||
|             check_carry_flag(cpu, dst_val, src_val, true) | ||||
|         case .SUB: | ||||
|             src_val := get_operand_value(cpu, inst.src) | ||||
|             dst_val := get_operand_value(cpu, inst.dst) | ||||
|             val := i16(cpu.registers[reg.name].full) - src_val | ||||
|             set_register_value(cpu, reg, val) | ||||
|             check_flags(cpu, val) | ||||
|             check_auxiliary_carry_flag(cpu, dst_val, src_val, false) | ||||
|             check_carry_flag(cpu, dst_val, src_val, false) | ||||
|         case .CMP: | ||||
|             src_val := get_operand_value(cpu, inst.src) | ||||
|             dst_val := get_operand_value(cpu, inst.dst) | ||||
|             val := i16(cpu.registers[reg.name].full) - src_val | ||||
|             check_flags(cpu, val) | ||||
|             check_auxiliary_carry_flag(cpu, dst_val, src_val, false) | ||||
|             check_carry_flag(cpu, dst_val, src_val, false) | ||||
|         } | ||||
|     } else if addr,ok := inst.dst.(DirectAddress); ok { | ||||
|         #partial switch inst.opname { | ||||
|         case .MOV: | ||||
|             if imm,ok := inst.src.(Immediate); ok { | ||||
|                 if imm.size == ._16 { | ||||
|                     cpu.memory[addr]   = u8(imm.value & 0x00FF) | ||||
|                     cpu.memory[addr+1] = u8((u16(imm.value) & 0xFF00) >> 8) | ||||
|                 } else { | ||||
|                     cpu.memory[addr] = u8(imm.value) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } else if mem_addr,ok := inst.dst.(MemoryAddr); ok { | ||||
|         #partial switch inst.opname { | ||||
|         case .MOV: | ||||
|             value := get_operand_value(cpu, inst.src) | ||||
| 
 | ||||
|             effective_addr_val := get_effective_address_value(cpu, mem_addr.addr_id) | ||||
|             addr := effective_addr_val + mem_addr.displacement | ||||
|             cpu.memory[addr]   = u8(value & 0x00FF) | ||||
|             cpu.memory[addr+1] = u8((u16(value) & 0xFF00) >> 8) | ||||
| 
 | ||||
|             // TODO: We need a way to detect if it's a byte or a word | ||||
|             // if imm,ok := inst.src.(Immediate); ok { | ||||
|             //     // TODO: We need a function that returns the registers to check out | ||||
|             //     effective_addr_val := get_effective_address_value(cpu, mem_addr.addr_id) | ||||
|             //     addr := effective_addr_val + mem_addr.displacement_value | ||||
|             //     if imm.size == .Signed16 { | ||||
|             //         cpu.memory[addr]   = u8(imm.value & 0x00FF) | ||||
|             //         cpu.memory[addr+1] = u8((u16(imm.value) & 0xFF00) >> 8) | ||||
|             //     } else { | ||||
|             //         cpu.memory[addr] = u8(imm.value) | ||||
|             //     } | ||||
|             // } | ||||
|         } | ||||
|     } else if jmp_offset,ok := inst.src.(Jump); ok { | ||||
|     if jmp_offset,ok := inst.src.(Jump); ok { | ||||
|         jump: bool | ||||
|         #partial switch inst.opname { | ||||
|         case .JNZ, .JNE: jump = !cpu.flags[.ZF] | ||||
| @ -187,6 +122,30 @@ execute_instruction :: proc(cpu: ^Cpu, inst: Instruction) { | ||||
|             cpu.registers[.ip].full += i16(jmp_offset) | ||||
|             cpu.registers[.ip].full -= i16(inst.bytes_read) | ||||
|         } | ||||
|         return | ||||
|     } | ||||
|     status_flags := bit_set[Flag]{.OF, .SF, .ZF, .AF, .PF, .CF} | ||||
|     #partial switch inst.opname { | ||||
|     case .MOV: | ||||
|         src_val := perform_load(cpu, inst.src, inst.is_word) | ||||
|         perform_store(cpu, src_val, inst.dst, inst.is_word) | ||||
|     case .ADD: | ||||
|         src_val := perform_load(cpu, inst.src, inst.is_word) | ||||
|         dst_val := perform_load(cpu, inst.dst, inst.is_word) | ||||
|         val := dst_val + src_val | ||||
|         perform_store(cpu, val, inst.dst, inst.is_word) | ||||
|         check_flags(cpu, status_flags, dst_val, src_val, val, true) | ||||
|     case .SUB: | ||||
|         src_val := perform_load(cpu, inst.src, inst.is_word) | ||||
|         dst_val := perform_load(cpu, inst.dst, inst.is_word) | ||||
|         val := dst_val - src_val | ||||
|         perform_store(cpu, val, inst.dst, inst.is_word) | ||||
|         check_flags(cpu, status_flags, dst_val, src_val, val, false) | ||||
|     case .CMP: | ||||
|         src_val := perform_load(cpu, inst.src, inst.is_word) | ||||
|         dst_val := perform_load(cpu, inst.dst, inst.is_word) | ||||
|         val := dst_val - src_val | ||||
|         check_flags(cpu, status_flags, dst_val, src_val, val, false) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -70,7 +70,7 @@ get_operand_string :: proc(operand: Operand, has_segment: Maybe(RegisterId)) -> | ||||
|     case RegisterId: | ||||
|         string_val = get_register_name(val) | ||||
|     case Immediate: | ||||
|         string_val = fmt.aprintf("%d", i16(val.value)) | ||||
|         string_val = fmt.aprintf("%d", val.value) | ||||
|     case MemoryAddr: | ||||
|         string_val = get_memory_string(val, has_segment) | ||||
|     case DirectAddress: | ||||
|  | ||||
| @ -7,6 +7,11 @@ import "core:strings" | ||||
| import "core:strconv" | ||||
| import "core:reflect" | ||||
| 
 | ||||
| get_cpu_register_by_name :: proc(cpu: ^Cpu, name: string) -> ^RegisterValue { | ||||
|     reg,_ := reflect.enum_from_name(Register, name) | ||||
|     return &cpu.registers[reg] | ||||
| } | ||||
| 
 | ||||
| parse_reference_cpu_state :: proc(filename: string) -> (Cpu, bool) { | ||||
|     cpu: Cpu | ||||
| 
 | ||||
|  | ||||
| @ -68,6 +68,7 @@ Immediate :: struct { | ||||
| MemoryAddr :: struct { | ||||
|     addr_id: u8, | ||||
|     displacement: i16, | ||||
|     disp_size: ImmediateSize, | ||||
| } | ||||
| DirectAddress :: distinct i16 | ||||
| Jump :: distinct i8 | ||||
| @ -119,6 +120,7 @@ InstructionInfo :: struct { | ||||
|     desc: string, | ||||
|     src: OperandInfo, | ||||
|     dst: OperandInfo, | ||||
|     flags: bit_set[Flag], | ||||
|     word_size: WordSize, | ||||
|     reg_info: RegisterEncodingBits, | ||||
|     has_flip: bool, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user