it can decide how to proceed. Some of those bits are necessary
to make TLB invalidation decisions. INVLPG doesn't cause
a whole TLB flush anymore, just one page. Some of the
current CPU behaviours model the P6, especially on CR0
reloads. Earlier processors kept some pre-change pre-fetched
instructions until a branch. We could probably model that
by setting a flag, and letting the revalidate_prefetch_q
function cause serialization.
The TLB flush code only invalidates entries which are not
already invalidated for the case where the TLB invalidation
ID trick is not in use.
Read-Modify-Write instructions. The first read phase stores
the host pointer in the "pages" field if a direct use pointer
is available. The Write phase first checks if a pointer was
issued and uses it for a direct write if available.
I chose the "pages" field since it needs to be checked by the
write_RMW_virtual variants anyways and thus needs to be
cached anyways.
Mostly the mods where to access.cc, but I did also macro-ize
the calls to write_RMW_virtual...() in files which use it
and cpu.h. Right now, the macro is just a straight pass-through.
I tried expanding it to a quick initial check for the pointer
availability to do the write in-place, with a function call
as a fall-back. That didn't seemed to matter at all.
Booting is not helped by this really. The upper bound of
the gain is 5 or 6%, and that's only if you have a loop that
looks like:
label:
add [eax], ebx ;; mega read-modify-write instruction
jmp label ;; intensive loop.
Kevin Lawton says he doesn't get a performance benefit.
I'm not sure if I do. Either way, the difference isn't
very large.
This code may get removed if it turns out to be useless.
- modified files: config.h.in cpu/init.cc debug/dbg_main.cc gui/control.cc
gui/siminterface.cc gui/siminterface.h gui/wxdialog.cc gui/wxdialog.h
gui/wxmain.cc gui/wxmain.h iodev/keyboard.cc
----------------------------------------------------------------------
Patch name: patch.wx-show-cpu2
Author: Bryce Denney
Date: Fri Sep 6 12:13:28 EDT 2002
Description:
Second try at implementing the "Debug:Show Cpu" and "Debug:Show
Keyboard" dialog with values that change as the simulation proceeds.
(Nobody gets to see the first try.) This is the first step toward
making something resembling a wxWindows debugger.
First, variables which are going to be visible in the CI must be
registered as parameters. For some variables, it might be acceptable
to change them from Bit32u into bx_param_num_c and access them only
with set/get methods, but for most variables it would be a horrible
pain and wreck performance.
To deal with this, I introduced the concept of a shadow parameter. A
normal parameter has its value stored inside the struct, but a shadow
parameter has only a pointer to the value. Shadow params allow you to
treat any variable as if it was a parameter, without having to change
its type and access it using get/set methods. Of course, a shadow
param's value is controlled by someone else, so it can change at any
time.
To demonstrate and test the registration of shadow parameters, I
added code in cpu/init.cc to register a few CPU registers and
code in iodev/keyboard.cc to register a few keyboard state values.
Now these parameters are visible in the Debug:Show CPU and
Debug:Show Keyboard dialog boxes.
The Debug:Show* dialog boxes are created by the ParamDialog class,
which already understands how to display each type of parameter,
including the new shadow parameters (because they are just a subclass
of a normal parameter class). I have added a ParamDialog::Refresh()
method, which rereads the value from every parameter that it is
displaying and changes the displayed value. At the moment, in the
Debug:Show CPU dialog, changing the values has no effect. However
this is trivial to add when it's time (just call CommitChanges!). It
wouldn't really make sense to change the values unless you have paused
the simulation, for example when single stepping with the debugger.
The Refresh() method must be called periodically or else the dialog
will show the initial values forever. At the moment, Refresh() is
called when the simulator sends an async event called
BX_ASYNC_EVT_REFRESH, created by a call to SIM->refresh_ci ().
Details:
- implement shadow parameter class for Bit32s, called bx_shadow_num_c.
implement shadow parameter class for Boolean, called bx_shadow_bool_c.
more to follow (I need one for every type!)
- now the simulator thread can request that the config interface refresh
its display. For now, the refresh event causes the CI to check every
parameter it is watching and change the display value. Later, it may
be worth the trouble to keep track of which parameters have actually
changed. Code in the simulator thread calls SIM->refresh_ci(), which
creates an async event called BX_ASYNC_EVT_REFRESH and sends it to
the config interface. When it arrives in the wxWindows gui thread,
it calls RefreshDialogs(), which calls the Refresh() method on any
dialogs that might need it.
- in the debugger, SIM->refresh_ci() is called before every prompt
is printed. Otherwise, the refresh would wait until the next
SIM->periodic(), which might be thousands of cycles. This way,
when you're single stepping, the dialogs update with every step.
- To improve performance, the CI has a flag (MyFrame::WantRefresh())
which tells whether it has any need for refresh events. If no
dialogs are showing that need refresh events, then no event is sent
between threads.
- add a few defaults to the param classes that affect the settings of
newly created parameters. When declaring a lot of params with
similar settings it's more compact to set the default for new params
rather than to change each one separately. default_text_format is
the printf format string for displaying numbers. default_base is
the default base for displaying numbers (0, 16, 2, etc.)
- I added to ParamDialog to make it able to display modeless dialog
boxes such as "Debug:Show CPU". The new Refresh() method queries
all the parameters for their current value and changes the value in
the wxWindows control. The ParamDialog class still needs a little
work; for example, if it's modal it should have Cancel/Ok buttons,
but if it's going to be modeless it should maybe have Apply (commit
any changes) and Close.
- bx_gen_reg cannot be declared with BX_SMF or it can't read gen_reg
when static member functions are turned on.
- use "BX_CPU_C_PREFIX" instead of "BX_CPU_C::" for get_segment_base.
- the SMF (static member function) tricks are just plain wierd. The only way to
really be sure that you're not breaking something is to try compiling it with
SMF on and with SMF off. e.g. "configure && make" and
"configure --enable-processors=2 && make".
work (control-C kills process instead of returning to debugger prompt), give
a configure-time error if they are enabled together. If we can fix the
signal problem in readline, this check can be removed.
problems with control-C handling if you enable readline, because readline()
installs its own signal handlers every time you call it. I'm having
good luck with "--with-wx --enable-debugger --disable-readline" now.
X windows, wxWindows. Each platform has its own way of returning
a variable length string, and its own rules about how you're supposed
to dispose of the string. Now all platforms do the same thing: they
allocate a Bit8u buffer with C++ "new" and copy the clipboard data in,
then release the clipboard data in the platform-specific correct way.
The Bit8u buffer is sent to the keyboard code, which frees it with
delete [] when finished.
- modified: gui/wxmain.cc gui/wxmain.h
X windows, wxWindows. Each platform has its own way of returning
a variable length string, and its own rules about how you're supposed
to dispose of the string. Now all platforms do the same thing: they
allocate a Bit8u buffer with C++ "new" and copy the clipboard data in,
then release the clipboard data in the platform-specific correct way.
The Bit8u buffer is sent to the keyboard code, which frees it with
delete [] when finished.
- modified: gui/wx.cc gui/x.cc gui/win32.cc iodev/keyboard.cc
files that need them. This is more in line with the other gui libraries,
and the compile line is easier to read.
- modified: Makefile.in configure.in configure gui/Makefile.in
delivered to both the GUI and simulator thread, so they both call
bx_signal_handler. This can lead to deadlock as multiple threads enter
BX_PANIC and try to show a dialog box at once. To solve the problem, I made
a function isSimThread() which can be called from anywhere. If the
bx_signal_handler is called from any thread OTHER THAN the simulation thread,
it returns without doing anything. As a result, only one thread is allowed
to enter the signal handler code, and now control-C works correctly.
Bochs to immediately read the bochsrc and start simulating immediately (as
opposed to going into the configuration interface first). Now -q does
the right thing in the wxWindows interface. It behaves as if you selected
Read Configuration and then Simulate:Start.
- modified: main.cc gui/siminterface.cc gui/siminterface.h gui/wxmain.cc
direct reads/writes from native variables to the x86 (guest)
memory image. Look at the end of bochs.h. Don't know if that's
the right place to put them, but here you can extend these
macros to platform-specific asm() code if you like, or just
use the generic C code I supplied. Some platforms have special
instructions for byte-order swapping etc. Also, you can't
make any assumptions about the alignment of the pointers
passed.
mode uses the notion of the guest-to-host TLB. This has the
benefit of allowing more uniform and streamlined acceleration
code in access.cc which does not have to check if CR0.PG
is set, eliminating a few instructions per guest access.
Shaved just a little off execution time, as expected.
Also, access_linear now breaks accesses which span two pages,
into two calls the the physical memory routines, when paging
is off, just like it always has for paging on. Besides
being more uniform, this allows the physical memory access
routines to known the complete data item is contained
within a single physical page, and stop reapplying the
A20ADDR() macro to pointers as it increments them.
Perhaps things can be optimized a little more now there too...
I renamed the routines to {read,write}PhysicalPage() as
a reminder that these routines now operate on data
solely within one page.
I also added a little code so that the paging module is
notified when the A20 line is tweaked, so it can dump
whatever mappings it wants to.
I have not tested these functions, but they model the format and
acceleration principals of the byte/word/dword functions. Give them
a try on both little/big endian machines.
to diff configure...you'll have to run autoconf yourself.
- in config.h.in set BX_SUPPORT_MMX to 0, not 1. The configure script
will replace it with a 1 if appropriate. That's the way all other
options are done.
- you need to use patch -p1 for this
wxHAS_RAW_KEY_CODES is not available in the wxWindows library.
my patch "patch.wx-raw-keycodes" adds wxHAS_RAW_KEY_CODES to the wxWindows
library, and it will also be in wxWindows 2.3.3 and beyond.