CF, OF, and PF flags, keep values as i16, update ref test script
This commit is contained in:
		
							parent
							
								
									5cf4768b80
								
							
						
					
					
						commit
						731e5bd45d
					
				| @ -119,11 +119,11 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr | ||||
|         if inst.has_sign_extension { | ||||
|             word_signed &&= data[0] & 0b0000_0010 == 0 | ||||
|         } | ||||
|         value: u16 = word_signed ? u16(get_i16(data[data_idx:])) : u16(data[data_idx]) | ||||
|         value: i16 = word_signed ? get_i16(data[data_idx:]) : i16(i8(data[data_idx])) | ||||
|         operand = Immediate { value = value, size = word_signed ? .Signed16 : .Signed8 } | ||||
|         processed^ += word_signed ? 2 : 1 | ||||
|     case .ImmediateUnsigned: | ||||
|         operand = Immediate { value = u16(data[processed^]), size = .Unsigned8 } | ||||
|         operand = Immediate { value = i16(data[processed^]), size = .Unsigned8 } | ||||
|         processed^ += 1 | ||||
|     case .Accumulator: | ||||
|         operand = RegisterId { name = Register(0), access = word ? .Full : .Low } | ||||
| @ -155,7 +155,7 @@ parse_operand :: proc(inst: InstructionInfo, opinfo: OperandInfo, data: []u8, pr | ||||
|         processed^ += 1 | ||||
|     case .DirectWithinSegment: | ||||
|         value := (int)(get_i16(data[1:])) + CPU.total_bytes_processed + 3 | ||||
|         operand = Immediate { value = u16(value), size = .Signed16 } | ||||
|         operand = Immediate { value = i16(value), size = .Signed16 } | ||||
|         processed^ += 2 | ||||
|     case .Intersegment: | ||||
|         operand = Intersegment { | ||||
|  | ||||
| @ -6,30 +6,31 @@ import "core:math" | ||||
| import "core:strings" | ||||
| import "core:reflect" | ||||
| 
 | ||||
| get_operand_value :: proc(operand: Operand) -> u16 { | ||||
| get_operand_value :: proc(operand: Operand) -> i16 { | ||||
|     #partial switch opr in operand { | ||||
|     case Immediate: | ||||
|         return opr.value | ||||
|         // fmt.printfln("0x%4x %d", i16(opr.value), opr.value) | ||||
|         return i16(opr.value) | ||||
|     case RegisterId: | ||||
|         reg_val := CPU.registers[opr.name] | ||||
|         switch opr.access { | ||||
|         case .Low, .High: | ||||
|             return u16(opr.access == .Low ? reg_val.low : reg_val.high) | ||||
|             return i16(opr.access == .Low ? reg_val.low : reg_val.high) | ||||
|         case .Full: | ||||
|             return reg_val.full | ||||
|             return i16(reg_val.full) | ||||
|         } | ||||
|     } | ||||
|     return 0 | ||||
| } | ||||
| 
 | ||||
| set_register_value :: proc(reg: RegisterId, value: u16) { | ||||
| set_register_value :: proc(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 = u16(value) | ||||
|         CPU.registers[reg.name].full = i16(value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -38,12 +39,40 @@ get_cpu_register_by_name :: proc(cpu: ^Cpu, name: string) -> ^RegisterValue { | ||||
|     return &cpu.registers[reg] | ||||
| } | ||||
| 
 | ||||
| check_zero_flag :: proc(value: u16) { | ||||
| check_zero_flag :: proc(value: i16) { | ||||
|     CPU.flags[.ZF] = value == 0 | ||||
| } | ||||
| 
 | ||||
| check_sign_flag :: proc(value: u16) { | ||||
|     CPU.flags[.SF] = value >> 15 == 1 | ||||
| check_sign_flag :: proc(value: i16) { | ||||
|     CPU.flags[.SF] = (value >> 15) & 0x1 == 1 | ||||
| } | ||||
| 
 | ||||
| check_carry_flag :: proc(dst: i16, src: i16, is_add: bool) { | ||||
|     CPU.flags[.CF] = is_add ? u32(dst) + u32(src) > 0xFFFF : src > dst | ||||
| } | ||||
| 
 | ||||
| check_parity_flag :: proc(value: i16) { | ||||
|     val := value | ||||
|     bit_count := 0 | ||||
|     val &= 0x00FF | ||||
|     for val != 0 { | ||||
|         if val & 0x1 == 1 { | ||||
|             bit_count += 1 | ||||
|         } | ||||
|         val >>= 1 | ||||
|     } | ||||
|     CPU.flags[.PF] = val % 2 == 0 | ||||
| } | ||||
| 
 | ||||
| check_auxiliary_carry_flag :: proc(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(value: i16) { | ||||
|     check_zero_flag(value) | ||||
|     check_sign_flag(value) | ||||
|     check_parity_flag(value) | ||||
| } | ||||
| 
 | ||||
| execute_instruction :: proc(inst: Instruction) { | ||||
| @ -54,21 +83,27 @@ execute_instruction :: proc(inst: Instruction) { | ||||
|             set_register_value(reg, src_val) | ||||
|         case .ADD: | ||||
|             src_val := get_operand_value(inst.src) | ||||
|             val := CPU.registers[reg.name].full + src_val | ||||
|             dst_val := get_operand_value(inst.dst) | ||||
|             val := i16(CPU.registers[reg.name].full) + src_val | ||||
|             set_register_value(reg, val) | ||||
|             check_zero_flag(val) | ||||
|             check_sign_flag(val) | ||||
|             check_flags(val) | ||||
|             check_auxiliary_carry_flag(dst_val, src_val, true) | ||||
|             check_carry_flag(dst_val, src_val, true) | ||||
|         case .SUB: | ||||
|             src_val := get_operand_value(inst.src) | ||||
|             val := CPU.registers[reg.name].full - src_val | ||||
|             dst_val := get_operand_value(inst.dst) | ||||
|             val := i16(CPU.registers[reg.name].full) - src_val | ||||
|             set_register_value(reg, val) | ||||
|             check_zero_flag(val) | ||||
|             check_sign_flag(val) | ||||
|             check_flags(val) | ||||
|             check_auxiliary_carry_flag(dst_val, src_val, false) | ||||
|             check_carry_flag(dst_val, src_val, false) | ||||
|         case .CMP: | ||||
|             src_val := get_operand_value(inst.src) | ||||
|             val := CPU.registers[reg.name].full - src_val | ||||
|             check_zero_flag(val) | ||||
|             check_sign_flag(val) | ||||
|             dst_val := get_operand_value(inst.dst) | ||||
|             val := i16(CPU.registers[reg.name].full) - src_val | ||||
|             check_flags(val) | ||||
|             check_auxiliary_carry_flag(dst_val, src_val, false) | ||||
|             check_carry_flag(dst_val, src_val, false) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										23
									
								
								sim8086.odin
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								sim8086.odin
									
									
									
									
									
								
							| @ -43,33 +43,40 @@ main :: proc() { | ||||
|     } | ||||
| 
 | ||||
|     if what_to_print == "registers" || what_to_print == "all" { | ||||
|         fmt.println("\nRegisters") | ||||
|         fmt.println("Registers") | ||||
|         for reg_val,name in CPU.registers { | ||||
|             full := fmt.aprintf("%s: %d ", name, reg_val.full) | ||||
|             hex := fmt.aprintf("0x%04x ", reg_val.full) | ||||
|             full := fmt.aprintf("%s: %d ", name, i16(reg_val.full)) | ||||
|             hex := fmt.aprintf("0x%04x ", u16(reg_val.full)) | ||||
|             fmt.printf("%s %*[1]s %s %*[4]s %08b %08b", | ||||
|                        full, 18 - len(full), "|", hex, 10 - len(hex), "|", reg_val.high, reg_val.low) | ||||
|             fmt.println() | ||||
|         } | ||||
|         fmt.println("\nFlags") | ||||
|         for state,flag in CPU.flags { | ||||
|             fmt.printfln("%c: %d",reflect.enum_string(flag)[0], state ? 1 : 0) | ||||
|             fmt.printf("%c:%d  ",reflect.enum_string(flag)[0], state ? 1 : 0) | ||||
|         } | ||||
|         fmt.println() | ||||
| 
 | ||||
|         failed_ref: bool | ||||
|         path,ok := strings.replace(os.args[1], ".bin", ".txt", 1) | ||||
|         ref_cpu,_ := extract_reference_cpu_state(path) | ||||
|         for reg_val,name in ref_cpu.registers { | ||||
|             if CPU.registers[name].full != reg_val.full { | ||||
|                 msg := "%s register does not match reference - Expected %04x | Actual %04x" | ||||
|                 fmt.eprintfln(msg, name, reg_val.full, CPU.registers[name].full) | ||||
|                 msg := "%s register does not match reference - Expected 0x%04x | Actual 0x%04x" | ||||
|                 fmt.printfln(msg, name, reg_val.full, CPU.registers[name].full) | ||||
|                 failed_ref = true | ||||
|             } | ||||
|         } | ||||
|         for f in Flag { | ||||
|             if ref_cpu.flags[f] != CPU.flags[f] { | ||||
|                 msg := "%s flag does not match reference - Expected %t | Actual %t" | ||||
|                 fmt.eprintfln(msg, f, ref_cpu.flags[f], CPU.flags[f]) | ||||
|                 msg := "%s flag does not match reference - Expected %d | Actual %d" | ||||
|                 fmt.printfln(msg, f, ref_cpu.flags[f] ? 1 : 0, CPU.flags[f] ? 1 : 0) | ||||
|                 failed_ref = true | ||||
|             } | ||||
|         } | ||||
|         if failed_ref { | ||||
|             os.exit(1) | ||||
|         } | ||||
|     } | ||||
|     if what_to_print == "instructions" || what_to_print == "all" { | ||||
|         print_instructions_stdout(instructions_list[:]) | ||||
|  | ||||
| @ -16,13 +16,14 @@ odin build . -out:sim8086 | ||||
| for asm_txt in asm_files/*.txt; | ||||
| do | ||||
|     asm_listing=$(basename $asm_txt .txt) | ||||
|     ./sim8086 asm_files/${asm_listing}.bin registers | awk '{print $1 $4}' | sort > temp1 | ||||
|     cat $asm_txt | awk '/Final registers/,0' | tail -n +2 | awk '{print $1 $2}' | sort > temp2 | ||||
|     diff -U0 --color temp1 temp2 | ||||
|     output=$(./sim8086 asm_files/${asm_listing}.bin registers) | ||||
|     if [ $? -eq 1 ]; then | ||||
|         echo Listing $asm_listing Failed! | ||||
|         echo -e "Listing $asm_listing ${RED}Failed!${NC}" | ||||
|         echo "$output" | while IFS= read -r line; do | ||||
|             echo "$line" | ||||
|         done | ||||
|         echo -e "" | ||||
|     else | ||||
|         echo Listing $asm_listing Succeded! | ||||
|         echo -e "Listing $asm_listing: ${GREEN}Succeded!${NC}" | ||||
|     fi | ||||
| done | ||||
| rm temp1 temp2 | ||||
| @ -44,7 +44,7 @@ extract_reference_cpu_state :: proc(filename: string) -> (Cpu, bool) { | ||||
|                     reg_value := get_cpu_register_by_name(&cpu, reg_name) | ||||
|                     hex_string := line[i+6:i+10] | ||||
|                     if hex_num,ok := strconv.parse_int(hex_string, 16); ok { | ||||
|                         reg_value^.full = u16(hex_num) | ||||
|                         reg_value^.full = i16(hex_num) | ||||
|                     } | ||||
|                 } | ||||
|                 break | ||||
|  | ||||
| @ -19,7 +19,7 @@ RegisterValue :: struct #raw_union { | ||||
|     using _: struct { | ||||
|         low, high: byte, | ||||
|     }, | ||||
|     full: u16, | ||||
|     full: i16, | ||||
| } | ||||
| 
 | ||||
| Flag :: enum { | ||||
| @ -69,7 +69,7 @@ ImmediateSize :: enum { | ||||
|     Signed16, | ||||
| } | ||||
| Immediate :: struct { | ||||
|     value: u16, | ||||
|     value: i16, | ||||
|     size: ImmediateSize, | ||||
| } | ||||
| MemoryAddr :: struct { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user