Main » Emulation » Emulator code design without libco » New reply
    Alert
    You are about to bump an old thread. This is usually a very bad idea. Please think about what you are about to do before you press the Post button.
    New reply
    Post help

    Presentation

    [b]…[/b] — bold type
    [i]…[/i] — italic
    [u]…[/u] — underlined
    [s]…[/s] — strikethrough
    [code]…[/code] — code block
    [spoiler]…[/spoiler] — spoiler block
    [spoiler=…]…[/spoiler]
    [source]…[/source] — colorcoded block, assuming C#
    [source=…]…[/source] — colorcoded block, specific language[which?]
    [abbr=…]…[/abbr] — abbreviation
    [color=…]…[/color] — set text color
    [jest]…[/jest] — you're kidding
    [sarcasm]…[/sarcasm] — you're not kidding

    Links

    [img]http://…[/img] — insert image
    [url]http://…[/url]
    [url=http://…]…[/url]
    >>… — link to post by ID
    [user=##] — link to user's profile by ID

    Quotations

    [quote]…[/quote] — untitled quote
    [quote=…]…[/quote] — "Posted by …"
    [quote="…" id="…"]…[/quote] — ""Post by …" with link by post ID

    Embeds

    [youtube]…[/youtube] — video ID only please
    Thread review
    creaothceann Depends on the hardware, the register, and the timing. For example on the SNES writing to VRAM during active display has no effect on the VRAM content, whereas writes to the brightness register do take effect immediately on most SNES revisions.
    nyanpasu64 I'm not experienced in emulation, but what happens if the CPU writes to a register during the middle of the GPU rendering a dot?
    segarally
    Posted by Sintendo
    What you're showing us here looks like a very basic scheduler, in which you run the CPU ahead and let the GPU play catch-up. Whether this particular scheme will suffice for the Megadrive I can't say; I imagine the answer depends on how the different devices are capable of interacting with each other, and what level of accuracy you're aiming for with your emulator.

    However, a scheduler doesn't have a whole lot to do with whether you use cooperative threads (e.g. libco) or not. The true advantage of using cooperative threads, is that you can suspend execution at any point without requiring additional logic. This maps beautifully to cycle-level emulation, where you can suspend in the middle of an instruction. State machines are an alternative, but can be very cumbersome to write. byuu wrote a nice article on this topic, if you haven't read it yet.


    I'm agree with you Sintendo, but the interest of my design is to suspend an instruction (for just before a slot of the vdp) to be sure that cpu is in sync before rendering the dot :-)
    The code is simple and does not recquire any libco thread.
    Sintendo What you're showing us here looks like a very basic scheduler, in which you run the CPU ahead and let the GPU play catch-up. Whether this particular scheme will suffice for the Megadrive I can't say; I imagine the answer depends on how the different devices are capable of interacting with each other, and what level of accuracy you're aiming for with your emulator.

    However, a scheduler doesn't have a whole lot to do with whether you use cooperative threads (e.g. libco) or not. The true advantage of using cooperative threads, is that you can suspend execution at any point without requiring additional logic. This maps beautifully to cycle-level emulation, where you can suspend in the middle of an instruction. State machines are an alternative, but can be very cumbersome to write. byuu wrote a nice article on this topic, if you haven't read it yet.
    creaothceann
    Posted by segarally
    If people have experience emulating system complexity at the level of Megadrive and have advice about this design and way to synchronize the device I'm very interested.

    You could also try posting a thread on /r/EmuDev/.
    segarally Hello Everybody.

    My name is Mickael an i live in france (sorry for my english).
    I'm french fan of sega and emulation world.

    I'm interesting particullary on code design.
    Higan and bsnes are a reference for me ;-).
    In my free time (i don't have much) i try to create a genesis emulator too.

    Theses days i'm trying to rework the general structure of my emulator to improve code design.

    I'm asking myself about using libco from byuu.

    After some search i found a solution to have the same advantage that libco but without using a library thread.
    Perhaps something is wrong in the way i think and i told myself it could be good to share this solution in this forum to take advices.
    Perhaps for example the way to synchronize device don't work in very every case but i can't have all configuration in mind yet to figure if it's a good solution or no.

    I wrote below an example of code synchronizing a cpu, wich can be executed at instruction level, and a gpu wich can be executed at slot level.
    The basic idea is that every device have a device manager wich receive event during execution of the device.
    Exactly like libco, the cpu device can send an event to his manager notify him that a memory read will start.



    class CPU {

    private :

    //internal clock
    uint _clock;

    //DeviceConroller
    CPUController* _controller;

    //internal bus reader
    u16 readBus(u32 addr) {

    _clock = _clock + 2;
    _controller->CPUEvent(DEVICEA::EVENT_BUS_READED);
    _clock = _clock + 4; //Improve could be to add wait potential extra cycles due to device latency
    }

    public :

    // exec loop
    void exec(){

    clock_instruction = execInstruction();
    _clock = _clock + clock_instruction;

    _controller->CPU(CPU::INSTRUCTION_ENDED);
    }

    uint getClock(){
    return _clock;
    }
    }



    The same thing for the GPU, wich can notify his manager that a new slot will start (i don't write example here).

    The class charged to synchronize all devices have to implement all DeviceManager interface from each component.
    When the object's class receive an event, the class will look if exist an other device with his clock in late.
    If exist this device will be executed until the next event this device will send.

    For example in our case when the memory read event will be notified by cpu, the class will ask the gpu to exec all slot until the clock reach the actual cpu clock.
    To avoid the case the gpu ask the cpu to sync, the class know that the cpu is waiting sync so it will ignore it.


    class DevicesManager :: CPUController, GPUController {

    private :

    Device[] _devices;
    uint[] _devicesState;

    uint _CPUID = 0;
    uint _GPUID = 1;

    public :

    void runDevices() {

    CPU->exec();
    }

    void CPUEvent(uint clock, u8 event) {

    if(event == CPU::EVENT_READ_BUS || CPU::INSTRUCTION_ENDED) {
    uint[] devices = {_GPUID};
    sync(clock, _GPUID);
    }
    }

    void GPUEvent(uint clock, u8 event) {

    if(event == GPU::SLOT_ENDED){
    uint[] devices = {_CPUID};
    sync(clock, _CPUID);
    }
    }

    void sync(clock, uint waitingDevice, uint[] deviceToSync) {

    _devicesState[waitingDevice] = WAITING;

    for(uint = 0; i < nbDevices; i++) {

    if(_devicesState[deviceID] != WAITING) {

    if(device->getClock() < clock)
    device->exec(clock);
    }

    _devicesState[waitingDevice] = RUNNING;
    }
    };



    The code syntax is perhaps wrong, the code need perhpas to be improved and completed to be consistent enough to manage a system like the megadrive but i wrote it only to show the principles.

    If people have experience emulating system complexity at the level of megadrive and have advice about this design and way to synchronize the device i'm very interested.
    My aim is have a design sufficient enough to emulate the megadrive.








      Main » Emulation » Emulator code design without libco » New reply
      Yes, it's an ad.