-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Combine with gbit and pass all the test #15
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not copy GBIT source files. Instead, use git submodule and apply necessary patches if any.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explain the instruction test in the top-level README.md
Now the code emission for the instruction tester is put in |
More comments are added for the instruction tester now. |
Makefile
Outdated
@@ -19,12 +19,30 @@ else | |||
endif | |||
|
|||
OUT ?= build | |||
SHELL_HACK := $(shell mkdir -p $(OUT)) | |||
INSTR_TEST_OUT ?= build/tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace INSTR_TEST_OUT ?= build/tests
with INSTR_TEST_OUT := $(OUT)/tests
because it was not intended to be set directly.
README.md
Outdated
@@ -597,6 +597,29 @@ one of these RAM banks would be chosen to mapped at `0xA000` to `0xBFFF` by MBC, | |||
state can be restored. When closing jitboy, contents in RAM banks should be copied to the file | |||
with the name we mentioned before. | |||
|
|||
## Instruction test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change it to "Instruction compliance tests"
README.md
Outdated
However, some limitations on jitboy cause problems to integrate with it. So we need to apply | ||
some approaches to get over them. | ||
|
||
* For jitboy, instructions are not expected to be executed one by one, which is how the tester |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The statement "For jitboy, instructions are not expected to be executed one by one, which is how the tester tests the instructions." is not informative. Instead, you can say, "Due to the JIT compilation, not each instruction is executed at one time."
README.md
Outdated
write the same value in the same position again. | ||
* For instructions that write two bytes, another macro `ld16` will be used for `gbz80_mmu_write` | ||
calling | ||
* We borrow `0xfc` and `0xfd` which are the two invalid opcodes in Game Boy for the status |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should explain how the original opcodes work and why you picked them up.
src/gbz80.c
Outdated
* build it at the init stage and then cache it for reusing to avoid spending | ||
* time on avoidable codegen. | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't leave the blank line. The comment should be very close to the corresponding implementation.
By the way, we can make use of GitHub Actions for CI/CD after the pull request is merged. |
Makefile
Outdated
$(INSTR_TEST_OUT)/%.o: tests/%.c | ||
$(CC) -o $@ -c $(CFLAGS) $< -MMD -MF $@.d | ||
|
||
$(INSTR_TEST_OUT)/%.o: src/%.c |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dislike the build rules on src
directory. Can you eliminate them? The dependency of the source files in src
directory should be already scratched.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confusing about this. Since if this rule is removed, then we can't build the target for the instruction test.
Note that I have separated the object files for jitboy and the instruction tester for the INSTRUCTION_TEST
definition, although some of the object files are the same. And this is for if someone executes make all
before make check
, he/she can still retrieve the correct build target. Please tell me if my approach is not good for solving this problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not necessary to create a new directory $(INSTR_TEST_OUT)
. You can use String Substitution to filter-out and replace the names of object files. e.g. build/emit-instr-test.o
Of course, you have to generate the corresponding build/emit-instr-test.c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we don't need emit-instr-test.c
? Since the file emit.c
which is generated by DynASM hasn't been preprocessed, it will be fine to share the same emit.c
between jitboy and instruction tester binary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My idea is to share the built objects as possible as we can. We can benefit from shorter build time and cleaner rules. However, we have to consider the scenario when instruction tester is about to be built right after target "all" is done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. But now I stuck on trading off between cleaner rules and the ability to share the built objects since I'm not so familiar with Makefile. I'll try to figure out the better approach and asking you to review it after that. 😢
src/gbz80.h
Outdated
@@ -11,4 +11,24 @@ bool compile(gb_block *block, | |||
|
|||
bool optimize_block(GList **instructions, int opt_level); | |||
|
|||
#ifdef INSTRUCTION_TEST | |||
struct inst_info { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use instr_info
rather than inst_info
.
inst
is a common term. See: https://en.wikipedia.org/wiki/Inst
tests/instr_test.c
Outdated
printf(" -h, --help Show this help.\n"); | ||
} | ||
|
||
static int parse_args(int argc, char **argv) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use bool
instead of plain int
.
tests/instr_test.c
Outdated
build_load_flag_block(load_flag_block); | ||
} | ||
|
||
void gbz80_close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Declare this function as "static."
src/gbz80.c
Outdated
gbz80_inst *inst = g_new(gbz80_inst, 1); | ||
|
||
uint8_t opcode = mem->mem[pc]; | ||
bool iscb = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is_cb
would be better for readability.
GList *instructions = NULL; | ||
|
||
/* run the fake instruction for flag setting */ | ||
gbz80_inst *inst_before = g_new(gbz80_inst, 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Later, you can submit a new pull request for gbz80_instr
name scheme consistency. It was my fault.
tests/instr_test.c
Outdated
static gb_vm *vm = NULL; | ||
|
||
/* since jitboy only update pc when doing instruction jmp/call | ||
* so we trickly use a fake one and count it independently to pass gbit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The wording "a fake one" might be misleading. You can say, "introduce an indirect layer for memory/register manipulation."
src/dasm_macros.inc
Outdated
|| gbz80_mmu_write(addr + 1, (value >> 8) & 0xff); | ||
|| } | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cut this blank line.
src/gbz80.c
Outdated
#ifdef INSTRUCTION_TEST | ||
/* To do code generating for flag setting and flag reloading which are | ||
* required for the instruction tester. Opcodes `0xfc` and `0xfd` which | ||
* are invalid opcodes in original Game Boy are borrowed for the purpose */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace "borrowed" with "diverted."
tests/instr_test.c
Outdated
uint16_t ret = block->func(&vm->state); | ||
|
||
/* Due to the JIT compilation, not each instruction is executed at one time, | ||
* which is how the tester tests the instructions. If we want to do this, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace "which is how the tester tests the instructions" with "that violates the expectation of instructions tester."
tests/instr_test.c
Outdated
*/ | ||
static uint16_t pc; | ||
static uint8_t flag; | ||
/* flag_args is used for carry the arguments for initial status flag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Append a new line for pretty print.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the grammar error in the above comment.
tests/instr_test.c
Outdated
/* the block for flag loading will be created at the initial and then cached */ | ||
static gb_block *load_flag_block; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this blank line.
src/gbz80.h
Outdated
@@ -11,4 +11,24 @@ bool compile(gb_block *block, | |||
|
|||
bool optimize_block(GList **instructions, int opt_level); | |||
|
|||
#ifdef INSTRUCTION_TEST | |||
struct instr_info { | |||
bool iscb; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename iscb
to is_cb
or is_codeblock
.
Finally, after this pull request, jitboy can now pass all instruction tests on gbit!
I think I should try to explain some detail here since many small tricks are applied to get over the jitboy's limitation.
instruction_mem
but not copy the contents. It will cause some errors if we directly do this on jitboy. Adding some extra codes may help, but it takes time to do this. So I come up with another solution: When executing the callback functionmycpu_set_state
intest_cpu.c
, it will adjustvm->memory.mem
to meet the content that gbit wants. So we can do gbit test correctly although this solution can lead to more executing time.pc
on the JIT codes' return. That's why line 181 intest_cpu.c
is there for "faking" the correctpc
mymmu_write
is expected to be called every time we change the content in memory. But jitboy may sometimes just write memory by jit code and doesn't go through any C code function. To also callmymmu_write
for gbit, you can see that some extrawrite_byte
macro will be used.0xfc
and0xfd
are two invalid opcodes in Game Boy, and I borrow them for the status flag's setting and loading. So we can set the state and also retrieve it back as gbit wishes.How to run gbit