Completed homework for 8086 simulator
This commit is contained in:
parent
60538301d5
commit
2900e508a1
7
8086_sim/.gitignore
vendored
7
8086_sim/.gitignore
vendored
@ -7,3 +7,10 @@ listing_0047_challenge_flags
|
|||||||
listing_0048_ip_register
|
listing_0048_ip_register
|
||||||
listing_0049_conditional_jumps
|
listing_0049_conditional_jumps
|
||||||
listing_0050_challenge_jumps
|
listing_0050_challenge_jumps
|
||||||
|
listing_0051_memory_mov
|
||||||
|
listing_0052_memory_add_loop
|
||||||
|
listing_0053_add_loop_challenge
|
||||||
|
listing_0054_draw_rectangle
|
||||||
|
test.asm
|
||||||
|
test
|
||||||
|
image.data
|
||||||
|
30
8086_sim/listing_0051_memory_mov.asm
Normal file
30
8086_sim/listing_0051_memory_mov.asm
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
; ========================================================================
|
||||||
|
;
|
||||||
|
; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved.
|
||||||
|
;
|
||||||
|
; This software is provided 'as-is', without any express or implied
|
||||||
|
; warranty. In no event will the authors be held liable for any damages
|
||||||
|
; arising from the use of this software.
|
||||||
|
;
|
||||||
|
; Please see https://computerenhance.com for further information
|
||||||
|
;
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
; ========================================================================
|
||||||
|
; LISTING 51
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
bits 16
|
||||||
|
|
||||||
|
mov word [1000], 1
|
||||||
|
mov word [1002], 2
|
||||||
|
mov word [1004], 3
|
||||||
|
mov word [1006], 4
|
||||||
|
|
||||||
|
mov bx, 1000
|
||||||
|
mov word [bx + 4], 10
|
||||||
|
|
||||||
|
mov bx, word [1000]
|
||||||
|
mov cx, word [1002]
|
||||||
|
mov dx, word [1004]
|
||||||
|
mov bp, word [1006]
|
36
8086_sim/listing_0052_memory_add_loop.asm
Normal file
36
8086_sim/listing_0052_memory_add_loop.asm
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
; ========================================================================
|
||||||
|
;
|
||||||
|
; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved.
|
||||||
|
;
|
||||||
|
; This software is provided 'as-is', without any express or implied
|
||||||
|
; warranty. In no event will the authors be held liable for any damages
|
||||||
|
; arising from the use of this software.
|
||||||
|
;
|
||||||
|
; Please see https://computerenhance.com for further information
|
||||||
|
;
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
; ========================================================================
|
||||||
|
; LISTING 52
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
bits 16
|
||||||
|
|
||||||
|
mov dx, 6
|
||||||
|
mov bp, 1000
|
||||||
|
|
||||||
|
mov si, 0
|
||||||
|
init_loop_start:
|
||||||
|
mov word [bp + si], si
|
||||||
|
add si, 2
|
||||||
|
cmp si, dx
|
||||||
|
jnz init_loop_start
|
||||||
|
|
||||||
|
mov bx, 0
|
||||||
|
mov si, 0
|
||||||
|
add_loop_start:
|
||||||
|
mov cx, word [bp + si]
|
||||||
|
add bx, cx
|
||||||
|
add si, 2
|
||||||
|
cmp si, dx
|
||||||
|
jnz add_loop_start
|
35
8086_sim/listing_0053_add_loop_challenge.asm
Normal file
35
8086_sim/listing_0053_add_loop_challenge.asm
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
; ========================================================================
|
||||||
|
;
|
||||||
|
; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved.
|
||||||
|
;
|
||||||
|
; This software is provided 'as-is', without any express or implied
|
||||||
|
; warranty. In no event will the authors be held liable for any damages
|
||||||
|
; arising from the use of this software.
|
||||||
|
;
|
||||||
|
; Please see https://computerenhance.com for further information
|
||||||
|
;
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
; ========================================================================
|
||||||
|
; LISTING 53
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
bits 16
|
||||||
|
|
||||||
|
mov dx, 6
|
||||||
|
mov bp, 1000
|
||||||
|
|
||||||
|
mov si, 0
|
||||||
|
init_loop_start:
|
||||||
|
mov word [bp + si], si
|
||||||
|
add si, 2
|
||||||
|
cmp si, dx
|
||||||
|
jnz init_loop_start
|
||||||
|
|
||||||
|
mov bx, 0
|
||||||
|
mov si, dx
|
||||||
|
sub bp, 2
|
||||||
|
add_loop_start:
|
||||||
|
add bx, word [bp + si]
|
||||||
|
sub si, 2
|
||||||
|
jnz add_loop_start
|
43
8086_sim/listing_0054_draw_rectangle.asm
Normal file
43
8086_sim/listing_0054_draw_rectangle.asm
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
; ========================================================================
|
||||||
|
;
|
||||||
|
; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved.
|
||||||
|
;
|
||||||
|
; This software is provided 'as-is', without any express or implied
|
||||||
|
; warranty. In no event will the authors be held liable for any damages
|
||||||
|
; arising from the use of this software.
|
||||||
|
;
|
||||||
|
; Please see https://computerenhance.com for further information
|
||||||
|
;
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
; ========================================================================
|
||||||
|
; LISTING 54
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
bits 16
|
||||||
|
|
||||||
|
; Start image after one row, to avoid overwriting our code!
|
||||||
|
mov bp, 64*4
|
||||||
|
|
||||||
|
mov dx, 0
|
||||||
|
y_loop_start:
|
||||||
|
|
||||||
|
mov cx, 0
|
||||||
|
x_loop_start:
|
||||||
|
; Fill pixel
|
||||||
|
mov word [bp + 0], cx ; Red
|
||||||
|
mov word [bp + 2], dx ; Blue
|
||||||
|
mov byte [bp + 3], 255 ; Alpha
|
||||||
|
|
||||||
|
; Advance pixel location
|
||||||
|
add bp, 4
|
||||||
|
|
||||||
|
; Advance X coordinate and loop
|
||||||
|
add cx, 1
|
||||||
|
cmp cx, 64
|
||||||
|
jnz x_loop_start
|
||||||
|
|
||||||
|
; Advance Y coordinate and loop
|
||||||
|
add dx, 1
|
||||||
|
cmp dx, 64
|
||||||
|
jnz y_loop_start
|
@ -1,22 +1,43 @@
|
|||||||
#include "include/aliases.h"
|
#include "include/aliases.h"
|
||||||
#include "include/flag_access.h"
|
#include "include/flag_access.h"
|
||||||
#include "include/reg_access.h"
|
#include "include/reg_access.h"
|
||||||
|
#include "include/sim86_instruction.h"
|
||||||
#include "include/sim86_lib.h"
|
#include "include/sim86_lib.h"
|
||||||
#include <bits/types/FILE.h>
|
#include <bits/types/FILE.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define MEM_SIZE (1 << 16)
|
#define MEM_SIZE (1 << 16)
|
||||||
|
#define BITS_PER_BYTE 8
|
||||||
|
|
||||||
struct basic_string {
|
struct basic_string {
|
||||||
char str[4096];
|
char str[4096];
|
||||||
};
|
};
|
||||||
|
|
||||||
u16 get_operand_value(instruction_operand operand);
|
struct membuf {
|
||||||
basic_string get_operand_string(instruction_operand operand);
|
u8 buffer[MEM_SIZE];
|
||||||
|
u64 mem_start;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mem_access_result {
|
||||||
|
u16 value;
|
||||||
|
u32 error;
|
||||||
|
};
|
||||||
|
|
||||||
|
u16 get_operand_value(instruction_operand operand, bool wide);
|
||||||
|
basic_string get_operand_string(instruction_operand operand, bool wide);
|
||||||
void print_instruction(instruction inst);
|
void print_instruction(instruction inst);
|
||||||
void mov_to_register(const register_access ®,
|
void mov_to_register(const register_access ®,
|
||||||
const instruction_operand &source);
|
const instruction_operand &source, bool wide);
|
||||||
|
void mov_to_memory(const effective_address_expression &addrexp,
|
||||||
|
const instruction_operand &source, bool wide);
|
||||||
|
mem_access_result get_mem_value(const effective_address_expression &addrexp,
|
||||||
|
bool wide);
|
||||||
|
mem_access_result set_mem_value(const effective_address_expression &addrexp,
|
||||||
|
u16 value, bool wide);
|
||||||
|
u16 get_mem_index(const effective_address_expression &addrexp);
|
||||||
|
|
||||||
|
static membuf memory;
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
@ -24,8 +45,8 @@ int main(int argc, char *argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 memory[MEM_SIZE];
|
memset((void *)memory.buffer, 0, MEM_SIZE);
|
||||||
memset((void *)memory, 0, MEM_SIZE);
|
memory.mem_start = 0;
|
||||||
|
|
||||||
const char *filename = argv[1];
|
const char *filename = argv[1];
|
||||||
|
|
||||||
@ -42,14 +63,14 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
fseek(fp, 0, SEEK_SET);
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
fread((void *)memory, sizeof(u8), size, fp);
|
fread((void *)memory.buffer, sizeof(u8), size, fp);
|
||||||
|
memory.mem_start = size + 1;
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
instruction_table table;
|
instruction_table table;
|
||||||
Sim86_Get8086InstructionTable(&table);
|
Sim86_Get8086InstructionTable(&table);
|
||||||
|
|
||||||
u32 mem_start = size + 1;
|
|
||||||
u32 offset = 0;
|
u32 offset = 0;
|
||||||
|
|
||||||
bool accessed_registers[REGISTER_COUNT] = {false};
|
bool accessed_registers[REGISTER_COUNT] = {false};
|
||||||
@ -58,10 +79,12 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
while (offset < size) {
|
while (offset < size) {
|
||||||
instruction decoded;
|
instruction decoded;
|
||||||
Sim86_Decode8086Instruction(size - offset, memory + offset, &decoded);
|
Sim86_Decode8086Instruction(size - offset, memory.buffer + offset,
|
||||||
|
&decoded);
|
||||||
|
|
||||||
if (decoded.Op) {
|
if (decoded.Op) {
|
||||||
offset += decoded.Size;
|
offset += decoded.Size;
|
||||||
|
bool wide = (decoded.Flags & Inst_Wide) == Inst_Wide;
|
||||||
|
|
||||||
print_instruction(decoded);
|
print_instruction(decoded);
|
||||||
|
|
||||||
@ -70,11 +93,12 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
switch (decoded.Op) {
|
switch (decoded.Op) {
|
||||||
case Op_mov: {
|
case Op_mov: {
|
||||||
|
|
||||||
if (dest.Type == Operand_Register) {
|
if (dest.Type == Operand_Register) {
|
||||||
mov_to_register(dest.Register, source);
|
mov_to_register(dest.Register, source, wide);
|
||||||
|
|
||||||
accessed_registers[dest.Register.Index] = true;
|
accessed_registers[dest.Register.Index] = true;
|
||||||
|
} else if (dest.Type == Operand_Memory) {
|
||||||
|
mov_to_memory(dest.Address, source, wide);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -83,7 +107,7 @@ int main(int argc, char *argv[]) {
|
|||||||
if (dest.Type == Operand_Register) {
|
if (dest.Type == Operand_Register) {
|
||||||
u16 value = get_register(dest.Register);
|
u16 value = get_register(dest.Register);
|
||||||
|
|
||||||
value += get_operand_value(source);
|
value += get_operand_value(source, wide);
|
||||||
set_flags(value);
|
set_flags(value);
|
||||||
|
|
||||||
set_register(dest.Register, value);
|
set_register(dest.Register, value);
|
||||||
@ -96,7 +120,7 @@ int main(int argc, char *argv[]) {
|
|||||||
if (dest.Type == Operand_Register) {
|
if (dest.Type == Operand_Register) {
|
||||||
u16 value = get_register(dest.Register);
|
u16 value = get_register(dest.Register);
|
||||||
|
|
||||||
value -= get_operand_value(source);
|
value -= get_operand_value(source, wide);
|
||||||
set_flags(value);
|
set_flags(value);
|
||||||
|
|
||||||
if (decoded.Op == Op_sub) {
|
if (decoded.Op == Op_sub) {
|
||||||
@ -108,7 +132,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
case Op_jne: {
|
case Op_jne: {
|
||||||
if (!get_flag(FLAG_ZERO)) {
|
if (!get_flag(FLAG_ZERO)) {
|
||||||
i16 inst_offset = get_operand_value(dest);
|
i16 inst_offset = get_operand_value(dest, wide);
|
||||||
|
|
||||||
offset += inst_offset;
|
offset += inst_offset;
|
||||||
}
|
}
|
||||||
@ -136,30 +160,54 @@ int main(int argc, char *argv[]) {
|
|||||||
printf("\nFinal flags:\n");
|
printf("\nFinal flags:\n");
|
||||||
print_flags();
|
print_flags();
|
||||||
|
|
||||||
|
#if 0 // Only needed (and working) for listing 0054
|
||||||
|
#define SIZE 64
|
||||||
|
#define BYTES SIZE * 4 * SIZE
|
||||||
|
|
||||||
|
u8 image[BYTES];
|
||||||
|
mempcpy(image, &(memory.buffer[memory.mem_start + (SIZE * 4)]), BYTES);
|
||||||
|
|
||||||
|
FILE *out = fopen("image.data", "wb");
|
||||||
|
|
||||||
|
fwrite(image, sizeof(u8), BYTES, out);
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 get_operand_value(instruction_operand operand) {
|
u16 get_operand_value(instruction_operand operand, bool wide) {
|
||||||
|
u16 output = 0;
|
||||||
|
|
||||||
switch (operand.Type) {
|
switch (operand.Type) {
|
||||||
case Operand_Register:
|
case Operand_Register:
|
||||||
return get_register(operand.Register);
|
output = get_register(operand.Register);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Operand_Memory:
|
case Operand_Memory: {
|
||||||
return 0;
|
mem_access_result result = get_mem_value(operand.Address, wide);
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
output = result.value;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Operand_Immediate:
|
case Operand_Immediate:
|
||||||
return operand.Immediate.Value;
|
output = operand.Immediate.Value;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return 0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
basic_string get_operand_string(instruction_operand operand) {
|
basic_string get_operand_string(instruction_operand operand, bool wide) {
|
||||||
basic_string output = {""};
|
basic_string output = {""};
|
||||||
|
|
||||||
switch (operand.Type) {
|
switch (operand.Type) {
|
||||||
@ -167,10 +215,27 @@ basic_string get_operand_string(instruction_operand operand) {
|
|||||||
sprintf(output.str, "%s", get_register_name(operand.Register));
|
sprintf(output.str, "%s", get_register_name(operand.Register));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Operand_Memory:
|
case Operand_Memory: {
|
||||||
sprintf(output.str, "%s", "MEM OPERAND");
|
char mem_string[1024] = {0};
|
||||||
|
|
||||||
|
register_access reg1 = operand.Address.Terms[0].Register;
|
||||||
|
if (reg1.Index != 0) {
|
||||||
|
sprintf(mem_string, "%s + ", get_register_name(reg1));
|
||||||
|
}
|
||||||
|
|
||||||
|
register_access reg2 = operand.Address.Terms[1].Register;
|
||||||
|
if (reg2.Index != 0) {
|
||||||
|
strcat(mem_string, get_register_name(reg2));
|
||||||
|
} else {
|
||||||
|
u32 length = strlen(mem_string);
|
||||||
|
|
||||||
|
sprintf(&(mem_string[length]), "%d", operand.Address.Displacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(output.str, "%s [%s]", wide ? "word" : "byte", mem_string);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Operand_Immediate:
|
case Operand_Immediate:
|
||||||
sprintf(output.str, "%d", operand.Immediate.Value);
|
sprintf(output.str, "%d", operand.Immediate.Value);
|
||||||
|
|
||||||
@ -183,13 +248,15 @@ basic_string get_operand_string(instruction_operand operand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void print_instruction(instruction inst) {
|
void print_instruction(instruction inst) {
|
||||||
|
bool wide = (inst.Flags & Inst_Wide) == Inst_Wide;
|
||||||
|
|
||||||
printf("\t%s %s, %s\n", Sim86_MnemonicFromOperationType(inst.Op),
|
printf("\t%s %s, %s\n", Sim86_MnemonicFromOperationType(inst.Op),
|
||||||
get_operand_string(inst.Operands[0]).str,
|
get_operand_string(inst.Operands[0], wide).str,
|
||||||
get_operand_string(inst.Operands[1]).str);
|
get_operand_string(inst.Operands[1], wide).str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mov_to_register(const register_access ®,
|
void mov_to_register(const register_access ®,
|
||||||
const instruction_operand &source) {
|
const instruction_operand &source, bool wide) {
|
||||||
switch (source.Type) {
|
switch (source.Type) {
|
||||||
case Operand_Immediate:
|
case Operand_Immediate:
|
||||||
set_register(reg, source.Immediate.Value);
|
set_register(reg, source.Immediate.Value);
|
||||||
@ -197,7 +264,94 @@ void mov_to_register(const register_access ®,
|
|||||||
case Operand_Register:
|
case Operand_Register:
|
||||||
set_register(reg, get_register(source.Register));
|
set_register(reg, get_register(source.Register));
|
||||||
break;
|
break;
|
||||||
|
case Operand_Memory: {
|
||||||
|
mem_access_result result = get_mem_value(source.Address, wide);
|
||||||
|
|
||||||
|
if (!result.error) {
|
||||||
|
set_register(reg, result.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mov_to_memory(const effective_address_expression &addrexp,
|
||||||
|
const instruction_operand &source, bool wide) {
|
||||||
|
switch (source.Type) {
|
||||||
|
case Operand_Immediate:
|
||||||
|
set_mem_value(addrexp, source.Immediate.Value, wide);
|
||||||
|
break;
|
||||||
|
case Operand_Register:
|
||||||
|
set_mem_value(addrexp, get_register(source.Register), wide);
|
||||||
|
break;
|
||||||
|
case Operand_Memory: {
|
||||||
|
mem_access_result result = get_mem_value(source.Address, wide);
|
||||||
|
|
||||||
|
if (!result.error) {
|
||||||
|
set_mem_value(addrexp, result.value, wide);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_access_result get_mem_value(const effective_address_expression &addrexp,
|
||||||
|
bool wide) {
|
||||||
|
u16 index = get_mem_index(addrexp);
|
||||||
|
|
||||||
|
mem_access_result result = {0, 0};
|
||||||
|
|
||||||
|
if (memory.mem_start + index >= MEM_SIZE) {
|
||||||
|
result.error = 1;
|
||||||
|
} else {
|
||||||
|
result.value |= memory.buffer[memory.mem_start + index];
|
||||||
|
|
||||||
|
if (wide) {
|
||||||
|
result.value |= (memory.buffer[memory.mem_start + index + 1]
|
||||||
|
<< (wide ? BITS_PER_BYTE : 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_access_result set_mem_value(const effective_address_expression &addrexp,
|
||||||
|
u16 value, bool wide) {
|
||||||
|
u16 index = get_mem_index(addrexp);
|
||||||
|
|
||||||
|
mem_access_result result = {0, 0};
|
||||||
|
|
||||||
|
if (memory.mem_start + index >= MEM_SIZE) {
|
||||||
|
result.error = 1;
|
||||||
|
} else {
|
||||||
|
memory.buffer[memory.mem_start + index] = (u8)value;
|
||||||
|
|
||||||
|
if (wide) {
|
||||||
|
memory.buffer[memory.mem_start + index + 1] =
|
||||||
|
(u8)(value >> (wide ? BITS_PER_BYTE : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
result.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 get_mem_index(const effective_address_expression &addrexp) {
|
||||||
|
u16 index = addrexp.Displacement;
|
||||||
|
|
||||||
|
const u16 term_count = 2;
|
||||||
|
for (u16 i = 0; i < term_count; ++i) {
|
||||||
|
if (addrexp.Terms[i].Register.Index != 0) {
|
||||||
|
index += get_register(addrexp.Terms[i].Register);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user