Reputation: 96
This is my first question here and I hope that you're able to help me! I'm currently working on a GameBoy Emulator and want to write it in MASM, for handling the CPU instructions, I want to create an array with variables to make it easier for me to access.
Here is an example what I want to achieve:
assume esi:ptr CPU_CORE
REGISTER_A equ (([esi].registers.AF AND 0F0h) SAR 3h)
REGISTER_B equ (([esi].registers.BC AND 0F0h) SAR 3h)
REGISTER_C equ (([esi].registers.BC AND 0Fh))
PARAM_TABLE [Type?] REGISTER_A
[Type?] REGISTER_B
[Type?] REGISTER_C
assume esi:ptr NOTHING
and if I want to grab a value from the PARAM_TABLE it should work like this:
lea esi, PARAM_TABLE
mov ecx, 1h ; just as example for accessing REGISTER_B
mov eax, [esi+ecx*[TYPE?]]
;EAX now contains the value from the hi-byte of the BC register, so: (([esi].registers.BC AND 0F0h) SAR 3h)
So basically my idea is to create variables like REGISTER_A to make it easier to access. I hope you understand me. Maybe it would be possible to do this with macros?
Upvotes: 4
Views: 440
Reputation: 96
So I answer my own question after tying out some things. Indeed you can create constants using registers like:
REGISTER_A equ [esi+CPU_CORE.registers.A]
but you can only load it like:
mov eax, REGISTER_A ;EAX will now contain the value of the register A.
Then i've figure out that you can just directly access the offsets of a structure (i don't know why i never have used it before.)
REGISTER_A equ CPU_CORE.registers.A
Since this works i've created a structure called PARAM which looks like:
PARAM struct
pointer DWORD ? ;Register pointer
flags BYTE ? ;BIT 0: Content Flag, BIT 1: 8 or 16 bit
desc DWORD ? ;Description of the parameter
PARAM ends
And from that i've just created a parameter list for the LD R,R opcode. which looks like:
PARAM_LIST_R PARAM <CPU_CORE.registers.B, 0, _stro('B')>
PARAM <CPU_CORE.registers._C, 0, _stro('C')>
PARAM <CPU_CORE.registers.D, 0, _stro('D')>
PARAM <CPU_CORE.registers.E, 0, _stro('E')>
PARAM <CPU_CORE.registers.H, 0, _stro('H')>
PARAM <CPU_CORE.registers.L, 0, _stro('L')>
PARAM <CPU_CORE.registers.H, 1, _stro('(HL)')>
PARAM <CPU_CORE.registers.A, 0, _stro('A')>
and a function to read from the register
LoadParam proc cpu_core:DWORD, param:DWORD
LOCAL value:DWORD
pushad
mov esi, cpu_core
mov edi, param
assume esi:ptr CPU_CORE
assume edi:ptr PARAM
add esi, [edi].pointer
movzx ebx, [edi].flags
bt ebx, 0
test ebx, ebx
jnc @NO_CONTENT
movzx edx, word ptr ds:[esi]
;-- ADDING CPU_READ FUNCTION --;
jmp @DONE
@NO_CONTENT:
bt ebx, 1
jc @GET16Bit
movzx eax, byte ptr ds:[esi]
jmp @DONE
@GET16Bit:
movzx eax, word ptr ds:[esi]
@DONE:
mov value, eax
assume esi:ptr NOTHING
assume edi:ptr NOTHING
popad
mov eax, value
ret
LoadParam endp
This function loads the CPU_CORE
into ESI
and the PARAM
into EDI
, the pointer of the PARAM
gets added to the CPU_CORE
. After that the flags are getting tested, if BIT 0
is set it reads from the CPU memory (as example: (HL)
), if it's not set it will just grab the value from the register. The BIT 1
is for the size if it's set the function will read a 16-bit register (BC
, DE
, HL
) or an 8-bit register (B
, C
, D
, E
, H
, L
, A
).
I hope you can understand what I've wrote. If you have any questions feel free to ask, this is just by far the "easiest" way for me to solve my problem.
If you're wondering why I've created the table: You can "decode" the opcodes for further information google "z80 decoding".
Upvotes: 2