implement conditional jumps
This commit is contained in:
parent
6238b07cdd
commit
0d7a1beedd
23
examples/48_ip_register.asm
Normal file
23
examples/48_ip_register.asm
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
; ========================================================================
|
||||||
|
;
|
||||||
|
; (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 48
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
bits 16
|
||||||
|
|
||||||
|
mov cx, 200
|
||||||
|
mov bx, cx
|
||||||
|
add cx, 1000
|
||||||
|
mov bx, 2000
|
||||||
|
sub cx, bx
|
12
examples/48_ip_register.txt
Normal file
12
examples/48_ip_register.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
--- test\listing_0048_ip_register execution ---
|
||||||
|
mov cx, 200 ; cx:0x0->0xc8 ip:0x0->0x3
|
||||||
|
mov bx, cx ; bx:0x0->0xc8 ip:0x3->0x5
|
||||||
|
add cx, 1000 ; cx:0xc8->0x4b0 ip:0x5->0x9 flags:->A
|
||||||
|
mov bx, 2000 ; bx:0xc8->0x7d0 ip:0x9->0xc
|
||||||
|
sub cx, bx ; cx:0x4b0->0xfce0 ip:0xc->0xe flags:A->CS
|
||||||
|
|
||||||
|
Final registers:
|
||||||
|
bx: 0x07d0 (2000)
|
||||||
|
cx: 0xfce0 (64736)
|
||||||
|
ip: 0x000e (14)
|
||||||
|
flags: CS
|
24
examples/49_conditional_jumps.asm
Normal file
24
examples/49_conditional_jumps.asm
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
; ========================================================================
|
||||||
|
;
|
||||||
|
; (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 49
|
||||||
|
; ========================================================================
|
||||||
|
|
||||||
|
bits 16
|
||||||
|
|
||||||
|
mov cx, 3
|
||||||
|
mov bx, 1000
|
||||||
|
loop_start:
|
||||||
|
add bx, 10
|
||||||
|
sub cx, 1
|
||||||
|
jnz loop_start
|
17
examples/49_conditional_jumps.txt
Normal file
17
examples/49_conditional_jumps.txt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
--- test\listing_0049_conditional_jumps execution ---
|
||||||
|
mov cx, 3 ; cx:0x0->0x3 ip:0x0->0x3
|
||||||
|
mov bx, 1000 ; bx:0x0->0x3e8 ip:0x3->0x6
|
||||||
|
add bx, 10 ; bx:0x3e8->0x3f2 ip:0x6->0x9 flags:->A
|
||||||
|
sub cx, 1 ; cx:0x3->0x2 ip:0x9->0xc flags:A->
|
||||||
|
jne $-6 ; ip:0xc->0x6
|
||||||
|
add bx, 10 ; bx:0x3f2->0x3fc ip:0x6->0x9 flags:->P
|
||||||
|
sub cx, 1 ; cx:0x2->0x1 ip:0x9->0xc flags:P->
|
||||||
|
jne $-6 ; ip:0xc->0x6
|
||||||
|
add bx, 10 ; bx:0x3fc->0x406 ip:0x6->0x9 flags:->PA
|
||||||
|
sub cx, 1 ; cx:0x1->0x0 ip:0x9->0xc flags:PA->PZ
|
||||||
|
jne $-6 ; ip:0xc->0xe
|
||||||
|
|
||||||
|
Final registers:
|
||||||
|
bx: 0x0406 (1030)
|
||||||
|
ip: 0x000e (14)
|
||||||
|
flags: PZ
|
14
src/main.c
14
src/main.c
@ -87,7 +87,7 @@ err:
|
|||||||
int dissassemble(FILE *src, FILE *dst) {
|
int dissassemble(FILE *src, FILE *dst) {
|
||||||
fprintf(dst, "bits 16\n\n");
|
fprintf(dst, "bits 16\n\n");
|
||||||
|
|
||||||
struct memory mem = { .mem = { 0xFF } };
|
struct memory mem = { 0 };
|
||||||
int byte_count = load_mem_from_stream(&mem, src, 0);
|
int byte_count = load_mem_from_stream(&mem, src, 0);
|
||||||
if (byte_count == -1) {
|
if (byte_count == -1) {
|
||||||
fprintf(stderr, "ERROR: Failed to load file to memory\n");
|
fprintf(stderr, "ERROR: Failed to load file to memory\n");
|
||||||
@ -96,7 +96,7 @@ int dissassemble(FILE *src, FILE *dst) {
|
|||||||
|
|
||||||
char buff[256];
|
char buff[256];
|
||||||
struct instruction inst;
|
struct instruction inst;
|
||||||
u32 inst_address = 0;
|
u16 inst_address = 0;
|
||||||
while (inst_address < byte_count) {
|
while (inst_address < byte_count) {
|
||||||
enum decode_error err = decode_instruction(&mem, &inst_address, &inst);
|
enum decode_error err = decode_instruction(&mem, &inst_address, &inst);
|
||||||
if (err == DECODE_ERR_EOF) break;
|
if (err == DECODE_ERR_EOF) break;
|
||||||
@ -114,7 +114,7 @@ int dissassemble(FILE *src, FILE *dst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int simulate(FILE *src) {
|
int simulate(FILE *src) {
|
||||||
struct memory mem;
|
struct memory mem = { 0 };
|
||||||
int byte_count = load_mem_from_stream(&mem, src, 0);
|
int byte_count = load_mem_from_stream(&mem, src, 0);
|
||||||
if (byte_count == -1) {
|
if (byte_count == -1) {
|
||||||
fprintf(stderr, "ERROR: Failed to load file to memory\n");
|
fprintf(stderr, "ERROR: Failed to load file to memory\n");
|
||||||
@ -123,12 +123,11 @@ int simulate(FILE *src) {
|
|||||||
|
|
||||||
struct cpu_state state = { 0 };
|
struct cpu_state state = { 0 };
|
||||||
struct instruction inst;
|
struct instruction inst;
|
||||||
u32 inst_address = 0;
|
while (state.ip < byte_count) {
|
||||||
while (inst_address < byte_count) {
|
enum decode_error err = decode_instruction(&mem, &state.ip, &inst);
|
||||||
enum decode_error err = decode_instruction(&mem, &inst_address, &inst);
|
|
||||||
if (err == DECODE_ERR_EOF) break;
|
if (err == DECODE_ERR_EOF) break;
|
||||||
if (err != DECODE_OK) {
|
if (err != DECODE_OK) {
|
||||||
fprintf(stderr, "ERROR: Failed to decode instruction at 0x%08x: %s\n", inst_address, decode_error_to_str(err));
|
fprintf(stderr, "ERROR: Failed to decode instruction at 0x%08x: %s\n", state.ip, decode_error_to_str(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
execute_instruction(&state, &inst);
|
execute_instruction(&state, &inst);
|
||||||
@ -142,6 +141,7 @@ int simulate(FILE *src) {
|
|||||||
printf(" bp: 0x%04x (%d)\n", state.bp, state.bp);
|
printf(" bp: 0x%04x (%d)\n", state.bp, state.bp);
|
||||||
printf(" si: 0x%04x (%d)\n", state.si, state.si);
|
printf(" si: 0x%04x (%d)\n", state.si, state.si);
|
||||||
printf(" di: 0x%04x (%d)\n", state.di, state.di);
|
printf(" di: 0x%04x (%d)\n", state.di, state.di);
|
||||||
|
printf(" ip: 0x%04x (%d)\n", state.ip, state.ip);
|
||||||
printf(" flags: %s%s\n", state.flags.sign ? "S" : "", state.flags.zero ? "Z" : "");
|
printf(" flags: %s%s\n", state.flags.sign ? "S" : "", state.flags.zero ? "Z" : "");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#define panic(...) fprintf(stderr, "PANIC(%s:%d): ", __FILE__, __LINE__); fprintf(stderr, __VA_ARGS__); abort()
|
#define panic(...) fprintf(stderr, "PANIC(%s:%d): ", __FILE__, __LINE__); fprintf(stderr, __VA_ARGS__); abort()
|
||||||
#define todo(...) fprintf(stderr, "TODO(%s:%d): ", __FILE__, __LINE__); fprintf(stderr, __VA_ARGS__); abort()
|
#define todo(...) fprintf(stderr, "TODO(%s:%d): ", __FILE__, __LINE__); fprintf(stderr, __VA_ARGS__); abort()
|
||||||
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||||
#define MEMORY_SIZE (1024 * 1024) // 1 MiB
|
#define MEMORY_SIZE 65536 // 2^16
|
||||||
|
|
||||||
enum operation {
|
enum operation {
|
||||||
OP_MOV,
|
OP_MOV,
|
||||||
@ -121,4 +121,6 @@ struct cpu_state {
|
|||||||
bool sign;
|
bool sign;
|
||||||
// TODO: Add all flags
|
// TODO: Add all flags
|
||||||
} flags;
|
} flags;
|
||||||
|
|
||||||
|
u16 ip;
|
||||||
};
|
};
|
@ -74,7 +74,7 @@ static enum mem_base decode_mem_base(u8 rm) {
|
|||||||
static void decode_reg_or_mem(
|
static void decode_reg_or_mem(
|
||||||
struct reg_or_mem_value *value,
|
struct reg_or_mem_value *value,
|
||||||
struct memory *mem,
|
struct memory *mem,
|
||||||
u32 *addr,
|
u16 *addr,
|
||||||
u8 rm,
|
u8 rm,
|
||||||
u8 mod,
|
u8 mod,
|
||||||
bool wide
|
bool wide
|
||||||
@ -110,7 +110,7 @@ static void decode_reg_or_mem(
|
|||||||
static void deocde_reg_or_mem_to_src(
|
static void deocde_reg_or_mem_to_src(
|
||||||
struct src_value *value,
|
struct src_value *value,
|
||||||
struct memory *mem,
|
struct memory *mem,
|
||||||
u32 *addr,
|
u16 *addr,
|
||||||
u8 rm,
|
u8 rm,
|
||||||
u8 mod,
|
u8 mod,
|
||||||
bool wide
|
bool wide
|
||||||
@ -129,7 +129,7 @@ static void deocde_reg_or_mem_to_src(
|
|||||||
// TODO: change to readinf from a byte buffer
|
// TODO: change to readinf from a byte buffer
|
||||||
// TODO: add handling for 'DECODE_ERR_MISSING_BYTES'
|
// TODO: add handling for 'DECODE_ERR_MISSING_BYTES'
|
||||||
// Handy reference: Table 4-12. 8086 Instruction Encoding
|
// Handy reference: Table 4-12. 8086 Instruction Encoding
|
||||||
enum decode_error decode_instruction(struct memory *mem, u32 *addr, struct instruction *output) {
|
enum decode_error decode_instruction(struct memory *mem, u16 *addr, struct instruction *output) {
|
||||||
u8 byte1 = pull_byte_at(mem, addr);
|
u8 byte1 = pull_byte_at(mem, addr);
|
||||||
|
|
||||||
// MOVE: Register memory to/from register
|
// MOVE: Register memory to/from register
|
||||||
|
@ -25,11 +25,11 @@ int load_mem_from_file(struct memory *mem, const char *filename, u32 start) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make this error some kind of error, when reading past end
|
// TODO: Make this error some kind of error, when reading past end
|
||||||
u8 read_byte_at(struct memory *mem, u32 address) {
|
u8 read_byte_at(struct memory *mem, u16 address) {
|
||||||
return mem->mem[address % MEMORY_SIZE];
|
return mem->mem[address % MEMORY_SIZE];
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 pull_byte_at(struct memory *mem, u32 *address) {
|
u8 pull_byte_at(struct memory *mem, u16 *address) {
|
||||||
u8 byte = read_byte_at(mem, *address);
|
u8 byte = read_byte_at(mem, *address);
|
||||||
(*address)++;
|
(*address)++;
|
||||||
return byte;
|
return byte;
|
||||||
|
@ -196,7 +196,14 @@ void execute_instruction(struct cpu_state *state, struct instruction *inst) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
case OP_JNE: {
|
||||||
|
if (!state->flags.zero) {
|
||||||
|
i8 jmp_offset = inst->jmp_offset;
|
||||||
|
state->ip += jmp_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
} default:
|
||||||
todo("Unhandled instruction execution '%s'\n", operation_to_str(inst->op));
|
todo("Unhandled instruction execution '%s'\n", operation_to_str(inst->op));
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user