<reponame>awiggs/chip-gr8
# THIS IS THE PART YOU MODIFY #

# Define the fields of the VM struct so that we can autogenerate a C struct and
# a python ctypes wrapper *correctly*. Provide a name, type, and description
# (comment) to include in the generated files.
#
# Currently the available types are u8, u16, u32, u64, void_ptr. You can also 
# create an array of any type with array(type, size) and a pointer to any type
# with ptr(type)

STRUCT_DEFINITION = lambda : [
    # Name        Type                 Description
    ('hexes',     array(u8,  '80'),    'Hexsprite pointer'),
    ('VRAM',      array(u8,  '0x100'), 'Video memory'),
    ('stack',     array(u16, '0x10'),  'Address stack'),
    ('V',         array(u8,  '0x10'),  'General purpose registers'),
    ('SP',        u8,                  'Stack pointer'),
    ('PC',        u16,                 'Program counter'),
    ('I',         u16,                 'Address register'),
    ('DT',        u8,                  'Delay timer'),
    ('ST',        u8,                  'Sound timer'),
    ('W',         u8,                  'Wait register'),
    ('K',         u16,                 'Key IO registers'),
    ('seed',      u8,                  'Seed for RNG'),
    ('wait',      u8,                  'Chip-8 in wait mode'),
    ('clock',     u64,                 'Time since simulation began'),
    ('freq',      u16,                 'Frequency as a factor of 60Hz'),
    ('diffX',     u8,                  'VRAM diff X position'),
    ('diffY',     u8,                  'VRAM diff Y position'),
    ('diffSize',  u8,                  'VRAM diff size'),
    ('diffClear', u8,                  'Indicate a CLS instruction'),
    ('diffSkip',  u8,                  'Flag to indicate a skipable DRW instruction'),
    ('quirks',    u8,                  'Flag to indicate quirky instructions for specific ROMs'),
]

# THIS IS THE PART YOU LEAVE ALONE #

import os

PY_PATH = os.path.realpath(os.path.join(__file__, '../chipgr8/autogen_Chip8VMStruct.py'))
C_PATH  = os.path.realpath(os.path.join(__file__, '../includes/autogen_Chip8VMStruct.h'))

# Type Definitions
[u8, u16, u32, u64, void_ptr] = (
#   python ctype        C type
    ('ctypes.c_uint8',  'u8 {}'),
    ('ctypes.c_uint16', 'u16 {}'),
    ('ctypes.c_uint32', 'u32 {}'),
    ('ctypes.c_uint64', 'u64 {}'),
    ('ctypes.c_void_p', 'void* {}'),
)
array  = lambda t, s : ('{} * {}'.format(t[0], s), t[1].format('{}[' + s + ']'))
ptr    = lambda t : ('ctypes.POINTER({})'.format(t[0]), t[1].format('')[:-1] + '* {}')

def defineVMStruct():
    print('Getting definition...')
    definition = STRUCT_DEFINITION()
    print('Writing py struct...'.format(PY_PATH))
    with open(PY_PATH, 'w') as fs:
        fs.write(
'''
# !!! DO NOT MODIFY THIS FILE !!!
#
# This file was autogenerated `defineVMStruct.py`.
# If you need to modify this struct modify the definition in that file.

import ctypes

class Chip8Regs(ctypes.Structure):
    _pack_   = 1
    _fields_ = [
        <fields>
    ]

class Chip8VMStruct(ctypes.Union):
    _pack_      = 1
    _anonymous_ = ['_regs']
    _fields_    = [
        ('RAM',   ctypes.c_uint8 * 0x1000),
        ('_regs', Chip8Regs),
    ]
'''.replace('<fields>', '\n        '.join(['(\'{}\', {}), # {}'.format(name, t0, comment) 
        for (name, (t0, t1), comment) 
        in definition
    ])))
    print('Writing C struct...'.format(C_PATH))
    with open(C_PATH, 'w') as fs:
        fs.write(
'''
#pragma once

/**
 * !!! DO NOT MODIFY THIS FILE !!!
 *
 * This file was autogenerated `defineVMStruct.py`.
 * If you need to modify this struct modify the definition in that file.
 */

#ifndef AUTOGEN_VMSTRUCT_H
#define AUTOGEN_VMSTRUCT_H

/* !!! DO NOT MODIFY !!! */
typedef struct Chip8VM_t Chip8VM_t;
#pragma pack(push, 1)
struct Chip8VM_t {
    union {
        u8 RAM[0x1000];
        struct {
            <fields>
        };
    };
};
#pragma pack(pop)

#endif /* AUTOGEN_VMSTRUCT_H */
'''.replace('<fields>', '\n            '.join(['{}; // {}'.format(t1.format(name), comment) 
        for (name, (t0, t1), comment) 
        in definition
    ])))
    print('done.')    

if __name__ == '__main__':
    defineVMStruct()
