lcgamboa / picsim

PICsim - PIC Simulator
GNU General Public License v2.0
55 stars 14 forks source link

Is it cycle-accurate? #6

Open paaspaas00 opened 6 days ago

paaspaas00 commented 6 days ago

Hi @lcgamboa ! Just discovered your amazing and impressive simulator, that's very cool! I have a question, is it cycle-accurate? Meaning that one can (or could) run at precisely 8 MHz and the output pins result is equal cycle by cycle to the original physical micro? If not, what would be needs in your opinion to make it behave like so? Some kind of latching? Dunno

Thank you for sharing this amazing project, love it!

lcgamboa commented 6 days ago

Hi @paaspaas00 ,

It depends on which backend simulator is used. ESP32, ESP32-C3, STM32 processors are simulated by Qemu which is not cycle-accurate. The other processors that use Simavr, PICsim, and uCsim are cycle-accurate. Which processor are you planning to use?

lcgamboa commented 6 days ago

Sorry, I answered earlier thinking it was about PICSimLab. Yes, PICSim is cycle-accurate.

paaspaas00 commented 6 days ago

@lcgamboa thank you! Reading thru the code, my doubt is: shouldn't one put the pic_step() function in a timer callback in Linux for instance, so that it is called with a freq of 8 MHz, i.e. 8 million times a second? Does picsim take care of timing etc by itself, just by telling it the proc freq in the init function? I'm a bit confused

lcgamboa commented 6 days ago

You need to call the pic_step() function using a timer. The frequency value at initialization is to be able to calculate how many steps to take in the timer. PICSimLab uses a 100ms timer, for 8 MHZ Clock (which means a 32MHz crystal for PIC) it advances 800000 steps every 100ms.

paaspaas00 commented 5 days ago

@lcgamboa Thanks, however I still have some doubts, you mean I need to put the pic_step() function inside a timer callback, called every 100ms? Could you provide a some minimalist example/pseudocode? In particular, I'd like to get all the pin values (GPIO, etc) at every step, without using a printf or anything, just take the variables out and set them at every cycle, like in the physical version. I've seen the PCSimLab code and the picsim executable code but I was not able to understand it well.

Btw just discovered the picsim_simple.c example don't compile, you need to put &pic1 as the first argument to pic_step(), pic_get_pin(1), pic_set_pin(2, val) and pic_end(). Hope it helps!

lcgamboa commented 5 days ago

Thank you for sharing the problem with picsim_simple, I just fixed it. I have added another example called realtime, which will help you to understand how to use PICSim.

paaspaas00 commented 4 days ago

@lcgamboa thank you for the info and the example! So this is setting a timer triggered every 100ms and letting the step function go n times to match the clock frequency. Isn't it a bit of a compromise? I mean, in my understanding to be perfectly realtime cycle-accurate in the pin output the function should be called (in a RTOS or bare metal) 4 million times a second, precisely spaced 1/(4000000) secs apart with a timer or something, assuming the physical machine it's running on is capable to run the picsim_step function in less than 1/(4000000) secs. Am I wrong? In your opinion is it feasible? How to achieve this?

lcgamboa commented 4 days ago

You are right for the case of an RTOS. In normal Linux or Windows OSes, timers usually cannot guarantee accuracy for values ​​smaller than 100ms. The cost for the OS to call the callback ends up being greater than the cost of the code to be executed. Typically, for simulation purposes only, this type of approach works well (it's what I use in PICSimLab). In the case of emulation, where you need to use the pin values directly, you need one hardware capable of guaranteeing the execution of each cycle within the expected time, probably using an RTOS. It wouldn't make much sense to use a microcontroller with much greater processing power to emulate a PIC, but it is possible. What is your specific use case?

paaspaas00 commented 4 days ago

I'm experimenting for fun trying to find out if an esp32 could be used for emulation, despite the limited processing power. I also considered an STM32 of those found in cheap "blue pill" boards which maybe could be a better candidate not having to deal with an RTOS in the background. Maybe I'd need to optimize the picsim a bit (while keeping it general). For instance, since one may not need to change micro at runtime, many thing could be put in #defines (like pic->print checks, etc). We could avoid pic->table.register reference access and have the struct offset precomputed by the compiler using pic.table.register, etc.

lcgamboa commented 4 days ago

This is a good didactic exercise to learn. Using a microcontroller as a base, it is possible to eliminate the peripheral simulation part and map to real peripherals, requiring only the simulation of the PIC instructions. As you said, it will require a lot of optimization to make it work reasonably. This cool project does the opposite of what you are proposing, it uses an 8-bit AVR to simulate a 32-bit ARM.