Compare commits

...

265 Commits

Author SHA1 Message Date
Hugo Villeneuve
73774e5974 Implement workaround for flex --header-file option
This is fixed in automake 1.12 and later.

The problem is that the ylwrap helper script creates a temporary directory
when running flex. Flex then correctly creates the scanner.h file inside this
temporary directory, but ylwrap does not copy it back to the build dir.
2014-11-06 22:32:08 -05:00
Hugo Villeneuve
c7eae29d2f Rename perl sources variable to avoid confusion
Variables ending with _SOURCES are specific to automake.
2014-11-06 20:59:22 -05:00
Hugo Villeneuve
b1c46135a4 Replace LEX macro with preferred one 2014-11-06 00:41:39 -05:00
Hugo Villeneuve
9cd867c94a Cleanup of autoconf files 2014-04-09 00:19:49 -04:00
Hugo Villeneuve
121bcb38f2 opcodes2c.pl: Add command line options
Argument 1 is opcodes list filename
Argument 2 is the output directory.

These arguments are necessary if we want to generate the C source
files and headers in a separate build directory.
2014-04-09 00:18:07 -04:00
Hugo Villeneuve
7d0bd87bf6 Save window position in configuration file 2014-04-08 22:39:50 -04:00
Hugo Villeneuve
9241cbf30e Allow to override window geometry on the command line 2014-04-08 22:39:50 -04:00
Hugo Villeneuve
3e3b891049 Change project's website URL 2014-04-08 14:31:07 -04:00
Hugo Villeneuve
486bd979e3 Add missing include file
There was no bug, code was compiling correctly. Just for clarity.
2014-04-08 14:29:29 -04:00
Hugo Villeneuve
2f8c619857 Remove unnecessary AM option parallel-tests 2014-04-07 00:10:00 -04:00
Hugo Villeneuve
3ca737ea38 Convert to automake gnits option 2014-04-06 23:46:40 -04:00
Hugo Villeneuve
972da42d11 Fix Makefile.am indentation 2014-04-06 23:10:23 -04:00
Hugo Villeneuve
d1392836d0 Convert to LIBTOOL 2014-04-06 23:03:24 -04:00
Hugo Villeneuve
acff1c38b1 Add option -Wno-extra-portability to AM_INIT_AUTOMAKE
To get rid of warning:
  linking libraries using a non-POSIX archiver requires 'AM_PROG_AR'...
2014-04-06 22:40:02 -04:00
Hugo Villeneuve
f7e3f1d8d0 Add option no-define to AM_INIT_AUTOMAKE
No need to define all variables on the compiler command line since
they are already defined in the config.h header file.
2014-04-06 22:36:16 -04:00
Hugo Villeneuve
b89d7661e7 Put automake macros together 2014-04-06 22:27:48 -04:00
Hugo Villeneuve
b5d52c94a7 emu8051 2.0.1 2014-03-22 14:24:24 -04:00
Hugo Villeneuve
e45e088e0d Convert manpage to UTF-8 2014-03-16 21:25:17 -04:00
Hugo Villeneuve
3edaa24acc Add tests for CLI version commands 2014-02-17 23:06:51 -05:00
Hugo Villeneuve
401c1d7060 Do not display registers at CLI version startup
This is to help testing the "dr" command, to be able to match
default register values.
2014-02-17 23:06:44 -05:00
Hugo Villeneuve
ab28e54867 Add proper error checking in asciihex2int functions 2014-02-16 01:51:47 -05:00
Hugo Villeneuve
4c4ca66c31 Dont exit in case of hexfile reading failure 2014-02-15 18:07:29 -05:00
Hugo Villeneuve
fbbb71d6d8 Replace disam.h with opcodes{h,c}
Also rename opcode2c.pl -> opcodes2c.pl
2014-02-15 01:43:32 -05:00
Hugo Villeneuve
7abd6d07ea Fix comment after cleanup 2014-02-15 00:45:16 -05:00
Hugo Villeneuve
c91e69d435 Fix splint warnings 2014-02-15 00:45:16 -05:00
Hugo Villeneuve
e417485aaf Fix C99 standard types uintN_t 2014-02-15 00:13:21 -05:00
Hugo Villeneuve
87daca654d Remove unused header file includes 2014-02-13 00:37:58 -05:00
Hugo Villeneuve
c69c15d65b Fix test script to work in external build directory 2014-02-13 00:25:19 -05:00
Hugo Villeneuve
00deadc94f Shorten memory_ functions prefix to mem_ in memory.c 2014-02-13 00:25:19 -05:00
Hugo Villeneuve
8bfc53036a Fix checkpatch warnings 2014-02-13 00:25:19 -05:00
Hugo Villeneuve
ba0e6b3b86 Move memory read functions to memory.c
Fix warnings given by checkpatch.pl
2014-02-13 00:25:19 -05:00
Hugo Villeneuve
4c9cf2f222 Fix auto-generated C source files indentation 2014-02-13 00:25:19 -05:00
Hugo Villeneuve
1d394c78b9 Remove unnecessary column in opcodes.lst
Begin to cleanup Perl code
2014-02-13 00:25:18 -05:00
Hugo Villeneuve
dc0e2b9353 Remove duplicate code for disassembly 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
5419d1bd9d Fix checkpatch warnings 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
3c838204cd Shorten GPLv2 licence text in header of each source file 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
75172f0ea5 Add up to 4 emulator timers 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
93c2708bee Rename DumpMem function -> memory_dump 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
888cea8f85 Add more error checking for CLI version arguments 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
8e5b455c12 Cleanup help menu 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
f2fba46bfe Add support for GNU readline
readline input is fed into Lex.

This adds commands history.

There is also a configure option to disable readline support.
2014-02-13 00:25:18 -05:00
Hugo Villeneuve
1466890269 Rename CLI and GUI versions main source files 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
f2f9b967b4 Allow hex numbers to begin with 0x or $ prefix in scanner 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
7c267c5882 Allow to set all SFR registers in CLI version 2014-02-13 00:25:18 -05:00
Hugo Villeneuve
a43a2e343e Add new value range check when writing register in CLI version
The GUI version also had this check, so the functionality has been merged.
2014-02-13 00:25:17 -05:00
Hugo Villeneuve
c7d14532b0 Convert CLI version input parsing to Lex/Yacc
Some error checking is still missing, but all commands seem to be
working correctly.

Update CLI help menu.
2014-02-13 00:25:17 -05:00
Hugo Villeneuve
fd418e0f87 Remove address parameter from RUN and TRACE CLI commands
Also automatically display register contents after each RUN operation.
2014-02-06 23:07:02 -05:00
Hugo Villeneuve
ce650967bd Add general-purpose timer to CLI
Also add command to reset it.
2014-01-26 18:33:53 -05:00
Hugo Villeneuve
d755f96382 Add better error checking when loading invalid hex files
Also replaced custom error message box with standard one.
2014-01-26 18:23:11 -05:00
Hugo Villeneuve
1f9c51e5df Refactor hex loading code
Merged two identical code portions that validated the checksum.

Also added better debug messages.
2014-01-26 17:52:21 -05:00
Hugo Villeneuve
fc904031c8 Allow EM command to be specified without arguments
In this case, program will run from the current PC address until a breakpoint
is reached.
2014-01-26 17:50:52 -05:00
Hugo Villeneuve
c2ac9fc48f Move macro definition to top of file 2014-01-26 15:38:55 -05:00
Hugo Villeneuve
cc6633f78b Use log functions to display errors 2014-01-26 15:38:46 -05:00
Hugo Villeneuve
310d829f65 Fix error when specifying start address in CLI version
Start address was specified as "0x0000", but need to be "0000".
2014-01-26 15:09:23 -05:00
Hugo Villeneuve
e8c456321e Add square root regression test 2014-01-26 00:25:48 -05:00
Hugo Villeneuve
b470088f1c Return error for test files without any validation condition 2014-01-25 23:39:27 -05:00
Hugo Villeneuve
d74a41311f Do not display eror message when simply pressing return in CLI version
Before was displaying message "Syntax error".
2014-01-25 18:56:10 -05:00
Hugo Villeneuve
a6ccc722bd Add general-purpose timer to GUI
This timer is not part of the 8051 hardware. It is a free running
timer/counter added as a mean to quickly measure delays in instruction
cyles.

For now, it is implemented only in GUI version.
2014-01-25 17:38:50 -05:00
Hugo Villeneuve
656993ee5e Add documentation about regression testing 2014-01-23 20:01:33 -05:00
Hugo Villeneuve
ff643bede1 Remove display of command line options in GUI mode
The information message was manually edited, which creates synchronization
problems now that we are using argp to manage our options.
2014-01-23 19:45:14 -05:00
Hugo Villeneuve
d230e5df59 Simplify options parsing code 2014-01-23 19:40:40 -05:00
Hugo Villeneuve
30f7307f61 emu8051 2.0.0 2014-01-23 00:18:36 -05:00
Hugo Villeneuve
5e7b849e7d Remove dynamic update of GUI layout
The application must restarted for the changes to take effect.

Added a message for telling this to the user.
2014-01-23 00:18:35 -05:00
Hugo Villeneuve
8f1773713c Improve view/hide of memory windows
Do not restart whole GUI, just update vpaned containing
the two memory scroll windows.
2014-01-23 00:18:35 -05:00
Hugo Villeneuve
cc7dd9b04f Remove deprecated view->sfr-window option 2014-01-22 23:32:10 -05:00
Hugo Villeneuve
9417a6bc0b Fix error when toggling memory display viewing on/off
Only the first two rows were displayed. The crc_init variable
was not handled correctly.
2014-01-22 23:32:10 -05:00
Hugo Villeneuve
cec5fe02c3 Remove autogen.sh from distribution tarball 2014-01-14 22:57:45 -05:00
Hugo Villeneuve
6281db4c82 ChangeLog is now automatically generated from git log output 2014-01-14 22:57:45 -05:00
Hugo Villeneuve
34513fc19f Fix compilation warning 2014-01-14 00:23:10 -05:00
Hugo Villeneuve
71c48441ed Refactor memwin.c for internal and external memories 2014-01-14 00:19:59 -05:00
Hugo Villeneuve
877e908e7b Change confusing variable name bits_per_row to bytes_per_row 2014-01-13 23:43:46 -05:00
Hugo Villeneuve
84a325ac72 Improve performance of GUI step operations
Use CRC to detect which memory rows have changed.

This is only to improve GUI performance when using stepping mode, as we then
only update rows which have been modified.
2014-01-13 23:36:37 -05:00
Hugo Villeneuve
b58acccaf0 Set external memory size default to 256 2014-01-13 22:40:56 -05:00
Hugo Villeneuve
0027047772 Set program memory size default to 65536
Before was set to 8192.

To make sure to not cause problems with bigger programs, or with small
programs that are split accross large memory regions.
2014-01-11 17:26:25 -05:00
Hugo Villeneuve
7f72e34564 Create common function for running instructions 2014-01-11 17:24:23 -05:00
Hugo Villeneuve
290e4eb58e Fix warning for ignored return value for getline() 2014-01-03 03:19:32 -05:00
Hugo Villeneuve
3a89081827 Fix [-Wsign-compare] warnings
Original warning message:
emuconsole.c:45:16: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
2014-01-03 03:18:02 -05:00
Hugo Villeneuve
dd7540145e Merge ADD and ADDC operations into common function 2014-01-03 02:57:16 -05:00
Hugo Villeneuve
30d141860a Fix code indentation 2014-01-03 02:37:18 -05:00
Hugo Villeneuve
4055176e86 Fix error with ADDC instruction
The carry flag was not added to the result.
2014-01-03 02:36:17 -05:00
Hugo Villeneuve
670bbd59fa Add tests for ADD and ADDC instructions 2014-01-03 02:33:32 -05:00
Hugo Villeneuve
57f6d79aa0 Fix [-Wformat-security] warning
Original warning message:
emuconsole.c:316:3: warning: format not a string literal and no format arguments [-Wformat-security]
2014-01-03 01:58:18 -05:00
Hugo Villeneuve
702da8f531 Fix warnings about unused function parameters 2014-01-03 01:58:18 -05:00
Hugo Villeneuve
fa97a074e5 Fix [-Wmissing-field-initializers] warnings 2014-01-03 01:58:18 -05:00
Hugo Villeneuve
1590b0711f Fix regression with ADDC instruction
Introduced when refactoring code with psw_set_ov() function.
2014-01-03 01:58:18 -05:00
Hugo Villeneuve
bd7be8da77 Add additional compile warning flags
Also changed way that warning flags are defined in autoconf files.
2014-01-03 01:58:18 -05:00
Hugo Villeneuve
5194d331cd Move git ignore file list to build-aux 2013-12-10 23:05:32 -05:00
Hugo Villeneuve
955a5eaa95 Remove configure cache directory after running autoreconf 2013-12-10 22:34:09 -05:00
Hugo Villeneuve
1eb382f725 Separate cli and gtk sources into separate directories
Also added a common directory to hold common files to both interfaces,
and compiled into a static library.
2013-12-07 18:50:45 -05:00
Hugo Villeneuve
b8e00ae8a1 Remove obsolescent macro AM_PROG_CC_C_O 2013-12-07 18:50:39 -05:00
Anthony Liu
429bc0270f Improve interrupt trigger code readability 2013-12-06 00:07:22 -05:00
Anthony Liu
2407d4a9a8 Fix bug when processing interrupts
Push current PC onto stack and take vector address from parameter.
2013-12-05 23:41:24 -05:00
Hugo Villeneuve
b95c4f897b Add support for as504 assembler, with output file option
Patch is available here:
http://www.hugovil.com/repository/hvlinux/patches/as504-add-output-file-option.patch

This patch is usefull because it fixes a bug when testing the distribution
in a  separate build directory like when using:
    make distcheck

configure.ac automatically detects if as504 supports the option.
2013-12-02 21:59:30 -05:00
Hugo Villeneuve
cca33e1d25 Add support for as504 assembler 2013-12-02 21:18:44 -05:00
Hugo Villeneuve
187e9a2c6c Fix bug when using separate build directory to create symbolic link 2013-12-01 23:33:18 -05:00
Hugo Villeneuve
96a44157eb Replace CALL by LCALL for compatibility with AS31 and AS504 assemblers 2013-12-01 23:31:51 -05:00
Hugo Villeneuve
091899a37a Remove CSEG directive for compatibility with AS31 and AS504 assemblers 2013-12-01 23:02:09 -05:00
Hugo Villeneuve
7977d9426b Remove currently unsupported option to set iram size 2013-12-01 21:20:49 -05:00
Hugo Villeneuve
fb189bd5ce Fix CPPFLAGS for each target (CLI and GTK) 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
5088955838 Change way tests are enabled/disabled by asem presence 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
a46ab59d50 Run each test separately from single shell script
Each new test is simply a link to opcodes.sh, generatated automatically.
2013-12-01 21:00:08 -05:00
Hugo Villeneuve
356fc4e3a3 Move timer functions to timers.c 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
bdc8dc1d31 Add tests for timers mode 2 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
ce24c216aa Change test output expected string layout
Also check stack pointer value for all tests
2013-12-01 21:00:08 -05:00
Hugo Villeneuve
6a014db0cd Add tests for timers mode 0 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
ef76945139 Fix bug with timers mode 0 (8 bits with 5-bit prescaler) 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
5d04244ebc Add tests for timers mode 1 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
e93543c1a1 Fix error with timer1 being written to timer0 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
1a20c858a9 Add PC check for all tests 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
28f33d3ca4 Add tests for MOV instruction 2013-12-01 21:00:08 -05:00
Hugo Villeneuve
0315df6597 Add tests for DIV instruction 2013-12-01 21:00:07 -05:00
Hugo Villeneuve
d27ffb9c24 Add tests for ANL instruction 2013-12-01 21:00:07 -05:00
Hugo Villeneuve
7521627a72 Add tests for ORL instruction 2013-12-01 21:00:07 -05:00
Hugo Villeneuve
7a22c370ea Add framework for regression testing 2013-12-01 21:00:07 -05:00
Hugo Villeneuve
594b0ac005 Automatic generation of test hex files 2013-12-01 21:00:07 -05:00
Hugo Villeneuve
97e8525955 Add tests for MUL instructions 2013-12-01 20:59:50 -05:00
Hugo Villeneuve
ab08aba210 Remove hex files 2013-12-01 20:59:04 -05:00
Hugo Villeneuve
3e23ac6c01 Rename test-files directory -> tests 2013-12-01 20:59:04 -05:00
Hugo Villeneuve
5f0e9d167d Add automake options -Wall and gnu std-options
Remove configure verbose output
2013-12-01 20:58:50 -05:00
Hugo Villeneuve
359b0be02b Remove superfluous bytes in program disassembly
Sometimes, B1 and B2 were showing old values from previous disassembly.
Now explicitly remove them for each disassembly line.
2013-12-01 20:53:34 -05:00
Hugo Villeneuve
8b2f6f3ebb Fix code indentation 2013-12-01 20:53:34 -05:00
Hugo Villeneuve
3e3d02a2f2 Prevent dissassembling instructions past last address 2013-12-01 20:52:42 -05:00
Hugo Villeneuve
444731db04 Add ignore files to gitignore 2013-12-01 20:52:42 -05:00
Hugo Villeneuve
72e3350162 Fix syntax error in comments 2013-12-01 20:52:42 -05:00
Hugo Villeneuve
3fed93eb25 Fix error with EM command in CLI mode
Address parameter was not handled correctly.
2013-12-01 20:49:43 -05:00
Hugo Villeneuve
b6dd8fec84 CLI version: Add <?> to display help menu 2013-12-01 20:49:43 -05:00
Hugo Villeneuve
a1c2d96861 Reintroduce PSW in list of displayed registers (for regression tests) 2013-12-01 20:49:43 -05:00
Hugo Villeneuve
381b6d7dd0 Display SFR registers one per line in automatic run mode 2013-12-01 20:49:43 -05:00
Hugo Villeneuve
e75510dd87 Move SFR read/write functions to new file sfr.c 2013-12-01 20:49:43 -05:00
Hugo Villeneuve
dd92f3969f Add option to automatically run and stop CLI emulator 2013-12-01 20:49:43 -05:00
Hugo Villeneuve
18b62c73db Replace printf statements with log functions 2013-12-01 20:49:06 -05:00
Hugo Villeneuve
ccb7a5d184 Move variable declaration before statements 2013-12-01 20:49:06 -05:00
Hugo Villeneuve
8c2d345bc7 Display filename in case of HEX file load error 2013-12-01 20:49:06 -05:00
Hugo Villeneuve
8d9b71ab38 Zero all memories when initializing program
This is especially usefull to have NOP in program memory.
2013-11-22 23:42:14 -05:00
Hugo Villeneuve
6bf8b77a5e Add grid lines to PSW window 2013-11-22 22:24:07 -05:00
Hugo Villeneuve
495c40d54e Add PSW sub window 2013-11-21 00:33:25 -05:00
Hugo Villeneuve
484f0d39a0 Use macro to set name of sub window 2013-11-21 00:33:25 -05:00
Hugo Villeneuve
b7b1c62985 Change scope of local variable to static 2013-11-21 00:33:25 -05:00
Hugo Villeneuve
f49cd33240 Add option to display bool hex character 2013-11-21 00:33:25 -05:00
Hugo Villeneuve
6743535949 Add PSW generic bit write/read functions 2013-11-21 00:33:25 -05:00
Hugo Villeneuve
98b757f83d Add parity bit update each instruction cycle 2013-11-17 22:52:00 -05:00
Hugo Villeneuve
ad5ac01289 Add function to read 16-bit address/offset/value from pgm memory 2013-11-17 22:23:50 -05:00
Hugo Villeneuve
61ae08f73d Fix bug with MOV DPTR,#data16 instruction
Source variable was 8 bits instead of 16 bits.
2013-11-17 22:22:48 -05:00
Hugo Villeneuve
47852aee98 Remove unused destination adressing mode #data16
Even if it is required, the destination variable is only 8-bits,
so this would have been a potential bug.
2013-11-17 22:22:27 -05:00
Hugo Villeneuve
f9394f5df4 Make MUL and DIV use generic source/destination variables
To remove confusing commented code and compilation warning
2013-11-17 18:48:26 -05:00
Hugo Villeneuve
e6f062fc43 Refactor perl code to write C source code line 2013-11-17 18:34:36 -05:00
Hugo Villeneuve
5905b40585 Refactor perl code to write file header 2013-11-17 18:33:34 -05:00
Hugo Villeneuve
82819ebb72 Add overflow and auxiliary carry flags manipulation functions 2013-11-17 18:33:26 -05:00
Hugo Villeneuve
eff770859b Simplify carry bit set/clr functions 2013-11-17 17:26:54 -05:00
Hugo Villeneuve
d1c1972f26 Add carry bit definitions 2013-11-17 17:26:54 -05:00
Hugo Villeneuve
84075f7a17 Move PSW bit manipulation functions to psw.c 2013-11-17 17:26:54 -05:00
Hugo Villeneuve
47f57bc580 Add carry flag manipulation functions 2013-11-17 17:26:54 -05:00
Hugo Villeneuve
21fb2cf2a3 Add stack push/pop functions 2013-11-17 17:26:54 -05:00
Hugo Villeneuve
3615ed71ec Add DPTR read/write functions 2013-11-17 17:26:54 -05:00
Hugo Villeneuve
70b6c9964c Add comment about reset value of stack pointer 2013-11-17 17:26:54 -05:00
Hugo Villeneuve
b7f56a8019 Fix error with ADD instruction and AC bit
The overflow bit was written instead of the auxiliary carry bit.
2013-11-17 17:26:53 -05:00
Hugo Villeneuve
bbd37b7501 Fix bug with ANL instruction 2013-11-17 15:28:10 -05:00
Hugo Villeneuve
00fd5e1abb Fix bug with ORL instruction 2013-11-17 15:28:02 -05:00
Hugo Villeneuve
e2ad770d00 Fix error with JMP @A,DPTR instruction
The resulting jump address is simply the sum of the values in the accumulator
and the DPTR registers, not the indirect read of that sum.

Error reported and fixed by Anthony (antliu at gmail.com).
2013-11-05 22:17:21 -05:00
Hugo Villeneuve
c4f4ebc5ab Fix error with RETI instruction
The stack pointer was not updated correctly.

Error reported and fixed by Anthony (antliu at gmail.com).
2013-11-05 22:17:17 -05:00
Hugo Villeneuve
ae50fa4fee Add view menu option to view/hide SFR memory dump window 2013-11-05 21:55:34 -05:00
Hugo Villeneuve
5e54765874 Add support to view/hide SFR memory dump window in config file 2013-11-05 21:55:34 -05:00
Hugo Villeneuve
b72c9b3c1b Update TODO 2013-11-05 21:55:34 -05:00
Hugo Villeneuve
68a328d198 Refactor code to create memory windows 2013-11-05 21:50:18 -05:00
Hugo Villeneuve
c2ef73ab94 Refactor log functions 2013-11-05 21:50:18 -05:00
Hugo Villeneuve
add152ddb8 Add option to specify maximum pgm memory size 2013-11-05 21:50:18 -05:00
Hugo Villeneuve
593009d28f Refactor code to read/write different memory types
Dynamic memory buffers allocation depending on sizes specified with command-line
options.

Add future support for separate IRAM and SFR buffers.
2013-11-05 21:50:18 -05:00
Hugo Villeneuve
dd2261ab6c Rename macros for maximum memory sizes 2013-11-05 21:50:18 -05:00
Hugo Villeneuve
276025c248 Limit default external memory size to 1024 bytes
Emulator is running very slow if external memory is at its maximum of 64K.
2013-11-05 21:50:18 -05:00
Hugo Villeneuve
ae3a0ccd89 Fix syntax error in comment 2013-11-05 21:50:18 -05:00
Hugo Villeneuve
83d7d5ddbe Do not reset emulator on file load (no ram clear)
Reset only when loading first file at application startup.
2013-11-05 21:50:18 -05:00
Hugo Villeneuve
fb0a9a8db4 Add Timers 0 and 1 to SFR window 2013-11-05 21:50:18 -05:00
Hugo Villeneuve
0f98327ed3 Add option to specify maximum memory sizes 2013-11-05 21:50:18 -05:00
Hugo Villeneuve
4c86604f94 Add view menu option to enable/disable IRAM/XRAM windows 2013-11-05 21:50:18 -05:00
Hugo Villeneuve
3edb6517f8 Add view menu option for selecting bits per row (8/16) 2013-11-05 21:50:18 -05:00
Hugo Villeneuve
ca2a000a22 Add support for bits per row in config file
Also add support for viewing internal and external memory windows
in config file.

These 3 new variables are not yet connected (TODO).
2013-11-05 21:50:17 -05:00
Hugo Villeneuve
bd0627548f Add live option to change windows layout
Restart UI when changing layout. This is working, altough the main window
temporarily disapear in doing so.
2013-11-05 21:50:17 -05:00
Hugo Villeneuve
02656a7a70 Use fixed font for ASCII column 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
42f213fff5 Align memory data columns text on left side 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
45be0d0218 Adjust memory index column header according to number of data columns 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
7657e4d7db Harmonize windows refresh function names 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
1aa4da2dd7 Save vpane position for memory windows 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
d367f394a9 Add external memory window vpaned_mem 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
fcc8caad9c Convert memwin to display internal or external memory 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
7e70fab3bd Use single function to refresh all windows
Use emugtk_UpdateDisplay() to replace individual calls to these functions:
  regwin_Show();
  memwin_DumpD();
  pgmwin_Disasm();
2013-11-05 21:50:17 -05:00
Hugo Villeneuve
b3a099e3ee Code cleanup (tree view store init) 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
aae7cef399 Increase dissassembled instructions lines from 24 to 100 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
7f00cb821f Add red color for current instruction in pgmwin 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
bb59ed1964 Refresh pgmwin after modifying regwin (PC) 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
4093ad22ec Add offset address to memwin dump header 2013-11-05 21:50:17 -05:00
Hugo Villeneuve
3002753538 Remove address parameter when dumping memwin 2013-11-05 21:50:16 -05:00
Hugo Villeneuve
3e67c30ca5 Refactor code for memwin and pgmwin modify
Add common functions int2asciihex and asciihex2int
2013-11-05 21:50:16 -05:00
Hugo Villeneuve
f3f6f52c0e Registers window can now be edited 2013-11-05 21:50:16 -05:00
Hugo Villeneuve
1e334b447f Refresh register window after any memory modification
Banked registers R0 to R7 depend on internal memory content.
2013-11-05 21:50:16 -05:00
Hugo Villeneuve
e224fa1ef2 Memory window can now be edited 2013-11-05 21:50:16 -05:00
Hugo Villeneuve
8dc9dd02e6 Replace macro EMU8051_DEBUG with logging functions 2013-11-05 21:50:16 -05:00
Hugo Villeneuve
7b400e8dd6 Replace custom command-line options processing with argp 2013-11-05 21:50:16 -05:00
Hugo Villeneuve
a38ca01fb6 Add debug log functions 2013-11-05 21:50:16 -05:00
Hugo Villeneuve
04200c3465 Replace custom help->about dialog with gtk_show_about_dialog 2013-11-05 21:50:16 -05:00
Hugo Villeneuve
746f97a65c Add web site url and bug report email to AC_INIT 2013-11-05 21:50:15 -05:00
Hugo Villeneuve
ac54ee974b Act as if reset was pressed if no hex file is specified at startup 2013-10-09 21:08:17 -04:00
Hugo Villeneuve
6c53f8ff02 Replace GTK deprecated functions
gtk_signal_connect_object -> g_signal_connect
gtk_menu_bar_append -> gtk_menu_shell_append

Also simplified ShowMessage function.
2013-10-09 21:08:17 -04:00
Hugo Villeneuve
311abd4cfc Replace deprecated gtk_clist (pgmwin) 2013-10-09 21:08:17 -04:00
Hugo Villeneuve
9e76ea5f95 Replace deprecated gtk_clist (regwin) 2013-10-09 21:08:17 -04:00
Hugo Villeneuve
9983810898 Add title to memory window 2013-10-09 21:08:17 -04:00
Hugo Villeneuve
327fe8f226 Refactor memory window ASCII display code section 2013-10-09 21:08:17 -04:00
Hugo Villeneuve
c862545432 Refactor memory window code section 2013-10-09 21:08:17 -04:00
Hugo Villeneuve
4f35cb1366 Replace deprecated gtk_clist (memwin) 2013-10-09 21:08:16 -04:00
Hugo Villeneuve
2dcf6a1a19 Replace autogen custom commands with autoreconf 2013-10-09 21:08:16 -04:00
Hugo Villeneuve
51b8355b29 Rename config to build-aux 2013-10-09 21:08:16 -04:00
Hugo Villeneuve
0ddadb203a Remove unused configure option --enable-debug 2013-10-09 21:08:16 -04:00
Hugo Villeneuve
0d3230092d Remove unused/commented code 2013-10-09 21:07:22 -04:00
Hugo Villeneuve
c9f73afe56 Remove superfluous function call gtk_widget_show_all() when creating menu 2013-10-09 21:07:22 -04:00
Hugo Villeneuve
00871e77de Remove superfluous function WindowDestroyEvent 2013-10-09 21:07:22 -04:00
Hugo Villeneuve
ba7ff1a7a7 Fix bug with children not resizing with main window 2013-10-09 21:07:22 -04:00
Hugo Villeneuve
696410ca8d Add Gtk windows diagram
Rename main_vbox -> vbox.
2013-10-09 21:07:22 -04:00
Hugo Villeneuve
36ea763e1d Add example configuration file 2013-10-09 21:07:22 -04:00
Hugo Villeneuve
536beb0f1e Save paned positions and main window size to config file 2013-10-09 21:07:21 -04:00
Hugo Villeneuve
9cddfd237c Add support for saving UI settings to config file 2013-10-09 21:07:21 -04:00
Hugo Villeneuve
de33eb581d Rename fixed_frame variable to scrollwin 2013-10-01 22:45:22 -04:00
Hugo Villeneuve
4760af53ee Add vpaned to separate memory dump window 2013-10-01 22:45:22 -04:00
Hugo Villeneuve
5143afcd54 Add hpaned to separate pgm and disassembly windows 2013-10-01 22:45:22 -04:00
Hugo Villeneuve
5d3fdb383d Remove obsolete gtksizes.h 2013-10-01 22:45:22 -04:00
Hugo Villeneuve
bd7fa9a1fb Eliminate all fixed size windows 2013-09-30 22:37:05 -04:00
Hugo Villeneuve
c361bcde92 Allow frames to expand and fill inside vbox and hbox 2013-09-30 22:17:54 -04:00
Hugo Villeneuve
c233aa6715 Remove fixed frame containing the 3 major windows 2013-09-30 22:17:54 -04:00
Hugo Villeneuve
aef9693dac Replace fixed frames with scrollable windows
Done for program, register and memory dump windows.
2013-09-30 22:17:54 -04:00
Hugo Villeneuve
d75d156ebc Replace deprecated gtk_widget_set_usize() 2013-09-30 21:19:45 -04:00
Hugo Villeneuve
43cc485237 Replace deprecated gtk_menu_append() 2013-09-30 21:19:45 -04:00
Hugo Villeneuve
cece320b97 Replace deprecated gtk_signal_connect() 2013-09-30 21:19:45 -04:00
Hugo Villeneuve
4d60f6b8f7 Increase spacing between buttons 2013-09-30 21:19:45 -04:00
Hugo Villeneuve
be12d598fd Replace deprecated functions for displaying pixmap buttons 2013-09-30 21:19:41 -04:00
Hugo Villeneuve
5dc03cd1b8 Replace gtk_idle functions with g_idle equivalents 2013-09-08 23:36:35 -04:00
Hugo Villeneuve
f2fdef17a2 Activate gtk deprecated compilation flags 2013-09-08 23:35:32 -04:00
Hugo Villeneuve
9a47639756 Remember previous opened directory in file selection dialog 2013-09-08 20:54:17 -04:00
Hugo Villeneuve
a689c76798 Use current working directory for initial file selection dialog 2013-09-08 20:54:15 -04:00
Hugo Villeneuve
e57f14d42e Replace gtk_file_selection dialog with gtk_file_chooser
Increase minimum gtk version to 2.4.0.
2013-09-08 20:54:10 -04:00
Hugo Villeneuve
61c76cca39 Release v1.1.2 2013-09-08 18:54:52 -04:00
Hugo Villeneuve
fd6fa7c56a Fix compiler warning (and potential bug) in auto-generated 8051 instructions
Original warning:
  warning: operation on ‘cpu8051.pc’ may be undefined [-Wsequence-point]
2013-09-08 18:54:52 -04:00
Hugo Villeneuve
581d60d73a Fix compiler warning about unused variable set by getline() 2013-09-08 18:54:52 -04:00
Hugo Villeneuve
47a60dcfbf Fix compiler warning about unused variable set by getch() 2013-09-08 18:54:52 -04:00
Hugo Villeneuve
67a0a710e0 Fix error with CJNE instruction
When the comparison was true, the PC was advanced by 2 instead of 3 bytes.

Error reported and fixed by Tobias Diedrich (ranma at tdiedrich.de).
2013-09-08 18:54:52 -04:00
Hugo Villeneuve
7121e7929d Add test file for CJNE bug 2013-09-08 18:54:52 -04:00
Hugo Villeneuve
761e720501 Remove obsolete comment about older c++ code 2013-09-08 18:54:52 -04:00
Hugo Villeneuve
60f3340a9f Fix trailing whitespace 2013-09-08 18:54:52 -04:00
Hugo Villeneuve
dfa6052123 Create two separate executables, emu8051-cli (default) and emu8051-gtk
emu8051-gtk is optional and compiled only if Gtk+ is detected.

Add optional size parameter when dumping memory.
2013-09-08 18:54:52 -04:00
Hugo Villeneuve
9b40aee50b Add display of address in case of error 2013-09-08 18:54:52 -04:00
Hugo Villeneuve
da17471fcb Fix error with SJMP instruction
Error reported and fixed by Pierre Ferrari (piferr4ri at gmail.com).
2013-09-08 18:54:52 -04:00
Hugo Villeneuve
fc3c2b3dbd Improve window sizing
Based on suggestions from Pierre Ferrari (piferr4ri at gmail.com).
2013-09-08 18:54:51 -04:00
Hugo Villeneuve
97bcc837a4 Remove unnecessary autoconf checks
Disable debug message when not compiled in debug mode.
2013-09-08 18:54:51 -04:00
Hugo Villeneuve
31155ac867 Fix syntax errors in ascii to int conversion 2013-09-08 18:54:51 -04:00
Hugo Villeneuve
3c5ab93d18 Conversion from iso8859-1 to utf-8 2013-09-08 18:54:51 -04:00
Hugo Villeneuve
b235414950 Run checkpatch.pl on every source file 2013-09-08 18:54:51 -04:00
Hugo Villeneuve
fb3b352957 Update NEWS and ChangeLog 2013-09-08 18:54:51 -04:00
Hugo Villeneuve
a78a174393 Reintroduce command line mode 2013-09-08 18:54:51 -04:00
Hugo Villeneuve
fc4dd8fa3a Update Free Software Foundation address 2013-09-08 18:54:51 -04:00
Hugo Villeneuve
6a65dca9d5 Add licencing information to each source file
Remove some debug messages.
2013-09-08 18:54:51 -04:00
Hugo Villeneuve
82756d9818 Upgrade to gtk+-2
Remove gtk+-1.0 support.
2013-09-08 18:54:51 -04:00
Hugo Villeneuve
2519aa8162 Add automatic regeneration of files from opcode2c.pl to src/Makefile.am 2013-09-08 18:54:51 -04:00
Hugo Villeneuve
b1fbb635cd Code simplification and cleanup 2013-09-08 18:54:51 -04:00
Hugo Villeneuve
4c305c73f8 Modify generated files for 8051 instructions
Seems to be working good.
2013-09-08 18:54:51 -04:00
Hugo Villeneuve
ec415e2315 Add options -h and -version
Merge common function LoadHexFile() to file.c.
2013-09-08 18:54:51 -04:00
Hugo Villeneuve
69b536c338 Change autogen.sh script and rename test_files directory 2013-09-08 18:54:50 -04:00
Hugo Villeneuve
87d58c2f12 Increase version number 2013-09-08 18:54:33 -04:00
Hugo Villeneuve
223164c042 Add documentation 2013-09-08 10:49:21 -04:00
125 changed files with 9682 additions and 9969 deletions

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
*.o
*/.deps/
*~
/aclocal.m4
/autom4te.cache
/config.cache
/config.log
/config.status
/configure
Makefile
Makefile.in
config-h.in
config.h
stamp-h1

23
AUTHORS
View File

@ -0,0 +1,23 @@
Original authors of emu8051:
Hugo Villeneuve
Jonathan St-André
Pascal Fecteau
Jimmy Ringuette
Actual maintainer:
Hugo Villeneuve
Debian package maintainer:
Bhavani Shankar
Additional contributors / bugs fixing:
Anthony Liu
Pierre Ferrari
Tobias Diedrich

492
ChangeLog
View File

@ -1,492 +0,0 @@
------------------------------------------------------------------------------
2002/11/12 Hugo Villeneuve <hugovil@videotron.ca>
-Removed some warnings for GCC 3.2: replaced <fstream.h> by <fstream>
and <iostream.h> by <iostream>.
-Added "using namespace std;" in EmuGtk.hpp (for GCC 3.2)
-Removed all unused variables
-Corrected error in CPU8051.cpp, in function:
'void CPU8051::IntMemBitInfo( unsigned int BitAddress, char *Text )'
Modified this:
'sprintf( &Text[ TextLength ], ".%X", BitAddress );'
instead of:
'sprintf( &Text[ TextLength ], ".%X" );'
-In Opcode2cpp.pl (line 767), modified for GCC 3.2:
'print INST_IMP " funcptr[$i]=&CPU8051::$ifunc;\n";'
instead of:
'print INST_IMP " funcptr[$i]=&$ifunc;\n";'
-EmuGtk.cpp, added '#include <iostream>'
-Modified the return type of some functions to void to remove warnings.
-In function 'void RegWin::Show( CPU8051 *CPU )' (RegWin.cpp), removed all
the '\n' in 'gtk_clist_set_text' calls (to fix a display problem)
------------------------------------------------------------------------------
99/04/27 Hugo Villeneuve <villen01@gel.ulaval.ca>
- Ajoute les fonctions DumpInt dans EmuConsole.hpp ainsi que ReadInt
dans CPU8051.hpp. Corrige des bugs dans WriteInt et WriteExt.
- Corrige l'implementation des timers. Les 4 modes ont ete testes et
semblent bien fonctionner maintenant. LEs flags sont mis correctement
et les timers augmentent maintenant (au lieu d'etre decrementes).
- Ajoute un fichier timer.hex pour tester les timers.
-----------------------------------------------------------------------------
99/04/22 Hugo Villeneuve <villen01@gel.ulaval.ca>
- Ajoute les fonctions ME, MI et MP (voir definitions dans
EmuConsole.cpp). Ajoute les fonctions membres WriteExt et WriteInt
dans la classe CPU8051 afin de suivre la logique de l'espace
memoire du 8051. WriteExt permet de modifier la memoire externe
qui va de $00 a $FFFF (et non de $100 a $FFFF comme c'etait le cas
avant). De meme, WriteInt permet de modifier la memoire interne qui
va de $00 a $FF (incluant les SFR). Meme si la memoire externe
contient les adresses $00 a $FF, il n'y a pas de conflit avec la
memoire interne de $00 a $FF car la memoire externe est accedee avec
l'instruction MOVX alors que la memoire interne l'est avec les
instructions MOV (direct ou indirect).
- Renomme l'option DD du menu pour DE (dump External data memory).
Change la description de l'option DI du menu pour Dump External
Data Memory.
- Ajoute la fonction ReadExt dans la classe CPU8051, toujours pour
la logique de la memoire du 8051. Ajoute la fonction DumpExt dans la
classe EmuConsole pour dumper la memoire externe.
- Ces nouvelles fonctions ont ete testees et semblent bien fonctionner.
------------------------------------------------------------------------------
99/04/09 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Refait marche le RunningState avec les classes.
- Reconnecte les signaux aux boutons Trace, Run, Reset et Quit.
- Ajoute bouton Step qui ajoute un breakpoint a la ligne suivante
et passe en RunningState. Pratique lorsqu'arrive un CALL et qu'on ne
veut pas y entrer contrairement a Trace.
------------------------------------------------------------------------------
99/04/06 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Creation de EmuConsole.hpp et EmuConsole.cpp
- Cette nouvelle archive est presque rendue au meme niveau que
l'ancienne. Vous allez pouvoir commencer a laisser faire l'ancienne
et vous concentrer sur celle-ci.
------------------------------------------------------------------------------
(Les modifs annoncee se rapportent a l'ancienne archive mais elles ont ete
ramenee dans celle-ci par Jonathan St-Andre)
99/04/05 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Corrige qq malfonctions dans exec de mainconsole.cpp (nb d'inst.
peut etre l'infini, caractere est attendu au clavier seulement
si l'execution est arretee par une touche.
- Corrige probleme d'instructions sans operandes mal desassemblees
(il ne faut pas ecrire le caractere ' ' dans la chaine, il faut
utiliser sprintf avec " " a la place car sprintf termine la chaine
avec un 0 a la fin. La chaine n'etait pas terminee par un 0 et elle
affichait du garbage de la memoire)
- Corrige probleme dans disasm.cpp en rapport avec addr11 qui ne
prenait pas opcode mais memoire[opcode] (je devais etre chaud quand
j'ai ecrit ca).
- Bouton Run se change en Stop dans l'interface Gtk+ lorsque l'on
clique dessus et le cpu se met en mode execution. Les fonctions de
l'interface restent disponibles. N'importe quelle action dans
l'interface(excepte le fait de cliquer dans les fenetre memoire
et programme) cause l'arret de l'execution et la mise a jour
de l'affichage.
- Il est possible de placer des breakpoints pendant qu'il est
dans le "RunningState".
- Enleve les pixmaps sur les boutons dans l'interface Gtk+
- Ajoute verification de breakpoint deja existant dans
setbreakpoint.
Hugo Villeneuve <villen01@gel.ulaval.ca>
-Modifie l'affichage de disasm pour que les operandes soient alignees.
-Modifie la fonction DP pour qu'elle prenne l'adresse du PC par
defaut si aucune adresse n'est specifiee.
- Erreur avec l'instruction ACALL qui ne calculait pas l'adresse
correctement et qui ne poussait pas l'adresse de retour sur la pile.
Il est important que le PC soit incremente de 2 avant de calculer
addr11 et de pousser le PC sur la pile...
Il faut aussi modifier le dessassemblage de cette instruction qui
n'affiche que la deuxieme operande (adresse de 8 bits), alors que
l'adresse est sur 11 bits...
-Erreur avec l'instruction RET( fichier siae1.asm adresse 03A4) ,
affiche RET @%K
-Ajoute la possibilite d'arreter l'execution du programme en pesant
sur n'importe quelle touche grace a la fonction kbhit().
-Ajoute les fonctions SB, RB et DB pour les breakpoints dans le
mode console. L'execution se fait jusqu'au breakpoint. Une fois
arrive au breakpoint, si on fait de nouveau EM, on peut continuer
l'execution du programme passe ce breakpoint. Autrement dit, EM
ne verifie pas si la premiere instruction qu'il execute est un
break point, ce qui est pratique pour continuer l'execution du prog
apres un breakpoint.
------------------------------------------------------------------------------
99/03/31-
99/04/03 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Reecriture de TOUT les sources en imbriquant au maximum
dans des classes pour que ce soit plus lisible et reutilisable.
- Les classes sont CPU8051, Memory, EmuGtk, MemWin, RegWin, PgmWin
et les exceptions.
- Tout est en anglais pour rendre le programme disponible sur
internet.
- Je n'ai pas encore refais l'interface Console en classes donc
elle n'est pas incluse dans cette archive. Il faudrait vraiment
la refaire en tant que classe.
- Ajout fichiers TODO, CREDITS et COPYING (license GPL)
------------------------------------------------------------------------------
99/03/30 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Corrige bug lors du desassemblage dans l'interpretation des
adresses directes dans 0-7F. disasm.cpp
- Corrige bug dans l'opcode 0x85, ajoute conditions particulieres
pour cette instruction dans script Perl et dans desassemblage.
Les operandes de cette instruction sont inversees dans la memoire
programme. Ex.: MOV 50H,51H est ecrit 85 51 50 dans la memoire
programme.
Hugo Villeneuve <villen01@gel.ulaval.ca>
- Bug dans les instructions ayant un mode d'adressage direct qui
utilisent des adresses dans 0-7F. Le desassembleur interprete les
adresses comme etant des adresses de bit.
- Bug dans l'opcode 0x85 MOV direct,direct. La source et la
destination sont inverses dans le desassemblage et dans l'execution.
------------------------------------------------------------------------------
99/03/29 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Remplace string::erase pour string::replace partout, g++ a
l'universite ne connait pas encore string::erase, c'est trop recent.
- Ajoute "-w" pour disabler les warnings et "-fhandle-exceptions"
pour activer les exceptions a l'universite.
Pascal Fecteau <fectea00@gel.ulaval.ca>
- Ajoute .h comme extension aux fichiers inclus, sinon ca ne
fonctionne pas a l'universite.
Pascal Fecteau <fectea00@gel.ulaval.ca>
Hugo Villeneuve <villen01@gel.ulaval.ca>
- Corrige une erreur dans les instructions AJMP addr11
------------------------------------------------------------------------------
99/03/28 Hugo Villeneuve <villen01@gel.ulaval.ca>
- Modification de la presentation de "Dump Register" sur la console.
Beaucoup plus facile a lire maintenant.
- Correction d'un bug dans l'instruction DA (opcode 0xD4).
------------------------------------------------------------------------------
99/03/27 Hugo Villeneuve <villen01@gel.ulaval.ca>
- Correction d'un probleme avec l'instruction CJNE.
- Correction de bugs dans LoadHexFile (voir 99/03/22)
Jonathan St-Andre <standr00@gel.ulaval.ca>
- Augmente la hauteur de la fenetre Internal RAM.
- Correction de probleme avec tous les XCH et XCHD, l'operande source
n'etait pas modifiee (Trouve par Hugo et suggestion de correction par
Hugo).
- Ajout de P0, P1, P2 et P3 dans la fenetre des registres.
(Suggestion d'Hugo).
- View -> Data Memory Dump et View -> Program Memory Dump sont
fonctionnels. On ne peut visionner que les 16384 premiers octets.
Il ne veut pas prendre 65536 lignes dans une scrolled window.
Probablement parce que 18colonnes x 65536lignes = 1179648 cellules
est beaucoup trop.
- J'ai remarque qu'avec Gtk, on peut facilement changer les raccoucis
dans les menus. Pour associer "View -> Program Memory Dump" au
raccourci "Alt-2" par exemple, il suffit d'aller dans le menu "View",
se placer au dessus de "Program Memory Dump" et appuyer "Alt-2".
Le menu se modifiera automatiquement pour afficher "Alt-2" au bout
de la ligne et desormais, lorsque vous appuierez "Alt-2", l'action
sera executee. Ca dure seulement durant la session presente.
- Reduit la taille de la fenetre principale en largeur de 120 pixels
et en hauteur de 20 pixels.
------------------------------------------------------------------------------
99/03/25 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Fenetre dump connais la position ou on clique dedans.
- Generalise dans une classe la fenetre memorydump, il sera plus
facile d'ajouter plusieurs fenetres memory dump a partir du menu
plus tard.
- Implemente Run jusqu'a un breakpoint (si aucun breakpoint,
loop sans fin -> il faut killer).
- Suffit de cliquer sur une ligne de programme dans Gtk pour placer
ou retirer un breakpoint. Les breakpoints apparaissent comme une
asterisque (*) a droite de l'adresse dans la fenetre program.
- Ajoute bouton Run dans interface Gtk
- Implemente quelques fonctions necessaires au breakpoints.
- Change un peu le layout
- Enleve image de fond (cause leger delai au chargement)
- Fait un peu de menage dans fichiers relatifs au Gtk
------------------------------------------------------------------------------
99/03/23 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Changement des champs GTK_TEXT des fenetres Registre, Program et
Internal RAM pour des champs GTK_CLIST. Plus beau, moins de
flickering quand on trace et plus pratique pour ce qui s'en vient.
- Integration des fichiers xpm dans l'executable. Mais c'est encore
trop long a charger lors de l'execution, va probablement falloir les
compresser ou laisser faire l'image de fond.
- Ajout de pixmaps sur les boutons Trace, Reset et Quit (Gtk)
- Ajout de pixmap comme fond (Gtk)
------------------------------------------------------------------------------
99/03/22 Hugo Villeneuve <villen01@gel.ulaval.ca>
- Corrige un bug dans la fonction LoadHexFile : Le checksum n'etait
pas calcule correctement, ce qui entrainait des erreurs a l'ouverture
de certains fichiers HEX. L'erreur venait du fait que le checksum se
calculait avec la valeur absolue du LoadOffset, au lieu d'utiliser
les caracteres composant le LoadOffset. Exemple : si LoadOffset =
0103, il faut additionner 01h+03h=4h au Checksum et non pas 0103h =
259 en decimal.
- Deplace la fonction enleve_espaces de main_console vers mainemu
car elle est commune aux deux interfaces graphiques.
- Modifie la fonction majuscules pour qu'elle puisse convertir les
lettres de minuscule a majuscule meme si la chaine contient des
chiffres ou autres signes de ponctuation.
- Modifie la declaration des fonctions dans tous les fichiers .hpp:
enleve le nom des parametres car c'etait inutile.
- Stocke le nom des registres dans un fichier registres8051.hpp.
Ainsi, si on veut emuler un autre type de processeur, il suffira
de se creer un autre fichier registres8052xxx.hpp par exemple.
- Implemente l'affichage en francais ou en anglais dependant de
l'option passee sur la ligne de commande. L'interface est beaucoup
plus lisible de cette facon. Par defaut, l'affichage est en anglais.
------------------------------------------------------------------------------
99/03/21 Hugo Villeneuve <villen01@gel.ulaval.ca>
- Ajoute deux parametres qu'on peut passer par la ligne de commande:
/? affiche les options disponibles sur la ligne de commande.
-f force l'affichage en francais (pas encore implemente!!!)
- Ajoute le controle d'erreur pour le chargement d'un fichier HEX.
Les differentes erreurs sont controlees ( checksum, rectype,
fin de fichier, etc.).
- Modifie la fonction unasm pour qu'elle accepte 0,1 ou 2 parametres.
U (adresse) (nombre d'instructions)
Si adresse et nombre d'instructions non-specifies:
Adresse = PC et Nombre d'Instructions = 16
Si adresse specifie et nombre d'instructions non-specifie:
Adresse = adresse specifiee et Nombre d'Instructions = 16
Si adresse specifie et nombre d'instructions specifie:
Adresse = adresse specifiee et Nombre d'Instructions = nb specifie
A noter: on peut specifier une adresse comme etant un nombre
hexadecimal, ou tout simplement en entrant "PC" ou "pc".
Jonathan St-Andre <standr00@gel.ulaval.ca
- Fait le menage dans la fonction main
- Modifie Makefile.console et Makefile.gtk
- Rearrangement des fichiers pour limiter les impacts sur
tout le projet lors de modifications dans une partie et
pour accelerer la compilation (en modules).
- Creation de mainconsole.hpp + mainconsole.cpp
- Creation de maingtk.cpp + maingtk.hpp
- Creation de mainemu.cpp + mainemu.hpp
- Elimine fonctions.cpp.
- Elimination du 2e parametre a unasm. Desassemble
de nouveau 16 instructions.
- Ajustement du menu pour qu'il rentre dans la largeur
d'un terminal 80x25.
Jimmy Ringuette <ringue00@gel.ulaval.ca>
- Ajout des interruptions du port serie.
- Ajout du timer 2 (8052).
------------------------------------------------------------------------------
99/03/20 Hugo Villeneuve <villen01@gel.ulaval.ca>
- Separe le fichier main.cpp en deux: main.cpp et fonctions.cpp.
fonctions.cpp contient les fonctions necessaires a main.cpp.
- Ajoute un fichier exceptions.hpp qui permet de gerer les erreurs.
- Modifie le Makefile en consequence.
- On peut maintenant entrer les adresses < a quatre caracteres :
ex: adresse 0000h = 0 ou 00 ou 000 ou 0000.
- Enleve le include <stdlib.h>
- Remplace toutes les commandes printf du main par cout.
- Modifie l'apparence du menu.
- Le programme est maintenant plus robuste en ce qui concerne les
erreurs de syntaxe, les adresses invalides, etc (a tester...).
- Modifier l'operation et la syntaxe de certaines commandes
S (set register) devient MR (modify register) car set veut
plutot dire "mettre a 1", et on pourra aussi implementer
MM (modify Memory).
R devient DR (display Register), pour suivre la logique de
DP, DM et DI.
- Ajoute une commande Execute Memory: EM addr n
- La gestion des chaines de caracteres se fait maintenant
uniquement avec des variables de type STRING, selon le C++.
- Enleve variables i,j,k et inputcars dans le main.
- Modifie la fonction RESET pour quelle n'affiche pas les
registres au demarrage... ca faisait pas beau! Ajoute
cependant un message pour dire que le up est resette.
- Pour changer un registre, on doit entrer PC (et non p) ainsi
que SP (et non seulement s).
- Ajoute une fonction qui convertit une chaine de caracteres
en majuscules.
------------------------------------------------------------------------------
99/03/19 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Fonction reset51() ajoutee dans cpu8051.cpp, reset() ajoutee
dans main.cpp.
- Commande "Z" fait un reset du processeur sur la console et le
bouton Reset fonctionne dans le GUI.
Jimmy Ringuette <ringue00@gel.ulaval.ca>
- Les interruptions sont maintenant implementees. check_hardware() a
ete supprimee et Do_timers() est appelee directement de exec8051().
------------------------------------------------------------------------------
99/03/18 Hugo Villeneuve <villen01@gel.ulaval.ca>
- Modifie l'entree des commandes pour gerer un peu plus les erreurs
de syntaxe (je n'ai pas fini, il y a encore de la job a faire pour
mettre ca error proof).
- Simplifie l'entree des parametres pour chacune des fonctions.
- Re-modifie l'instruction trace pour avoir seulement deux modes:
trace a adresse et trace 1 instruction. Cela simplifie l'entree de
la commande (on n'a pas a faire TA, qui n'est pas une commande
standard dans les emulateurs). Si on veut faire tracer pour plusieurs
instructions, alors il suffira d'implementer la commande
EXECUTE Nombre_instructions, ce qui est beaucoup plus logique et
c'est ce qu'on retrouve dans la plupart des emulateurs.
- Ajoute la description des commandes en francais (loi 101).
------------------------------------------------------------------------------
99/03/18 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Le bouton Trace dans la version Gtk+ fonctionne. On peut tracer
et les 3 fenetres(registres, memoire, programme) se mettent a jour.
- Ajout de 2 nouvelles fonctions trace : "tracenb()" et "traceat()"
Qui, respectivement, prenent un nombre d'instruction a executer ou
une adresse ou commencer l'execution. La fonction trace() a ete
resimplifiee.
- Dans les instructions RET, RETI, LCALL, PUSH et POP la pile prend
la iram seulement pour les adresses sous 0x80, la data RAM est
utilisee autrement. Avant, les SFR se faisaient ecraser!
- Modes d'addressage addr16, reladdr, #data16 modifies!
En tenant compte de ce que Hugo avait fait remarquer ce matin :
ex.: si PC++ apparait 2 fois sur une ligne, les 2 fois il repartira
de la meme valeur de PC et suite a cette ligne, on se trouve avec
un PC incremente 1 fois au lieu de 2.
- Menu accepte maj/minuscules
- Corrige bug dans "setreg", les registres peuvent vraiment
etre donnes en maj/minuscules maintenant.
------------------------------------------------------------------------------
99/03/17 Hugo Villeneuve <villen01@gel.ulaval.ca
- Corrige les instructions LJMP et LCALL qui ne calculaient pas la
bonne adresse pour le PC. Toutes les autres instructions de
branchement sont probablement a revoir pour le meme probleme. Le
probleme etait cause par la syntaxe dans le fichier instructions.hpp
(lignes ou on retrouve addr16 = (pgm_mem[PC++] << 8)+pgm_mem[PC++] a
remplacer par addr16 = (pgm_mem[PC+1] << 8) + pgm_mem[PC+2] )
- Modifie la commande TRACE pour qu'on puisse lui passer une adresse
de depart comme parametre (main.cpp lignes 406-409) et modifie
en consequence ascii2hex pour qu'il ignore les espaces avant
l'adresse. (main.cpp ligne 133).
------------------------------------------------------------------------------
99/03/14 Pascal Fecteau <fectea00@gel.ulaval.ca>
- Correction de bugs relatifs a la compilation sur VC5.
Dont ajout de #include <string.h>.
------------------------------------------------------------------------------
99/03/13 Jimmy Ringuette <ringue00@gel.ulaval.ca>
- Ajout des timers dans cpu8051.cpp. Il faudrait tester a fond.
------------------------------------------------------------------------------
99/03/12 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Je crois qu'il sera plus interessant si on garde le memory
dump normal dans une fenetre exterieur et dont on pourra en ouvrir
plusieurs pour monitorer differents endroits de la memoire, c'est
pourquoi je n'ai place que "Internal RAM" comme memory dump dans
la fenetre principale.
- Au demarrage, effectue un premier memory dump dans la fenetre
"Internal RAM", un unasm dans "Program" et un show register dans
"Registers".
- Bouton Quit, menus "File -> Quit" et "Help -> About" reagissent.
- Comporte maintenant 2 Makefile : Makefile.console(fonctionne sur
toutes les plateformes) et Makefile.gtk(teste seulement sous Linux).
- DEBUT d'interface graphique Gtk+ (ne fait qu'afficher une fenetre
avec un layout tres simple), presentement je cours apres des sources
de documentations.(le manuel n'est pas encore complet)
------------------------------------------------------------------------------
99/03/09 Jimmy Ringuette <ringue00@gel.ulaval.ca>
- Regle le bug avec mul (probleme avec les bits 15-8 du resultat
ne se ramenaient pas dans les bits 7-0 du registre B)
- La conversion chaine->hexadecimal accepte les minuscules
- Il n'est plus obligatoire d'ecrire les 4 caracteres lorsqu'il faut
entrer une valeur hexadecimale.
------------------------------------------------------------------------------
99/03/05 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Corrige un warning de compilation sous Solaris.
------------------------------------------------------------------------------
99/03/04 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Ca execute! (presque)
- Phase de corrections des bugs dans les instructions, une premiere
implementation est faite pour toutes les instructions.
- Ajout fonction "trace" et "dump internal memory"
- Les modes d'adressage sont pratiquement termines dans
les instructions.
- Certaines instructions ont un debut d'implementation.
- Desassembleur, bit addressable segment 00-7F -> 20.0-2F.7
------------------------------------------------------------------------------
99/03/03 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Ajout automatique de certaines lignes de codes concernant
l'adressage dans les fonctions d'instructions tres brouillon
- Ajout de stub pour write_mem et read_mem, modifs dans exec8051
- Ajout de la fonction showregister() et de la commande 'r'.
- Correction d'une erreur iram_mem doit etre unsigned char et non int
- Note : Il y a des references a certaines parties du 8052 mais
elles ne seront pas implementees. Ce n'est qu'a titre d'informations.
- Ajout de #define pour faire correspondre les registres SFR avec
leur adresse dans la iram.
- Renomme instructions.cpp a instructions.hpp et ajout du tableau
de pointeurs sur les fonctions
- Ajout de la ram interne 00-FF et valeurs initiale au reset
dans cpu8051.cpp avec le registre : unsigned int PC.
- Ajout de cpu8051.cpp contenant exec8051()
------------------------------------------------------------------------------
99/03/02 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Ajout de remarques dans le source
- Il faudrait maintenant tester avec plusieurs programmes pour
reperer les bugs.
- Le desassembleur reconnait maintenant les registres du SFR
(ex.: 88H est remplace par TCON, F0 par B, etc...)
- Changement au desassembleur (instructions peuvent avoir jusqu'a 3
arguments ex.: CJNE R0,#data,reladdr)
- La vrai instruction CJNE comporte 3 arguments il faut changer
radicalement le desassembleur
------------------------------------------------------------------------------
99/03/01 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Probleme dans opcodes.lst au niveau de l'instruction CJNE (mauvaise
definition)
- Tous les types d'adressages semblent fonctionner
- Le desassembleur peut lire les arguments et les afficher
(ex.: MOV A,#data peut devenir plus concret MOV A,#20)
- Desassembleur (instructions ont 2 arguments : instleftarg et
instrightarg)
------------------------------------------------------------------------------
99/02/28 Jonathan St-Andre <standr00@gel.ulaval.ca>
- Charge un fichier .hex donne en parametre (format Intel Hexadecimal
produit par ASM51)
- Effectue le dump program memory et dump data memory
- On peut quitter (YEAH!)
- Affiche le menu
- Creation de opcodes.lst et script Perl pour l'interpreter
- Debut

View File

@ -1,25 +1,57 @@
## Makefile.am -- Process this file with automake to produce Makefile.in
AUTOMAKE_OPTIONS = gnu
.PHONY: changelog
SUBDIRS = src doc
SUBDIRS = \
src/common \
src/cli \
src/gtk \
data \
doc \
tests
EXTRA_DIST = bootstrap \
$(ac_aux_dir)/debug.m4 \
$(ac_aux_dir)/gtk2.m4 \
pixmaps/*.xpm \
test_files/*
## We want these in the dist tarball
EXTRA_DIST = pixmaps
ACLOCAL = aclocal -I $(ac_aux_dir)
ACLOCAL_AMFLAGS = -I m4
LIBTOOL_MACROS = \
m4/libtool.m4 \
m4/ltoptions.m4 \
m4/ltsugar.m4 \
m4/ltversion.m4 \
m4/lt~obsolete.m4
CLEANFILES = *~
DISTCLEANFILES = .deps/*.P
MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure config-h.in stamp-h.in \
$(ac_aux_dir)/depcomp $(ac_aux_dir)/install-sh $(ac_aux_dir)/missing \
$(ac_aux_dir)/mkinstalldirs $(ac_aux_dir)/config.guess \
$(ac_aux_dir)/config.sub $(ac_aux_dir)/ltmain.sh
MAINTAINERCLEANFILES = \
Makefile.in \
aclocal.m4 \
configure \
config-h.in \
stamp-h.in \
ChangeLog \
$(ac_aux_dir)/depcomp \
$(ac_aux_dir)/install-sh \
$(ac_aux_dir)/missing \
$(ac_aux_dir)/mkinstalldirs \
$(ac_aux_dir)/config.guess \
$(ac_aux_dir)/config.sub \
$(ac_aux_dir)/ltmain.sh \
$(ac_aux_dir)/compile \
$(ac_aux_dir)/test-driver \
$(ac_aux_dir)/ar-lib \
$(ac_aux_dir)/ylwrap \
$(LIBTOOL_MACROS)
changelog:
@if test -d $(srcdir)/.git; then \
$(srcdir)/build-aux/gitlog-to-changelog \
--format='%s%n%n%b%n' \
--no-cluster \
--strip-tab \
--strip-cherry-pick \
>ChangeLog; \
fi

107
NEWS
View File

@ -0,0 +1,107 @@
2014-01-14: emu8051-2.0.1 has been released
Convert manpage to UTF-8
Do not display registers at CLI version startup
Dont exit application in case of hexfile reading failure
Fix C99 standard types uintN_t
Fix test script to work in external build directory
Add support for GNU readline (adds commands history).
Allow hex numbers to begin with 0x or $ prefix in CLI version
Allow to set all SFR registers in CLI version
Convert CLI version input parsing to Lex/Yacc
Remove address parameter from RUN and TRACE CLI commands
Add better error checking when loading invalid hex files
Allow EM command to be specified without arguments
Add two timers (independent of internal 8051 timers)
See the file 'ChangeLog' for further details.
2014-01-14: emu8051-2.0.0 has been released
Fix error with ADDC instruction: the carry flag was not added to the
result.
Fix bug when processing interrupts
Fix bug with timers mode 0 (8 bits with 5-bit prescaler)
Fix error with timer1 being written to timer0
Fix error with EM command in CLI mode
Add option to automatically run and stop CLI emulator for
regression testing
Add parity bit update each instruction cycle
Fix bug with MOV DPTR,#data16 instruction
Fix bugs with ORL and ANL instructions
Fix error with ADD instruction and AC bit
Fix error with JMP @A,DPTR instruction
Fix error with RETI instruction
Add Timers 0 and 1 to SFR window
Add option to specify memory sizes
Add live option to change windows layout (8 or 16 bytes width)
Add external memory window
Memory and register windows values can now be edited
Save paned positions and main window size to config file
Add support for saving UI settings to config file
Replace fixed frames with scrollable and resizable windows
Update code to compile with GTK3
See the file 'ChangeLog' for further details.
2013-09-07: emu8051-1.1.2 has been released
Fix error with CJNE instruction.
2011-12-11: emu8051-1.1.1 has been released (from emu8051-1.1.1-rc2).
2011-11-20: emu8051-1.1.1-rc2 has been released.
Added optional size parameter when dumping memory.
Created two separate executables, emu8051-cli (default)
and optional emu8051-gtk if Gtk+ is detected.
See the file 'ChangeLog' for further details.
2011-10-29: emu8051-1.1.1-rc1 has been released.
Fixed SJMP error and improved columns and rows sizing
2010-03-19: emu8051-1.1.0 has been released.
Reintroduced the console mode if no GTK+ librairies are
detected.
2009-02-09: emu8051-1.0.2 has been released.
Updated Free Software Foundation address.
2008-11-05: emu8051-1.0.1 has been released.
See the file 'ChangeLog' for further details.
2008-04-28: emu8051-1.0.0 has been released.
Removed gtk+-1.0 support, now requires gtk+-2
2005-05-07: emu8051-0.1.0 has been released.
Fixed bug with CJNE instruction and autoconf files cleanup.
See the file 'ChangeLog' for further details.

54
README
View File

@ -0,0 +1,54 @@
Emu8051
Emu8051 is a simulator/emulator for the Intel 8051 family of microcontrollers.
It is available in two versions: a console (text-only) version and a graphical
version (using the GTK+ toolkit). This is an Open-Source project. The program
can load Intel HEX files. Once loaded, a program can be run (it will run
indefinitely or until a breakpoint is encountered). You can also use the STEP
button to execute only a single instruction at a time and see the effects on
registers and memory. It is written in C, and uses Perl scripts to generate
automatically C functions corresponding to each assembly instruction of the
8051 microcontroller.
For recent project news, see the NEWS file.
Project website:
http://www.hugovil.com/en/emu8051
Installation:
For installation instructions, see the INSTALL file.
Regression testing:
Emu8051 now supports automatic regression tests. This feature is mainly for
developers who want to make sure that whatever features they implement or
whatever bug they fix don't create additional or new problems.
To support that feature, you must have a compatible 8051 assembler installed.
At the moment, these two assemblers are supported:
as504 -- http://www.vanwal.nl/as504
ASEM-51 -- http://plit.de/asem-51
I recommend to compile as504 with this patch to support option "-O":
http://www.hugovil.com/repository/hvlinux/patches/as504-add-output-file-option.patch
as504 doesn't come with an installation script so compile and install it with:
$> make
$> sudo install as504 /usr/local/bin
Then reconfigure emu8051 so that as504 can be detected and regression testing
enabled.
You can run regression testing by issuing:
$> make check
Adding a new test case implies adding a new asm source file inside the tests
subdirectory and adding its name to two variables in tests/Makefile.am.
This program was tested on the following systems:
"Linux From Scratch 4.0"

0
THANKS Normal file
View File

29
TODO
View File

@ -1,15 +1,16 @@
THINGS TO DO
------------
TODO
----
-Compile only one program for both graphical and console modes, or
support only the graphical mode.
- Some fine tuning around the classes
- Make MemWin, RegWin be able to make a standalone
window if parentwin=0.
- Connect File->Open, View->... and Help->License menus.
- Make the RegWin and MemWin react when mouse clicked. (modify register or
memory)
- Enlever les fonctions ReadI, WriteI, dumpI etc... et plutot utiliser les
fonctions ReadInt, WriteInt, DumpInt, DumpExt, etc.
- Lors d'un DumpInt, verifier a ne pas afficher plus haut que la taille
reelle de la memoire interne. (Detail)
-Add visual indication when emulated program is running
-Gtk tree view: Switch from G_TYPE_STRING to G_TYPE_UINT for numbers, and
create custom renderer to display as hex numbers.
-Compile only one program for both graphical and console modes.
-Add new breakpoint menu:
->show breakpoints
->remove all breakpoints
-Create config menu:
-> Do not reset emulator on hex file load enable/disable

View File

@ -1,28 +1,9 @@
#!/bin/sh
# bootstrap -- Use this script to create generated files from the CVS dist
# Copyright (C) 2000 Gary V. Vaughan
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# autogen.sh -- Use this script to create generated files from the git distribution
## @start 1
#! /bin/sh
# ChangeLog is generated from git log output using "make changelog"
touch ChangeLog
set -x
aclocal -I config
##libtoolize --force --copy
autoheader
automake --add-missing --copy
autoconf
## @end 1
set -e
autoreconf -vi
rm -rf autom4te.cache

9
build-aux/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
compile
config.guess
config.rpath
config.sub
depcomp
install-sh
missing
test-driver
ar-lib

432
build-aux/gitlog-to-changelog Executable file
View File

@ -0,0 +1,432 @@
eval '(exit $?0)' && eval 'exec perl -wS "$0" ${1+"$@"}'
& eval 'exec perl -wS "$0" $argv:q'
if 0;
# Convert git log output to ChangeLog format.
my $VERSION = '2014-01-15 03:30'; # UTC
# The definition above must lie within the first 8 lines in order
# for the Emacs time-stamp write hook (at end) to update it.
# If you change this file with Emacs, please let the write hook
# do its job. Otherwise, update this string manually.
# Copyright (C) 2008-2014 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Written by Jim Meyering
use strict;
use warnings;
use Getopt::Long;
use POSIX qw(strftime);
(my $ME = $0) =~ s|.*/||;
# use File::Coda; # http://meyering.net/code/Coda/
END {
defined fileno STDOUT or return;
close STDOUT and return;
warn "$ME: failed to close standard output: $!\n";
$? ||= 1;
}
sub usage ($)
{
my ($exit_code) = @_;
my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR);
if ($exit_code != 0)
{
print $STREAM "Try '$ME --help' for more information.\n";
}
else
{
print $STREAM <<EOF;
Usage: $ME [OPTIONS] [ARGS]
Convert git log output to ChangeLog format. If present, any ARGS
are passed to "git log". To avoid ARGS being parsed as options to
$ME, they may be preceded by '--'.
OPTIONS:
--amend=FILE FILE maps from an SHA1 to perl code (i.e., s/old/new/) that
makes a change to SHA1's commit log text or metadata.
--append-dot append a dot to the first line of each commit message if
there is no other punctuation or blank at the end.
--no-cluster never cluster commit messages under the same date/author
header; the default is to cluster adjacent commit messages
if their headers are the same and neither commit message
contains multiple paragraphs.
--srcdir=DIR the root of the source tree, from which the .git/
directory can be derived.
--since=DATE convert only the logs since DATE;
the default is to convert all log entries.
--format=FMT set format string for commit subject and body;
see 'man git-log' for the list of format metacharacters;
the default is '%s%n%b%n'
--strip-tab remove one additional leading TAB from commit message lines.
--strip-cherry-pick remove data inserted by "git cherry-pick";
this includes the "cherry picked from commit ..." line,
and the possible final "Conflicts:" paragraph.
--help display this help and exit
--version output version information and exit
EXAMPLE:
$ME --since=2008-01-01 > ChangeLog
$ME -- -n 5 foo > last-5-commits-to-branch-foo
SPECIAL SYNTAX:
The following types of strings are interpreted specially when they appear
at the beginning of a log message line. They are not copied to the output.
Copyright-paperwork-exempt: Yes
Append the "(tiny change)" notation to the usual "date name email"
ChangeLog header to mark a change that does not require a copyright
assignment.
Co-authored-by: Joe User <user\@example.com>
List the specified name and email address on a second
ChangeLog header, denoting a co-author.
Signed-off-by: Joe User <user\@example.com>
These lines are simply elided.
In a FILE specified via --amend, comment lines (starting with "#") are ignored.
FILE must consist of <SHA,CODE+> pairs where SHA is a 40-byte SHA1 (alone on
a line) referring to a commit in the current project, and CODE refers to one
or more consecutive lines of Perl code. Pairs must be separated by one or
more blank line.
Here is sample input for use with --amend=FILE, from coreutils:
3a169f4c5d9159283548178668d2fae6fced3030
# fix typo in title:
s/all tile types/all file types/
1379ed974f1fa39b12e2ffab18b3f7a607082202
# Due to a bug in vc-dwim, I mis-attributed a patch by Paul to myself.
# Change the author to be Paul. Note the escaped "@":
s,Jim .*>,Paul Eggert <eggert\\\@cs.ucla.edu>,
EOF
}
exit $exit_code;
}
# If the string $S is a well-behaved file name, simply return it.
# If it contains white space, quotes, etc., quote it, and return the new string.
sub shell_quote($)
{
my ($s) = @_;
if ($s =~ m![^\w+/.,-]!)
{
# Convert each single quote to '\''
$s =~ s/\'/\'\\\'\'/g;
# Then single quote the string.
$s = "'$s'";
}
return $s;
}
sub quoted_cmd(@)
{
return join (' ', map {shell_quote $_} @_);
}
# Parse file F.
# Comment lines (starting with "#") are ignored.
# F must consist of <SHA,CODE+> pairs where SHA is a 40-byte SHA1
# (alone on a line) referring to a commit in the current project, and
# CODE refers to one or more consecutive lines of Perl code.
# Pairs must be separated by one or more blank line.
sub parse_amend_file($)
{
my ($f) = @_;
open F, '<', $f
or die "$ME: $f: failed to open for reading: $!\n";
my $fail;
my $h = {};
my $in_code = 0;
my $sha;
while (defined (my $line = <F>))
{
$line =~ /^\#/
and next;
chomp $line;
$line eq ''
and $in_code = 0, next;
if (!$in_code)
{
$line =~ /^([0-9a-fA-F]{40})$/
or (warn "$ME: $f:$.: invalid line; expected an SHA1\n"),
$fail = 1, next;
$sha = lc $1;
$in_code = 1;
exists $h->{$sha}
and (warn "$ME: $f:$.: duplicate SHA1\n"),
$fail = 1, next;
}
else
{
$h->{$sha} ||= '';
$h->{$sha} .= "$line\n";
}
}
close F;
$fail
and exit 1;
return $h;
}
# git_dir_option $SRCDIR
#
# From $SRCDIR, the --git-dir option to pass to git (none if $SRCDIR
# is undef). Return as a list (0 or 1 element).
sub git_dir_option($)
{
my ($srcdir) = @_;
my @res = ();
if (defined $srcdir)
{
my $qdir = shell_quote $srcdir;
my $cmd = "cd $qdir && git rev-parse --show-toplevel";
my $qcmd = shell_quote $cmd;
my $git_dir = qx($cmd);
defined $git_dir
or die "$ME: cannot run $qcmd: $!\n";
$? == 0
or die "$ME: $qcmd had unexpected exit code or signal ($?)\n";
chomp $git_dir;
push @res, "--git-dir=$git_dir/.git";
}
@res;
}
{
my $since_date;
my $format_string = '%s%n%b%n';
my $amend_file;
my $append_dot = 0;
my $cluster = 1;
my $strip_tab = 0;
my $strip_cherry_pick = 0;
my $srcdir;
GetOptions
(
help => sub { usage 0 },
version => sub { print "$ME version $VERSION\n"; exit },
'since=s' => \$since_date,
'format=s' => \$format_string,
'amend=s' => \$amend_file,
'append-dot' => \$append_dot,
'cluster!' => \$cluster,
'strip-tab' => \$strip_tab,
'strip-cherry-pick' => \$strip_cherry_pick,
'srcdir=s' => \$srcdir,
) or usage 1;
defined $since_date
and unshift @ARGV, "--since=$since_date";
# This is a hash that maps an SHA1 to perl code (i.e., s/old/new/)
# that makes a correction in the log or attribution of that commit.
my $amend_code = defined $amend_file ? parse_amend_file $amend_file : {};
my @cmd = ('git',
git_dir_option $srcdir,
qw(log --log-size),
'--pretty=format:%H:%ct %an <%ae>%n%n'.$format_string, @ARGV);
open PIPE, '-|', @cmd
or die ("$ME: failed to run '". quoted_cmd (@cmd) ."': $!\n"
. "(Is your Git too old? Version 1.5.1 or later is required.)\n");
my $prev_multi_paragraph;
my $prev_date_line = '';
my @prev_coauthors = ();
while (1)
{
defined (my $in = <PIPE>)
or last;
$in =~ /^log size (\d+)$/
or die "$ME:$.: Invalid line (expected log size):\n$in";
my $log_nbytes = $1;
my $log;
my $n_read = read PIPE, $log, $log_nbytes;
$n_read == $log_nbytes
or die "$ME:$.: unexpected EOF\n";
# Extract leading hash.
my ($sha, $rest) = split ':', $log, 2;
defined $sha
or die "$ME:$.: malformed log entry\n";
$sha =~ /^[0-9a-fA-F]{40}$/
or die "$ME:$.: invalid SHA1: $sha\n";
# If this commit's log requires any transformation, do it now.
my $code = $amend_code->{$sha};
if (defined $code)
{
eval 'use Safe';
my $s = new Safe;
# Put the unpreprocessed entry into "$_".
$_ = $rest;
# Let $code operate on it, safely.
my $r = $s->reval("$code")
or die "$ME:$.:$sha: failed to eval \"$code\":\n$@\n";
# Note that we've used this entry.
delete $amend_code->{$sha};
# Update $rest upon success.
$rest = $_;
}
# Remove lines inserted by "git cherry-pick".
if ($strip_cherry_pick)
{
$rest =~ s/^\s*Conflicts:\n.*//sm;
$rest =~ s/^\s*\(cherry picked from commit [\da-f]+\)\n//m;
}
my @line = split "\n", $rest;
my $author_line = shift @line;
defined $author_line
or die "$ME:$.: unexpected EOF\n";
$author_line =~ /^(\d+) (.*>)$/
or die "$ME:$.: Invalid line "
. "(expected date/author/email):\n$author_line\n";
# Format 'Copyright-paperwork-exempt: Yes' as a standard ChangeLog
# `(tiny change)' annotation.
my $tiny = (grep (/^Copyright-paperwork-exempt:\s+[Yy]es$/, @line)
? ' (tiny change)' : '');
my $date_line = sprintf "%s %s$tiny\n",
strftime ("%F", localtime ($1)), $2;
my @coauthors = grep /^Co-authored-by:.*$/, @line;
# Omit meta-data lines we've already interpreted.
@line = grep !/^(?:Signed-off-by:[ ].*>$
|Co-authored-by:[ ]
|Copyright-paperwork-exempt:[ ]
)/x, @line;
# Remove leading and trailing blank lines.
if (@line)
{
while ($line[0] =~ /^\s*$/) { shift @line; }
while ($line[$#line] =~ /^\s*$/) { pop @line; }
}
# Record whether there are two or more paragraphs.
my $multi_paragraph = grep /^\s*$/, @line;
# Format 'Co-authored-by: A U Thor <email@example.com>' lines in
# standard multi-author ChangeLog format.
for (@coauthors)
{
s/^Co-authored-by:\s*/\t /;
s/\s*</ </;
/<.*?@.*\..*>/
or warn "$ME: warning: missing email address for "
. substr ($_, 5) . "\n";
}
# If clustering of commit messages has been disabled, if this header
# would be different from the previous date/name/email/coauthors header,
# or if this or the previous entry consists of two or more paragraphs,
# then print the header.
if ( ! $cluster
|| $date_line ne $prev_date_line
|| "@coauthors" ne "@prev_coauthors"
|| $multi_paragraph
|| $prev_multi_paragraph)
{
$prev_date_line eq ''
or print "\n";
print $date_line;
@coauthors
and print join ("\n", @coauthors), "\n";
}
$prev_date_line = $date_line;
@prev_coauthors = @coauthors;
$prev_multi_paragraph = $multi_paragraph;
# If there were any lines
if (@line == 0)
{
warn "$ME: warning: empty commit message:\n $date_line\n";
}
else
{
if ($append_dot)
{
# If the first line of the message has enough room, then
if (length $line[0] < 72)
{
# append a dot if there is no other punctuation or blank
# at the end.
$line[0] =~ /[[:punct:]\s]$/
or $line[0] .= '.';
}
}
# Remove one additional leading TAB from each line.
$strip_tab
and map { s/^\t// } @line;
# Prefix each non-empty line with a TAB.
@line = map { length $_ ? "\t$_" : '' } @line;
print "\n", join ("\n", @line), "\n";
}
defined ($in = <PIPE>)
or last;
$in ne "\n"
and die "$ME:$.: unexpected line:\n$in";
}
close PIPE
or die "$ME: error closing pipe from " . quoted_cmd (@cmd) . "\n";
# FIXME-someday: include $PROCESS_STATUS in the diagnostic
# Complain about any unused entry in the --amend=F specified file.
my $fail = 0;
foreach my $sha (keys %$amend_code)
{
warn "$ME:$amend_file: unused entry: $sha\n";
$fail = 1;
}
exit $fail;
}
# Local Variables:
# mode: perl
# indent-tabs-mode: nil
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "my $VERSION = '"
# time-stamp-format: "%:y-%02m-%02d %02H:%02M"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "'; # UTC"
# End:

View File

@ -1,18 +0,0 @@
dnl
dnl Macro for adding an option to 'configure' for enabling debugging messages
dnl
AC_DEFUN([HV_CHECK_FOR_DEBUG],[
AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
[enable debugging messages on console
(default is NO)]),[
if test x"${enableval}" = xyes; then
debug_messages=1
AC_DEFINE([DEBUG],1,[Set to 1 to enable debugging messages.])
elif test x"${enableval}" = xno; then
debug_messages=0
else
AC_MSG_ERROR(bad value for --enable-debug option)
fi
], debug_messages=0 )
])

View File

@ -1,17 +0,0 @@
dnl
dnl Macro for adding an option to 'configure' for choosing GTK+-2 instead of the
dnl GTK+-1 default
dnl
AC_DEFUN([HV_CHECK_FOR_GTK2],[dnl
AC_ARG_WITH(gtk2, AC_HELP_STRING([--with-gtk2], [use GTK2 (default is GTK1)]),[dnl
if test x"${withval}" = xyes; then
use_gtk2=1
AC_DEFINE([USE_GTK2],1,[Set to 1 to use the Gtk+-2 library.])
elif test x"${withval}" = xno; then
use_gtk2=0
else
AC_MSG_ERROR(bad value for --with-gtk2 option)
fi
], use_gtk2=0 )
])

137
configure.ac Normal file
View File

@ -0,0 +1,137 @@
# configure.ac -- Process this file with autoconf to produce configure
dnl Initialization stuff.
AC_INIT([emu8051], [2.0.1], [hugo@hugovil.com], [emu8051],
[http://www.hugovil.com/emu8051/])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR(src/common/cpu8051.c)
dnl -Wno-extra-portability:
dnl To get rid of message:
dnl linking libraries using a non-POSIX archiver requires 'AM_PROG_AR'...
dnl -Wall:
dnl Ask automake to turn on all warnings (not a gcc flag)
AM_INIT_AUTOMAKE([no-define gnits dist-bzip2 color-tests
-Wall -Wno-extra-portability])
AM_SILENT_RULES([yes])
AM_CONFIG_HEADER(config.h:config-h.in)
dnl Testing the C compiler.
AC_LANG_C
dnl Testing for libtool support.
AM_PROG_LIBTOOL
AC_ARG_WITH([readline],
[AS_HELP_STRING([--without-readline], [disable support for readline])],
[],
[with_readline=yes])
LIBREADLINE=
AS_IF([test "x$with_readline" != xno],
[AC_CHECK_LIB([readline], [main],
[AC_SUBST([LIBREADLINE], ["-lreadline"])
AC_DEFINE([HAVE_LIBREADLINE], [1],
[Define if you have libreadline])
],
[AC_MSG_FAILURE(
[readline test failed (--without-readline to disable)])],
[]
)])
dnl Testing for Lex/Yacc
AM_PROG_LEX
AC_PROG_YACC
dnl Checking for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_PID_T
AC_TYPE_SIZE_T
dnl Basic warning CFLAGS values
WARNINGCFLAGS="-Wall -Wextra -Wformat -Wformat-security"
PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.26.0])
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
dnl Checks for Gtk+-2.0
AC_ARG_ENABLE(gui,
[ --enable-gui Enable building the GUI (default=yes)],
[ac_cv_enable_gui=$enableval], [ac_cv_enable_gui=yes])
AC_MSG_CHECKING([whether to build GUI])
if test x$ac_cv_enable_gui = xyes; then
AC_MSG_RESULT(yes)
PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.4.0, [], dnl
ac_cv_enable_gui=no)
if test x$ac_cv_enable_gui = xyes; then
AC_DEFINE([HAVE_GTK],1,[Set to 1 to enable GTK+ support for building GUI.])
GTK_CFLAGS="${GTK_CFLAGS} -DGDK_PIXBUF_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED"
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)
fi
else
AC_MSG_RESULT(no)
fi
AM_CONDITIONAL([USE_GTK], [test x${ac_cv_enable_gui} = xyes])
dnl Try to locate valid 8051 assembler to generate test files (.hex)
run_tests=no
AC_CHECK_PROG(AS504_CHECK,as504,yes)
if test x"$AS504_CHECK" = x"yes" ; then
run_tests=yes
dnl Check if as504 has been patched to support option -O:
dnl See http://www.hugovil.com/repository/hvlinux/patches/as504-add-output-file-option.patch
AS504HV_CHECK=no
if as504 2>&1 | grep -q Ooutfile; then
AS504HV_CHECK=yes
fi
fi
AC_CHECK_PROG(ASEM51_CHECK,asem,yes)
if test x"$ASEM51_CHECK" = x"yes" ; then
run_tests=yes
fi
if test x"$run_tests" != x"yes" ; then
AC_MSG_WARN([Please install as504 (http://www.vanwal.nl/as504/) or ASEM-51 (http://plit.de/asem-51) to run test suite.])
fi
AM_CONDITIONAL([RUN_TESTS],[test x"$run_tests" = x"yes"])
AM_CONDITIONAL([USE_AS504HV],[test x"$AS504HV_CHECK" = x"yes"])
AM_CONDITIONAL([USE_AS504],[test x"$AS504_CHECK" = x"yes"])
AM_CONDITIONAL([USE_AS51],[test x"$ASEM51_CHECK" = x"yes"])
dnl zlib required for its crc32 function
ac_have_zlib=no
PKG_CHECK_MODULES([zlib], [zlib > 1.2.1],
[AC_CHECK_LIB([z], [crc32],
[ac_have_zlib=yes],
[ac_have_zlib=no])])
if test x"$ac_have_zlib" = x"yes" ; then
ZLIB_LIBS='-lz'
AC_SUBST(ZLIB_LIBS)
else
AC_MSG_ERROR([Please install zlib and zlib-devel packages])
fi
AC_SUBST(WARNINGCFLAGS)
AC_SUBST(ac_aux_dir)
dnl Creating output file(s)
AC_OUTPUT(Makefile
src/common/Makefile
src/cli/Makefile
src/gtk/Makefile
data/Makefile
doc/Makefile
tests/Makefile)

View File

@ -1,89 +0,0 @@
# configure.in -- Process this file with autoconf to produce configure
dnl Initialization stuff.
AC_INIT(emu8051, 0.1.0)
AC_CONFIG_AUX_DIR(config)
AC_CONFIG_SRCDIR(src/CPU8051.cpp)
AM_CONFIG_HEADER(config.h:config-h.in)
dnl Checking if the NEWS file has been updated to reflect the current version.
AM_INIT_AUTOMAKE(check-news)
dnl Tests the C compiler
AC_PROG_CC
AC_LANG_C
dnl Checking for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(strings.h unistd.h)
dnl Checking for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_PID_T
AC_TYPE_SIZE_T
dnl Basic CFLAGS values
CFLAGS="-Wall"
dnl Checks for '--enable-debug' option
HV_CHECK_FOR_DEBUG
if test x"${debug_messages}" = x1; then
dnl -g is for GDB debugging
CFLAGS="${CFLAGS} -g -gdwarf-2 -g3"
fi
dnl Checks for '--with-gtk2' option
HV_CHECK_FOR_GTK2
if test x"${use_gtk2}" = x0; then
dnl Checks for Gtk+-1.2.0
AM_PATH_GTK(1.2.0, CFLAGS="${CFLAGS} ${GTK_CFLAGS}" LIBS="${LIBS} ${GTK_LIBS}",
AC_MSG_ERROR(GTK+ not found!))dnl
else
dnl Checks for Gtk+-2.0
PKG_CHECK_MODULES(GTK,gtk+-2.0 >= 2.0.5, CFLAGS="${CFLAGS} ${GTK_CFLAGS}" \
LIBS="${LIBS} ${GTK_LIBS}",AC_MSG_ERROR(GTK+-2.0 not found!))dnl
fi
dnl Tests the C++ compiler
AC_PROG_CXX
AC_LANG_CPLUSPLUS
CXXFLAGS="${CFLAGS}"
AC_SUBST(CFLAGS)
AC_SUBST(CXXFLAGS)
AC_SUBST(LIBS)
AC_SUBST(ac_aux_dir)
dnl Creating output file(s)
AC_OUTPUT(Makefile src/Makefile doc/Makefile)
echo \
"---------------------------------------------------------------------------
Configuration:
Install path: ${prefix}
Compiler: ${CC}
Compiler flags: ${CFLAGS}
Linker flags: ${LIBS}"
echo -n " GTK base version: "
if test x"${use_gtk2}" = x1; then
echo "2"
else
echo "1"
fi
echo -n " Debugging messages: "
if test x"${debug_messages}" = x1; then
echo "yes"
else
echo "no"
fi
echo \
"
See config.h for further configuration information.
---------------------------------------------------------------------------"

11
data/Makefile.am Normal file
View File

@ -0,0 +1,11 @@
defconfdir=$(sysconfdir)/xdg/emu8051/default
defconf_DATA = \
emu8051.conf
EXTRA_DIST= \
$(defconf_DATA)
CLEANFILES = *~
MAINTAINERCLEANFILES = Makefile.in

9
data/emu8051.conf Normal file
View File

@ -0,0 +1,9 @@
[emulation]
clear_ram_on_file_load=false
[ui]
win_width=500
win_height=300
hpane_pos=100
vpane_pos=200

View File

@ -1,123 +1,33 @@
.TH WMNOTIFY 1 "March 2003" "wmnotify" "User's Manual"
.TH EMU8051 1 "May 2004" "emu8051" "User's Manual"
.SH NAME
wmnotify \- Dockable E-mail notification program for single POP3 account
emu8051 \- Simulator/emulator for the Intel 8051 family of microcontrollers
.SH SYNOPSIS
.B wmnotify
[\fIOPTION\fR]...
.B emu8051
[\fIOPTION\fR]... [\fIFILENAME\fR]
.SH DESCRIPTION
\fBwmnotify\fR is a dockable application (DockApp) for the WindowMaker window
manager to periodically check a POP3 E-mail account for new messages. If there
are new messages in the mailbox, a simple animation is started to notify the
user. An optional beep or sound can also be produced if desired.
\fBemu8051\fR is a simulator/emulator for the Intel 8051 family of microcontrollers. It is available in two versions: a console (text-only) version and a graphical version (using the GTK+ toolkit). This is an Open-Source project. The program can load Intel HEX files.
The interface is kept very simple. To immediately check for new messages,
single-click on the mailbox image. To start your favorite email program,
double-click on the mailbox image.
Once loaded, a program can be run (it will run indefinitely or until a breakpoint is encountered). You can also use the STEP button to execute only a single instruction at a time and see the effects on registers and memory.
When you double-click on the mailbox image to start your email program,
the new messages animation is stopped, assuming that you will read your new
messages. If you don't, the wmnotify program will simply continue it's
periodic checking of your email account and will restart the new messages
animation after the usual delay if new messages are unread.
By default, the interval between checks is 1 minute, and this can be changed in
the configuration file. You can also enable audio notification as well as
specify an optional audio sound file (WAV or AU). If audio notification is
enabled but no audio sound file is specified, a beep will be produced. There is
an option in the configuration file to adjust the volume of the sound file.
It is written in C++, and uses Perl scripts to generate automatically C++ functions corresponding to each assembly instruction of the 8051 microcontroller.
.SH "OPTIONS"
.TP
.BI "\-\^c " config-file
.B wmnotify
reads your POP3 account settings and preferences from the specified
configuration file. This option overrides the use of the default config file,
.IR "$HOME/.wmnotifyrc".
.TP
.BI \-display " host" : display
Specifies the host and screen to be used by \fBwmnotify\fR. By default this
is obtained from the environment variable
.SB DISPLAY.
.TP
.BI \-geometry " geometry"
.RB ( *geometry )
Specifies the initial geometry of the window.
.TP
\fB\-h\fR
display usage and exit
.TP
\fB\-v\fR
\fB\-version\fR
output version information and exit
.SH "CONFIGURATION FILE"
.IR $HOME/.wmnotifyrc
The first time the program is run, it will check for the presence of the
configuration file in the user's home directory. If this file is not found,
wmnotify will automatically create a new one, and exit. Then the user must
enter it's POP3 account settings and preferences in the configuration file
before restarting wmnotify.
.TP
.BI "server " <pop3-servername>
POP3 server name.
.TP
.BI "port " <pop3-portnumber>
POP3 port number (optional, default value is 110).
.TP
.BI "username " <pop3-username>
POP3 username.
.TP
.BI "password " <pop3-password>
POP3 password.
.TP
.BI "mailcheckdelay " <delay-in-minutes>
Mail check interval, in minutes (optional, default value is 1).
.TP
.BI "mailclient " <program>
The program to start when double-clicking on the mailbox image (optional).
.TP
.BI "enablebeep " <value>
This option controls the audio notification enabling/disabling. If this option
is enabled and the "audiofile" option below contains a valid audio file, it
will be played whenever new message(s) are detected. If "audiofile" is
commented, the console beep will be used to produce the audio notification. The
value may be set to "0" to disable or to "1" to enable (optional, default value is 0, disabled).
.TP
.BI "audiofile " <path-to-audiofile>
Path and filename of the WAV or AU audio sound file to play when new message(s)
are detected (optional).
.TP
.BI "volume " <value>
Volume value, in percent, when playing an audio file (optional, default value is
100%). This volume value is relative to the values you have set in your sound
card mixer settings. If you find the audio notification sound to be too loud,
just reduce the volume value. On the other hand, if you want to increase the
audio notification sound amplitude, just increase the volume. If you increase
the volume value to 100% and you find that it is not sufficient, then you would
have to increase the volume using your favorite sound card mixer program
(ex: with alsamixer, increase the PCM or master value).
.SH CREDITS
\fBwmnotify\fR was written by Hugo Villeneuve <hugovil@videotron.ca>, based on
the WMPop3 program by Scott Holden <scotth@thezone.net>.
\fBemu8051\fR was originally written by Jonathan St-André, Hugo Villeneuve <hugo@hugovil.com> and Pascal Fecteau.
.SH COPYRIGHT
\fBwmnotify\fR is free; anyone may redistribute it to anyone under the terms
\fBemu8051\fR is free; anyone may redistribute it to anyone under the terms
stated in the GNU General Public License. A copy of the license is included in
the \fBwmnotify\fR distribution. You can also browse it online at
the \fBemu8051\fR distribution. You can also browse it online at
.I http://www.gnu.org/copyleft/gpl.html

0
m4/.gitignore vendored Normal file
View File

View File

@ -1,644 +0,0 @@
// CPU8051.cpp
#include <stdio.h>
#include <iostream>
#include "CPU8051.hpp"
#include "disasm.hpp"
//////////////////////////////////////////////////////////////////////////////
// CPU8051::CPU8051( )
// CPU8051 constructor
//////////////////////////////////////////////////////////////////////////////
CPU8051::CPU8051( )
{
InitFuncPtr( );
// Cree les objets Memory
SFRMem = new Memory( 128 );
PGMMem = new Memory( 65536 );
IntMem = new Memory( 128 );
ExtMem = new Memory( 65536 );
PC = 0; CLOCK = 0; ActivePriority = -1;
}
//////////////////////////////////////////////////////////////////////////////
// CPU8051::~CPU8051( )
// CPU8051 destructor
//////////////////////////////////////////////////////////////////////////////
CPU8051::~CPU8051( )
{
// Detruit les objets Memory
delete SFRMem;
delete PGMMem;
delete IntMem;
delete ExtMem;
SFRMem = 0;
PGMMem = 0;
IntMem = 0;
ExtMem = 0;
PC = 0;
CLOCK = 0;
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::Exec( )
// Execute at address PC from PGMMem
//////////////////////////////////////////////////////////////////////////////
void CPU8051::Exec( )
{
int i;
unsigned char opcode = PGMMem->Read8( PC++ );
int insttiming = ( this->*funcptr[ opcode ] )();
for ( i = 0; i < insttiming; i++)
{
CheckInterrupts();
DoTimers();
CLOCK++;
}
}
//////////////////////////////////////////////////////////////////////////////
// unsigned int CPU8051::GetNextAddress( )
// Return PC + size in bytes of current instruction
//////////////////////////////////////////////////////////////////////////////
unsigned int CPU8051::GetNextAddress( )
{
return ( PC + InstSizesTbl[ PGMMem->Read8( PC ) ] );
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::Reset( )
// Reset the registers and CPU state
//////////////////////////////////////////////////////////////////////////////
void CPU8051::Reset( )
{
PC = 0; CLOCK = 0; ActivePriority = -1;
// Reinitialisation des registres
int i;
for ( i = 0; i < 128; i++ )
{
SFRMem->Write8( i, 0 );
IntMem->Write8( i, 0 );
}
SFRMem->Write8( _P0_ - 0x80, 0xFF );
SFRMem->Write8( _P1_ - 0x80, 0xFF );
SFRMem->Write8( _P2_ - 0x80, 0xFF );
SFRMem->Write8( _P3_ - 0x80, 0xFF );
SFRMem->Write8( _SP_ - 0x80, 0x07 );
}
//////////////////////////////////////////////////////////////////////////////
// unsigned int CPU8051::GetPC( )
// Return the value of PC register
//////////////////////////////////////////////////////////////////////////////
unsigned int CPU8051::GetPC( )
{
return PC;
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::SetPC( unsigned int NewPC )
// Set the new value of PC register
//////////////////////////////////////////////////////////////////////////////
void CPU8051::SetPC( unsigned int NewPC )
{
PC = NewPC;
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::WriteD( unsigned int Address, unsigned char Value )
// Write with a direct addressing mode at Address the new Value
//////////////////////////////////////////////////////////////////////////////
void CPU8051::WriteD( unsigned int Address, unsigned char Value )
{
if ( Address > 0x7F ) { SFRMem->Write8( Address - 0x80, Value ); return; }
IntMem->Write8( Address, Value );
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::WriteExt( unsigned int Address, unsigned char Value )
// Ecriture d'une valeur dans la memoire externe ( Address = $00 a $FFFF )
//////////////////////////////////////////////////////////////////////////////
void CPU8051::WriteExt( unsigned int Address, unsigned char Value )
{
ExtMem->Write8( Address, Value );
return;
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::WriteInt( unsigned int Address, unsigned char Value )
// Ecriture d'une valeur dans la memoire interne ( Address = $00 a $FF )
//////////////////////////////////////////////////////////////////////////////
void CPU8051::WriteInt( unsigned int Address, unsigned char Value )
{
if ( Address > 0x7F )
SFRMem->Write8( Address - 0x80, Value );
else
IntMem->Write8( Address, Value );
return;
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::WriteI( unsigned int Address, unsigned char Value )
// Write with an indirect addressing mode at Address the new Value
//////////////////////////////////////////////////////////////////////////////
void CPU8051::WriteI( unsigned int Address, unsigned char Value )
{
if ( Address > 0x7F ) { ExtMem->Write8( Address, Value ); return; }
IntMem->Write8( Address, Value );
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::WritePGM( unsigned int Address, unsigned char Value )
// Write at Address the new Value in PGMMem
//////////////////////////////////////////////////////////////////////////////
void CPU8051::WritePGM( unsigned int Address, unsigned char Value )
{
PGMMem->Write8( Address, Value );
}
//////////////////////////////////////////////////////////////////////////////
// unsigned char CPU8051::ReadD( unsigned int Address )
// Read with a direct addressing mode at Address
//////////////////////////////////////////////////////////////////////////////
unsigned char CPU8051::ReadD( unsigned int Address )
{
if ( Address > 0xFF ) return ExtMem->Read8( Address );
if ( Address > 0x7F ) return SFRMem->Read8( Address - 0x80 );
return IntMem->Read8( Address );
}
//////////////////////////////////////////////////////////////////////////////
// unsigned char CPU8051::ReadInt( unsigned int Address )
// Read Internal data memory at Address
//////////////////////////////////////////////////////////////////////////////
unsigned char CPU8051::ReadInt( unsigned int Address )
{
if ( Address > 0x7F )
return SFRMem->Read8( Address - 0x80 );
return IntMem->Read8( Address );
}
//////////////////////////////////////////////////////////////////////////////
// unsigned char CPU8051::ReadExt( unsigned int Address )
// Lecture du contenu de la memoire externe
//////////////////////////////////////////////////////////////////////////////
unsigned char CPU8051::ReadExt( unsigned int Address )
{
return ExtMem->Read8( Address );
}
//////////////////////////////////////////////////////////////////////////////
// unsigned char CPU8051::ReadI( unsigned int Address )
// Read with a indirect addressing mode at Address
//////////////////////////////////////////////////////////////////////////////
unsigned char CPU8051::ReadI( unsigned int Address )
{
if ( Address > 0x7F ) return ExtMem->Read8( Address );
return IntMem->Read8( Address );
}
//////////////////////////////////////////////////////////////////////////////
// unsigned char CPU8051::ReadPGM( unsigned int Address )
// Read at Address from PGMMem
//////////////////////////////////////////////////////////////////////////////
unsigned char CPU8051::ReadPGM( unsigned int Address )
{
return PGMMem->Read8( Address );
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::WriteB( unsigned int BitAddress, unsigned char Value )
// Write with a bit addressing mode at BitAddress the new Value
//////////////////////////////////////////////////////////////////////////////
void CPU8051::WriteB( unsigned int BitAddress, unsigned char Value )
{
unsigned int ByteAddress, BitNumber;
unsigned char ByteValue, ByteMask;
if ( BitAddress > 0x7F ) {
// SFR 80-FF
ByteAddress = BitAddress & 0xF8;
BitNumber = BitAddress & 0x07;
}
else {
// 20-2F
ByteAddress = ( BitAddress >> 3 ) + 0x20;
BitNumber = BitAddress & 0x07;
}
ByteMask = ( ( 1 << BitNumber ) ^ 0xFF );
ByteValue = ReadD( ByteAddress ) & ByteMask;
ByteValue += Value << BitNumber;
WriteD( ByteAddress, ByteValue );
}
//////////////////////////////////////////////////////////////////////////////
// unsigned char CPU8051::ReadB( unsigned int BitAddress )
// Read with a bit addressing mode at BitAddress
//////////////////////////////////////////////////////////////////////////////
unsigned char CPU8051::ReadB( unsigned int BitAddress )
{
unsigned int ByteAddress, BitNumber;
unsigned char BitValue;
if ( BitAddress > 0x7F ) {
// SFR 80-FF
ByteAddress = BitAddress & 0xF8;
BitNumber = BitAddress & 0x07;
}
else {
// 20-2F
ByteAddress = ( BitAddress >> 3 ) + 0x20;
BitNumber = BitAddress & 0x07;
}
BitValue = ( ReadD( ByteAddress ) >> BitNumber );
BitValue &= 1;
return BitValue;
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::CheckInterrupts()
// Check interrupts state and process them as needed
//////////////////////////////////////////////////////////////////////////////
void CPU8051::CheckInterrupts()
{
unsigned char SP;
if ( ReadD( _IE_ ) & 0x80 ) {
for ( int i = 1; i >= 0; i-- )
if ( ActivePriority < i ) {
//------------------------- External interrupt 0 ----------------------------
// if ( ( ReadD( _IE_ ) & 0x01 ) && ( ( ReadD( _IP_ ) & 0x01 ) ? i : !i ) && pin0 )
//-------------------------- Interrupt timer 0 -------------------------------
if ( ( ReadD( _IE_ ) & 0x02 ) && ( ( ReadD( _IP_ & 0x02 ) ? i : !i ) && ( ReadD( _TCON_ ) & 0x20 ) ) ){
WriteD( _TCON_, ReadD( _TCON_ ) & 0xDF );
SP = ReadD( _SP_ );
WriteI( ++SP, ( PC & 0xFF ) );
WriteI( ++SP, ( PC >> 8 ) );
WriteD( _SP_, SP );
PC = 0x0B;
ActivePriority = i;
return;
}
//-------------------------- External interrupt 1 ----------------------------
// if ( ( ReadD( _IE_ ) & 0x04 ) && ( ( ReadD( _IP_ ) & 0x04 ) ? i : !i ) && pin1 )
//-------------------------- Interrupt timer 1 -------------------------------
if ( ( ReadD( _IE_ ) & 0x08 ) && ( ( ReadD( _IP_ ) & 0x08 ) ? i : !i ) && ( ReadD( _TCON_ ) & 0x80 ) ) {
WriteD( _TCON_, ReadD( _TCON_ ) & 0x7F );
SP = ReadD( _SP_ );
WriteI( ++SP, ( PC & 0xFF ) );
WriteI( ++SP, ( PC >> 8 ) );
WriteD( _SP_, SP );
PC = 0x1B;
ActivePriority = i;
return;
}
//-------------------------- Serial Interrupts -------------------------------
if ( ( ReadD( _IE_ ) & 0x10 ) && ( ( ReadD( _IP_ ) & 0x10 ) ? i : !i ) && ( ReadD( _SCON_ ) & 0x03 ) ) {
SP = ReadD( _SP_ );
WriteI( ++SP, ( PC & 0xFF ) );
WriteI( ++SP, ( PC >> 8 ) );
WriteD( _SP_, SP );
PC = 0x23;
ActivePriority = i;
return;
}
//-------------------------- Interrupt timer 2 -------------------------------
if ( ( ReadD( _IE_ ) & 0x20 ) && ( ( ReadD( _IP_ ) & 0x20 ) ? i : !i ) && ( ReadD( _T2CON_ ) & 0x80 ) ) {
SP = ReadD( _SP_ );
WriteI( ++SP, ( PC & 0xFF ) );
WriteI( ++SP, ( PC >> 8 ) );
WriteD( _SP_, SP );
PC = 0x2B;
ActivePriority = i;
return;
}
}
}
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::DoTimers( )
// Execute les timers
//////////////////////////////////////////////////////////////////////////////
void CPU8051::DoTimers( )
{
unsigned int tmp;
unsigned int TR;
unsigned int MODE;
unsigned int GATE;
unsigned int TimerCounter;
// ----- Timer 0
TR = ReadD( _TCON_ ) & 0x10;
MODE = ReadD( _TMOD_ ) & 0x03;
GATE = ReadD( _TMOD_ ) & 0x08;
TimerCounter = ReadD( _TMOD_ ) & 0x04;
if ( ( TR && !GATE && !TimerCounter ) || ( MODE == 3 ) )
switch( MODE ) {
// Mode 0, compteur de 13 bits.
case 0 :
tmp = ReadD( _TH0_ ) * 0x100 + ReadD( _TL0_ );
++tmp &= 0x1FFF; // On ne garde que 13 bits.
if ( tmp == 0 ) // If overflow set TF0
WriteD( _TCON_, ReadD( _TCON_ ) | 0x20 );
WriteD( _TH0_, tmp / 0x100 );
WriteD( _TL0_, tmp & 0xFF );
break;
// Mode 1, compteur de 16 bits.
case 1 :
tmp = ReadD( _TH0_ ) * 0x100 + ReadD( _TL0_ );
++tmp &= 0xFFFF; // On ne garde que 16 bits.
if ( tmp == 0 ) // If overflow set TF0
WriteD( _TCON_, ReadD( _TCON_ ) | 0x20 );
WriteD( _TH0_, ( tmp / 0x100 ) );
WriteD( _TL0_, ( tmp & 0xFF ) );
break;
// Mode 2, Compteur de 8 bits avec Auto-Reload
case 2 :
tmp = ReadD( _TL0_ );
++tmp &= 0xFF;
if ( tmp == 0 ) { // If overflow -> reload et set TF0
WriteD( _TCON_, ReadD( _TCON_ ) | 0x20 );
WriteD( _TL0_, ReadD( _TH0_ ) );
}
else
WriteD( _TL0_, tmp );
break;
// Mode 3 : TL0 et TH0 sont 2 Timers independants de 8 bits chacuns.
case 3 :
if ( TR && !GATE && !TimerCounter ) {
tmp = ReadD( _TL0_ );
++tmp &= 0xFF;
if ( tmp == 0 ) // If TL0 overflow set TF0
WriteD( _TCON_, ReadD( _TCON_ ) | 0x20 );
WriteD( _TL0_, tmp );
} // TH0 utilise TR1 et TF1.
TR = ReadD( _TCON_ ) & 0x40;
if ( TR ) {
tmp = ReadD( _TH0_ );
++tmp &= 0xFF;
if ( tmp == 0 ) // If TH0 overflow set TF1
WriteD( _TCON_, ReadD( _TCON_ ) | 0x80 ); // TF1 = 1.
WriteD( _TH0_, tmp );
}
break;
};
// ----- Timer 1
TR = ReadD( _TCON_ ) & 0x40;
MODE = ( ReadD( _TMOD_ ) & 0x30 ) >> 4 ;
GATE = ReadD( _TMOD_ ) & 0x80;
TimerCounter = ReadD( _TMOD_ ) & 0x40;
if ( TR && !GATE && !TimerCounter )
switch( MODE ) {
// Mode 0, compteur de 13 bits.
case 0 :
tmp = ReadD( _TH1_ ) * 0x100 + ReadD( _TL1_ );
++tmp &= 0x1FFF; // On ne garde que 13 bits.
if ( tmp == 0 ) // If overflow set TF1
WriteD( _TCON_, ReadD( _TCON_ ) | 0x80 );
WriteD( _TH1_, tmp / 0x100 );
WriteD( _TL1_, tmp & 0xFF );
break;
// Mode 1, compteur de 16 bits.
case 1 :
tmp = ReadD( _TH1_ ) * 0x100 + ReadD( _TL1_ );
++tmp &= 0xFFFF; // On ne garde que 16 bits.
if ( tmp == 0 ) // If overflow set TF1
WriteD( _TCON_, ReadD( _TCON_ ) | 0x80 );
WriteD( _TH1_, ( tmp / 0x100 ) );
WriteD( _TL1_, ( tmp & 0xFF ) );
break;
// Mode 2, Compteur de 8 bits avec Auto-Reload
case 2 :
tmp = ReadD( _TL1_ );
++tmp &= 0xFF;
if ( tmp == 0 ) { // If overflow -> reload et set TF1
WriteD( _TCON_, ReadD( _TCON_ ) | 0x80 );
WriteD( _TL1_, ReadD( _TH1_ ) );
}
else
WriteD( _TL1_, tmp );
break;
// Mode 3 : mode inactif: retient la valeur de TH1 et TL1.
// Equivalent a TR1 = 0.
case 3 :
break;
};
}
// Addressing modes defined in the order as they appear in disasm.hpp
// from table argstext[]
#define ADDR11 0
#define ADDR16 1
#define DIRECT 3
#define BITADDR 14
#define RELADDR 15
#define DATAIMM 16
#define DATA16 22
#define CBITADDR 23
// SFR Memory map [80h - FFh]
// ---------------------------------------------------------------
// F8 | | | | | | | | | FF
// F0 | B | | | | | | | | F7
// E8 | | | | | | | | | EF
// E0 | ACC | | | | | | | | E7
// D8 | | | | | | | | | DF
// D0 | PSW | | | | | | | | D7
// C8 | T2CON| |RCAP2L|RCAP2H| TL2 | TH2 | | | CF
// C0 | | | | | | | | | C7
// B8 | IP | | | | | | | | BF
// B0 | P3 | | | | | | | | B7
// A8 | IE | | | | | | | | AF
// A0 | P2 | | | | | | | | A7
// 98 | SCON | SBUF | | | | | | | 9F
// 90 | P1 | | | | | | | | 97
// 88 | TCON | TMOD | TL0 | TL1 | TH0 | TH1 | | | 8F
// 80 | P0 | SP | DPL | DPH | | | | PCON | 87
// ---------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////
// int CPU8051::SFRMemInfo( unsigned int Address, char *Text )
// Return as Text the name of the SFR register at Address if any
//////////////////////////////////////////////////////////////////////////////
int CPU8051::SFRMemInfo( unsigned int Address, char *Text )
{
switch( Address ) {
case 0x80 : return sprintf( Text, "P0" );
case 0x81 : return sprintf( Text, "SP" );
case 0x82 : return sprintf( Text, "DPL" );
case 0x83 : return sprintf( Text, "DPH" );
case 0x87 : return sprintf( Text, "PCON" );
case 0x88 : return sprintf( Text, "TCON" );
case 0x89 : return sprintf( Text, "TMOD" );
case 0x8A : return sprintf( Text, "TL0" );
case 0x8B : return sprintf( Text, "TL1" );
case 0x8C : return sprintf( Text, "TH0" );
case 0x8D : return sprintf( Text, "TH1" );
case 0x90 : return sprintf( Text, "P1" );
case 0x98 : return sprintf( Text, "SCON" );
case 0x99 : return sprintf( Text, "SBUF" );
case 0xA0 : return sprintf( Text, "P2" );
case 0xA8 : return sprintf( Text, "IE" );
case 0xB0 : return sprintf( Text, "P3" );
case 0xB8 : return sprintf( Text, "IP" );
case 0xC8 : return sprintf( Text, "T2CON" );
case 0xCA : return sprintf( Text, "RCAP2L" );
case 0xCB : return sprintf( Text, "RCAP2H" );
case 0xCC : return sprintf( Text, "TL2" );
case 0xCD : return sprintf( Text, "TH2" );
case 0xD0 : return sprintf( Text, "PSW" );
case 0xE0 : return sprintf( Text, "ACC" );
case 0xF0 : return sprintf( Text, "B" );
default : return sprintf( Text, "%.2XH", Address );
}
}
//////////////////////////////////////////////////////////////////////////////
// void CPU8051::IntMemBitInfo( unsigned int BitAddress, char *Text )
// Return as Text the decoded BitAddress
//////////////////////////////////////////////////////////////////////////////
void CPU8051::IntMemBitInfo( unsigned int BitAddress, char *Text )
{
unsigned int ByteAddress, BitNumber;
int TextLength;
if ( BitAddress > 0x7F ) {
// SFR 80-FF
ByteAddress = BitAddress & 0xF8;
BitNumber = BitAddress & 0x07;
}
else {
// 20-2F
ByteAddress = ( BitAddress >> 3 ) + 0x20;
BitNumber = BitAddress & 0x07;
}
TextLength = SFRMemInfo( ByteAddress, Text );
// sprintf( &Text[ TextLength ], ".%X" );
// Modified by Hugo Villeneuve to remove compilation warning
sprintf( &Text[ TextLength ], ".%X", BitAddress );
}
//////////////////////////////////////////////////////////////////////////////
// int CPU8051::Disasm( unsigned int Address, char *Text )
// Disasm one instruction at Address into a Text string
//////////////////////////////////////////////////////////////////////////////
int CPU8051::Disasm( unsigned int Address, char *Text )
{
int TextLength=0;
char TextTmp[20];
unsigned char OpCode;
int ArgTblOfs;
int InstSize;
int i;
OpCode = PGMMem->Read8( Address );
InstSize = InstSizesTbl[ OpCode ];
//printf("%.4X\n", Address);
TextLength += sprintf( Text, " %.4X ", Address );
for (i = 0; i < InstSize; i++ )
TextLength += sprintf( &Text[TextLength], " %.2X", PGMMem->Read8( Address + i ) );
Address++;
for (; TextLength < 17; ) TextLength += sprintf( &Text[ TextLength ], " " );
TextLength += sprintf( &Text[ TextLength ], "%s ", InstTextTbl[ InstTypesTbl[ OpCode ] ] );
ArgTblOfs = OpCode << 2;
for (; TextLength < 25; ) TextLength += sprintf( &Text[ TextLength ], " " );
// MOV direct, direct (OpCode 85h) is peculiar, the operands are inverted
if ( OpCode == 0x85 ) {
SFRMemInfo( PGMMem->Read8( Address + 1 ), TextTmp );
TextLength += sprintf( &Text[ TextLength ], "%s,", TextTmp );
SFRMemInfo( PGMMem->Read8( Address ), TextTmp );
TextLength += sprintf( &Text[ TextLength ], "%s", TextTmp );
Address += 2;
return InstSize;
}
for ( i = 1; i <= InstArgTbl[ ArgTblOfs ]; i++ ) {
switch( InstArgTbl[ ArgTblOfs + i ] ) {
case ADDR11 : {
TextLength += sprintf( &Text[ TextLength ], "%.4XH", ( ( OpCode << 3) & 0xF00 ) + ( PGMMem->Read8( Address ) ) );
Address++;
break;
}
case ADDR16 : {
TextLength += sprintf( &Text[ TextLength ], "%.4XH", ( ( PGMMem->Read8( Address ) << 8 ) + PGMMem->Read8( Address + 1 ) ) );
Address += 2;
break;
}
case DIRECT : {
SFRMemInfo( PGMMem->Read8( Address ), TextTmp );
TextLength += sprintf( &Text[ TextLength ], "%s", TextTmp );
Address++;
break;
}
case BITADDR : {
IntMemBitInfo( ( PGMMem->Read8( Address ) & 0xF8 ), TextTmp );
TextLength += sprintf( &Text[ TextLength ], "%s.%X" , TextTmp, ( PGMMem->Read8( Address ) & 7 ) );
Address++;
break;
}
case RELADDR : {
Address++;
TextLength += sprintf( &Text[ TextLength ], "%.4XH", ( Address & 0xFF00 ) + ( ( ( Address & 0xFF ) + PGMMem->Read8( Address - 1 ) ) & 0xFF ) );
break;
}
case DATAIMM : {
TextLength += sprintf( &Text[ TextLength ], "#%.2XH", PGMMem->Read8( Address ) );
Address++;
break;
}
case DATA16 : {
TextLength += sprintf( &Text[ TextLength ],"#%.4XH", ( ( PGMMem->Read8( Address ) << 8 ) + PGMMem->Read8( Address+1 ) ) );
Address += 2;
break;
}
case CBITADDR : {
IntMemBitInfo( ( PGMMem->Read8( Address ) & 0xF8 ), TextTmp );
TextLength += sprintf( &Text[ TextLength ], "/%s.%X", TextTmp, ( PGMMem->Read8( Address ) & 7 ) );
Address++;
break;
}
default : {
TextLength += sprintf( &Text[ TextLength ],"%s", ArgsTextTbl[ InstArgTbl[ ArgTblOfs + i ] ] );
}
}
if (i < InstArgTbl[ ArgTblOfs ]) { TextLength += sprintf( &Text[ TextLength ], "," ); }
}
return InstSize;
}
#include "Inst_Imp.cpp"

View File

@ -1,62 +0,0 @@
#ifndef _CPU8051_HPP_
#define _CPU8051_HPP_
#include "Memory.hpp"
#include "Reg8051.hpp"
#define BANKPSW ( ReadD( _PSW_ ) & 0x18 )
//////////////////////////////////////////////////////////////////////////////
// CPU8051
// Implements the 8051 CPU Object
//////////////////////////////////////////////////////////////////////////////
class CPU8051 {
public:
CPU8051( );
~CPU8051( );
void Exec( );
void Reset( );
unsigned int GetPC( );
void SetPC( unsigned int NewPC );
void WriteD( unsigned int Address, unsigned char Value );
void WriteExt( unsigned int Address, unsigned char Value );
void WriteInt( unsigned int Address, unsigned char Value );
void WriteI( unsigned int Address, unsigned char Value );
void WritePGM( unsigned int Address, unsigned char Value );
unsigned char ReadD( unsigned int Address );
unsigned char ReadInt( unsigned int Address );
unsigned char ReadExt( unsigned int Address );
unsigned char ReadI( unsigned int Address );
unsigned char ReadPGM( unsigned int Address );
unsigned int GetNextAddress( );
void WriteB( unsigned int BitAddress, unsigned char Value );
unsigned char ReadB( unsigned int BitAddress );
void CheckInterrupts( );
void DoTimers( );
int SFRMemInfo( unsigned int Address, char *Text );
void IntMemBitInfo( unsigned int BitAddress, char *Text );
int Disasm( unsigned int Address, char *Text );
private:
Memory *SFRMem;
Memory *PGMMem;
Memory *IntMem;
Memory *ExtMem;
unsigned int PC;
unsigned long CLOCK;
int ActivePriority;
int (CPU8051::*funcptr[256])();
#include "Inst_Def.hpp"
};
#endif

View File

@ -1,737 +0,0 @@
// EmuConsole.cpp
#include <stdio.h>
#include <iostream>
#include <fstream>
#include "config.h"
#include "EmuConsole.hpp"
#include "CPU8051.hpp"
#include "Reg8051.hpp"
#include "Keyboard.hpp"
int main( int argc, char **argv )
{
CPU8051 *maincpu = new CPU8051;
EmuConsole *emuUI = new EmuConsole( argc, argv, maincpu );
emuUI->Main();
printf( "End of program.\n" );
delete emuUI;
delete maincpu;
return 0;
}
//////////////////////////////////////////////////////////////////////////////
// EmuConsole::EmuConsole( int argc, char **argv, CPU8051 *mCPU )
// EmuConsole constructor
//////////////////////////////////////////////////////////////////////////////
EmuConsole::EmuConsole( int argc, char **argv, CPU8051 *mCPU )
{
CPU = mCPU;
CPU->Reset( );
NbBreakpoints = 0;
if ( argc > 1 ) LoadHexFile( argv[ 1 ] );
}
//////////////////////////////////////////////////////////////////////////////
// EmuConsole::~EmuConsole( )
// EmuConsole destructor
//////////////////////////////////////////////////////////////////////////////
EmuConsole::~EmuConsole( )
{
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::Main( )
// EmuConsole main loop
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::Main( )
{
/*int ASCII_Code;*/
unsigned int Index;
string InputString;
string Command;
string Parameter1;
string Parameter2;
char prompt[] = "-> ";
char *Title[] = { " *******************",
" * 8051 Emulator *",
" *******************",
"", 0 };
char *Menu[] = {
" Available commands, [ ] = options",
"",
" Set Breakpoint.............. SB [address]",
" Remove Breakpoint........... RB [address]",
" Display Breakpoint(s)....... DB",
" Dump External Data Memory... DE [address]",
" Dump Internal Data Memory... DI [address]",
" Dump Program Memory......... DP [address]",
" Display Registers content... DR",
" Execute..................... EM [address [number of instructions]]",
" Help........................ H",
" Modify External Data Memory. ME address value",
" Modify Internal Data Memory. MI address value",
" Modify Program Memory....... MP address value",
" Modify Register............. MR register value",
" Quit Emulator............... Q",
" Trace mode.................. T [address]",
" Unassemble.................. U [address [numberof instructions]]",
" Reset processor............. Z", 0 };
Index = 0;
while ( Title[ Index ] != 0 ) printf( "%s%s", Title[ Index++ ], ENDLINE );
Index = 0;
while ( Menu[ Index ] != 0 ) printf( "%s%s", Menu[ Index++ ], ENDLINE );
Reset( );
int QuitRequest = 0;
while( !QuitRequest ) {
try {
printf( prompt );
getline ( cin, InputString, '\n' );
Capitalize( &InputString );
RemoveSpaces( &InputString );
for ( Index = 0; Index < InputString.size( ); Index++ ) {
if ( InputString[ Index ] < 'A' || InputString[ Index ] > 'z' )
break;
}
Command = InputString;
// Keep only the Command part from the input line
Command.replace( Index, Command.size( ), 0, ( char )0 );
// Keep only the arguments
InputString.replace( 0, Index, 0, ( char )0 );
RemoveSpaces ( &InputString );
Index = 0;
while ( ( Index < InputString.size( ) ) && ( InputString [ Index ] != ' ' ) ) Index++;
Parameter1 = InputString;
Parameter1.replace( Index, Parameter1.size( ), 0, ( char )0 );
InputString.replace( 0, Index, 0, ( char )0 );
RemoveSpaces ( &InputString );
Index = 0;
while ( ( Index < InputString.size( ) ) && ( InputString [ Index ] != ' ' ) ) Index++;
Parameter2 = InputString;
Parameter2.replace( Index, Parameter2.size( ), 0, ( char )0 );
InputString.replace( 0, Index, 0, ( char )0 );
RemoveSpaces ( &InputString );
if ( !InputString.empty( ) )
throw SyntaxError( );
if ( Command.empty( ) && !Parameter1.empty( ) )
throw SyntaxError( );
if ( ( Parameter1.size( ) > 4 ) || ( Parameter2.size( ) > 4 ) )
throw InvalidParameter( );
if ( !Command.empty( ) ) {
switch ( Command [ 0 ] ) {
case 'D' :
if ( Parameter2.empty( ) ) {
if ( Command == "DB" && Parameter1.empty( ) )
ShowBreakpoints( );
else if ( Command == "DE" )
DumpExt( Parameter1 );
else if ( Command == "DI" )
DumpInt( Parameter1 );
else if ( Command == "DP" ) {
if ( Parameter1.empty( ) )
Parameter1 = "PC";
DumpPGM( Parameter1 );
}
else if ( Command == "DR" && Parameter1.empty( ) )
ShowRegisters( );
else
throw SyntaxError( );
}
else
throw SyntaxError( );
break;
case 'E' :
if ( Command == "EM" )
Exec( Parameter1, Parameter2 );
else
throw SyntaxError( );
break;
case 'H' :
if ( Command == "H" && Parameter1.empty( ) && Parameter2.empty( ) )
{
Index = 0;
while ( Menu[ Index ] != 0 ) printf( "%s%s", Menu[ Index++ ], ENDLINE );
}
else
throw SyntaxError( );
break;
case 'M' :
if ( Parameter1.empty() || Parameter2.empty() )
throw MissingParameter();
else if ( Command == "ME" ) {
unsigned int adresse = Ascii2Hex( Parameter1, 4 );
unsigned char valeur = Ascii2Hex( Parameter2, 2 );
CPU->WriteExt( adresse, valeur );
}
else if ( Command == "MI" ) {
unsigned char adresse = Ascii2Hex( Parameter1, 2 );
unsigned char valeur = Ascii2Hex( Parameter2, 2 );
CPU->WriteInt( adresse, valeur );
}
else if ( Command == "MP" ) {
unsigned int adresse = Ascii2Hex( Parameter1, 4 );
unsigned char valeur = Ascii2Hex( Parameter2, 2 );
CPU->WritePGM( adresse, valeur );
}
else if ( Command == "MR" )
SetRegister( Parameter1, Parameter2 );
else
throw SyntaxError();
break;
case 'Q' :
if ( Command == "Q" && Parameter1.empty( ) && Parameter2.empty( ) )
QuitRequest = 1;
else
throw SyntaxError( );
break;
case 'R' :
if ( !Parameter2.empty( ) )
throw TooMuchParameters( );
if ( Command == "RB" ) {
if ( Parameter1.empty( ) )
ClearBreakpoint( CPU->GetPC( ) );
else
ClearBreakpoint( Ascii2Hex( Parameter1, 4 ) );
}
else
throw SyntaxError( );
break;
case 'S' :
if ( !Parameter2.empty( ) )
throw TooMuchParameters( );
if ( Command == "SB" ) {
if ( Parameter1.empty( ) )
SetBreakpoint( CPU->GetPC( ) );
else
SetBreakpoint( Ascii2Hex( Parameter1, 4 ) );
}
else
throw SyntaxError( );
break;
case 'T' :
if ( !Parameter2.empty( ) )
throw TooMuchParameters( );
if ( Command == "T" )
Trace( Parameter1 );
else
throw SyntaxError( );
break;
case 'U' :
if ( Command == "U" )
Disasm( Parameter1, Parameter2 );
else
throw SyntaxError( );
break;
case 'Z' :
if ( Command == "Z" && Parameter1.empty( ) && Parameter2.empty( ) )
Reset( );
else
throw SyntaxError( );
break;
case '\n' :
break;
default :
throw SyntaxError( );
}
}
}
catch ( SyntaxError ) {
printf( "Syntax Error!%s", ENDLINE );
}
catch ( MissingParameter ) {
printf( "Missing Parameter!%s", ENDLINE );
}
catch ( InvalidParameter ) {
printf( "Invalid Parameter Format!%s", ENDLINE );
}
catch ( TooMuchParameters ) {
printf( "Wrong Number of Parameters!%s", ENDLINE );
}
catch ( ResetRequest ) {
printf( "Resetting Microcontroler...%s", ENDLINE );
}
catch ( InvalidRegister ) {
printf( "%sInvalid register name!%s", ENDLINE, ENDLINE );
printf( "Valid registers are A, B, PC and SP.%s", ENDLINE );
}
}
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::Reset( )
// CPU reset and Console UI update
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::Reset( )
{
printf( "Resetting... " );
CPU->Reset( );
printf( "Done.%s", ENDLINE );
ShowRegisters( );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::Trace( string Address )
// CPU trace and Console UI update
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::Trace( string Address )
{
if ( !Address.empty( ) ) CPU->SetPC( Ascii2Hex( Address, Address.size( ) ) );
CPU->Exec( );
ShowRegisters( );
DisasmN( CPU->GetPC( ), 1 );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::Exec( string Address, string NumberInst )
// CPU exec and Console UI update
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::Exec( string Address, string NumberInst )
{
char dummy;
int NbInst = -1; // -1 is infinity
if ( !Address.empty( ) ) {
Capitalize( &Address );
if ( Address != "PC" ) CPU->SetPC( Ascii2Hex( Address, Address.size( ) ) );
}
if ( !NumberInst.empty( ) ) NbInst = Ascii2Hex( NumberInst, NumberInst.size( ) );
InitUnixKB( );
printf( "Program executing...%s", ENDLINE );
do {
CPU->Exec( );
if ( NbInst > 0 ) NbInst--;
} while ( !IsBreakpoint( CPU->GetPC( ) ) && ( NbInst != 0 ) && !kbhit( ) );
if ( kbhit( ) ) {
dummy = getch( ); // flush key
printf( "Caught break signal!%s", ENDLINE );
}
if ( NbInst == 0 ) printf( "Number of instructions reached! Stopping!%s", ENDLINE );
if ( IsBreakpoint( CPU->GetPC( ) ) ) printf( "Breakpoint hit at %.4X! Stopping!%s", CPU->GetPC( ), ENDLINE );
ResetUnixKB( );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::ShowBreakpoints( )
// Show Breakpoints list
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::ShowBreakpoints( )
{
for ( int Index = 0; Index < NbBreakpoints ; Index++ )
printf( "Breakpoint at Address = %.4X%s", Breakpoints[ Index ], ENDLINE );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::ClearBreakpoint( unsigned int Address )
// Clear Breakpoint at Address from list
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::ClearBreakpoint( unsigned int Address )
{
int Index = 0;
while ( Index < NbBreakpoints && Breakpoints[ Index ] != Address ) Index++;
if ( Breakpoints[ Index ] != Address ) return;
Breakpoints[ Index ] = Breakpoints[ NbBreakpoints - 1 ];
NbBreakpoints--;
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::SetBreakpoint( unsigned int Address )
// Set Breakpoint at Address from list
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::SetBreakpoint( unsigned int Address )
{
if ( IsBreakpoint( Address ) ) return;
if ( NbBreakpoints < MAXBP ) Breakpoints[ NbBreakpoints++ ] = Address;
}
//////////////////////////////////////////////////////////////////////////////
// int EmuConsole::IsBreakpoint( unsigned int Address )
// Is the a breakpoint at Address
//////////////////////////////////////////////////////////////////////////////
int EmuConsole::IsBreakpoint( unsigned int Address )
{
int Index = 0;
while ( Index < NbBreakpoints && Breakpoints[ Index ] != Address ) Index++;
return ( Breakpoints[ Index ] == Address && Index < NbBreakpoints );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::Disasm( string Address, string NumberInst )
// Disassemble 16 instructions at Address
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::Disasm( string Address, string NumberInst )
{
unsigned int MemAddress, NbInst;
Capitalize( &Address );
if ( Address.empty( ) || ( Address == "PC" ) ) MemAddress = CPU->GetPC( );
else MemAddress = Ascii2Hex( Address, Address.size( ) );
if ( NumberInst.empty( ) ) NumberInst = "10";
NbInst = Ascii2Hex( NumberInst, NumberInst.size( ) );
DisasmN( MemAddress, NbInst );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::DisasmN( unsigned int Address, int NumberInst )
// Disassemble NumberInst instructions at Address
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::DisasmN( unsigned int Address, int NumberInst )
{
char TextTmp[255];
int Row;
for ( Row = 0; Row < NumberInst ; Row++ ) {
Address += CPU->Disasm( Address, TextTmp );
printf( "%s%s", TextTmp, ENDLINE );
}
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::DumpPGM( string Address )
// Dump Program memory
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::DumpPGM( string Address )
{
unsigned int MemAddress = 0;
int Offset, Column;
unsigned char Byte;
if ( !Address.empty( ) ) {
Capitalize( &Address );
if ( Address == "PC" )
MemAddress = CPU->GetPC( );
else
MemAddress = Ascii2Hex( Address, Address.size( ) );
}
for ( Offset = 0; Offset < 256; Offset += 16 ) {
printf( "%.4X ", MemAddress + Offset );
for ( Column = 0; Column < 16; Column++ )
printf( " %.2X", ( int )CPU->ReadPGM( MemAddress + Offset + Column ) );
printf( " " );
for ( Column = 0; Column < 16; Column++ ) {
Byte = CPU->ReadPGM( MemAddress + Offset + Column );
if ( ( int )Byte >= 32 && ( int )Byte <= 126 )
printf( "%c", Byte );
else printf( "." );
}
printf( "%s", ENDLINE );
}
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::DumpI( string Address )
// Dump using Indirect read access
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::DumpI( string Address )
{
unsigned int MemAddress = 0;
int Offset, Column;
unsigned char Byte;
if ( !Address.empty( ) ) MemAddress = Ascii2Hex( Address, Address.size( ) );
for ( Offset = 0; Offset < 256; Offset += 16 ) {
printf( "%.4X ", MemAddress + Offset );
for ( Column = 0; Column < 16; Column++ )
printf( " %.2X", ( int )CPU->ReadI( MemAddress + Offset + Column ) );
printf( " " );
for ( Column = 0; Column < 16; Column++ ) {
Byte = CPU->ReadI( MemAddress + Offset + Column );
if ( ( int )Byte >= 32 && ( int )Byte <= 126 )
printf( "%c", Byte );
else printf( "." );
}
printf( "%s", ENDLINE );
}
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::DumpInt( string Address )
// Dump internal Data memory
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::DumpInt( string Address )
{
unsigned int MemAddress = 0;
int Offset, Column;
unsigned char Byte;
if ( !Address.empty( ) )
MemAddress = Ascii2Hex( Address, 4 );
for ( Offset = 0; Offset < 256; Offset += 16 ) {
printf( "%.4X ", MemAddress + Offset );
for ( Column = 0; Column < 16; Column++ )
printf( " %.2X", ( int )CPU->ReadInt( MemAddress + Offset + Column ) );
printf( " " );
for ( Column = 0; Column < 16; Column++ ) {
Byte = CPU->ReadInt( MemAddress + Offset + Column );
if ( ( int )Byte >= 32 && ( int )Byte <= 126 )
printf( "%c", Byte );
else printf( "." );
}
printf( "%s", ENDLINE );
}
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::DumpExt( string Address )
// Dump de la memoire externe ( $00 a $FFFF)
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::DumpExt( string Address )
{
unsigned int MemAddress = 0;
int Offset, Column;
unsigned char Byte;
if ( !Address.empty( ) )
MemAddress = Ascii2Hex( Address, 4 );
for ( Offset = 0; Offset < 256; Offset += 16 ) {
printf( "%.4X ", MemAddress + Offset );
for ( Column = 0; Column < 16; Column++ )
printf( " %.2X", ( int )CPU->ReadExt( MemAddress + Offset + Column ) );
printf( " " );
for ( Column = 0; Column < 16; Column++ ) {
Byte = CPU->ReadExt( MemAddress + Offset + Column );
if ( ( int )Byte >= 32 && ( int )Byte <= 126 )
printf( "%c", Byte );
else printf( "." );
}
printf( "%s", ENDLINE );
}
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::DumpD( string Address )
// Dump using Direct read access
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::DumpD( string Address )
{
unsigned int MemAddress = 0;
int Offset, Column;
unsigned char Byte;
if ( !Address.empty( ) ) MemAddress = Ascii2Hex( Address, Address.size( ) );
for ( Offset = 0; Offset < 256; Offset += 16 ) {
printf( "%.4X ", MemAddress + Offset );
for ( Column = 0; Column < 16; Column++ )
printf( " %.2X", ( int )CPU->ReadD( MemAddress + Offset + Column ) );
printf( " " );
for ( Column = 0; Column < 16; Column++ ) {
Byte = CPU->ReadD( MemAddress + Offset + Column );
if ( ( int )Byte >= 32 && ( int )Byte <= 126 )
printf( "%c", Byte );
else printf( "." );
}
printf( "%s", ENDLINE );
}
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::SetRegister( string Register, string NewValue )
// Set NewValue to Register
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::SetRegister( string Register, string NewValue )
{
Capitalize( &Register );
if ( Register == "PC" ) CPU->SetPC( Ascii2Hex( NewValue, 4 ) );
else if ( Register == "A" ) CPU->WriteD( _ACC_, Ascii2Hex( NewValue, 2 ) );
else if ( Register == "B" ) CPU->WriteD( _B_, Ascii2Hex( NewValue, 2 ) );
else if ( Register == "SP" ) CPU->WriteD( _SP_, Ascii2Hex( NewValue, 2 ) );
else throw InvalidRegister( );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::Capitalize( string *InputString )
// Capitalize all letters in InputString
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::Capitalize( string *InputString )
{
for (unsigned int Index = 0; Index < InputString->size( ); Index++ ) {
{
if ( ( ( *InputString )[ Index ] >= 'a' ) && ( ( *InputString )[ Index ] <= 'z' ) )
( *InputString )[ Index ] -= ( ( int )'a'- ( int )'A' );
}
}
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::RemoveSpaces( string *InputString )
// Remove spaces from InputString
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::RemoveSpaces( string *InputString )
{
unsigned int Index = 0;
while ( ( Index < ( *InputString ).size( ) ) && ( *InputString )[ Index ] == ' ' ) {
Index++;
}
( *InputString ).replace( 0, Index, 0, ( char )0 );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::ShowRegisters( )
// Show CPU registers
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::ShowRegisters( )
{
unsigned char PSW = CPU->ReadD( _PSW_ );
int BankSelect = ( PSW & 0x18 );
printf( "----------------------------------------------------------------------%s", ENDLINE );
printf( "| PC | SP | DPTR | ACC | B | PSW: CY AC F0 RS1 RS0 OV - P |%s", ENDLINE );
printf( "| %.4X | %.2X | %.4X | %.2X | %.2X |", CPU->GetPC( ), CPU->ReadD( _SP_ ), ( CPU->ReadD( _DPTRHIGH_ ) << 8 ) + CPU->ReadD( _DPTRLOW_ ), CPU->ReadD( _ACC_ ), CPU->ReadD( _B_ ) );
printf( " %d %d %d %d %d %d %d %d |", ( PSW >> 7 ) & 1, ( PSW >> 6 ) & 1, ( PSW >> 5 ) & 1, ( PSW >> 4 ) & 1, ( PSW >> 3 ) & 1, ( PSW >> 2 ) & 1, ( PSW >> 1 ) & 1, PSW & 1 );
printf( "%s", ENDLINE );
printf( "----------------------------------------------------------------------%s", ENDLINE );
printf( "| TCON | TMOD | IE | IP | R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7 | |%s", ENDLINE );
printf( "| %.2X | %.2X | %.2X | %.2X ", CPU->ReadD( _TCON_ ), CPU->ReadD( _TMOD_ ), CPU->ReadD( _IE_ ), CPU->ReadD( _IP_ ) );
printf( "| %.2X | %.2X | %.2X | %.2X ", CPU->ReadD( BankSelect + _R0_ ), CPU->ReadD( BankSelect + _R1_ ), CPU->ReadD( BankSelect + _R2_ ), CPU->ReadD( BankSelect + _R3_ ) );
printf( "| %.2X | %.2X | %.2X | %.2X ", CPU->ReadD( BankSelect + _R4_ ), CPU->ReadD( BankSelect + _R5_ ), CPU->ReadD( BankSelect + _R6_ ), CPU->ReadD( BankSelect + _R7_ ) );
printf( "| |%s", ENDLINE );
printf( "----------------------------------------------------------------------%s", ENDLINE );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuConsole::LoadHexFile( string Filename )
//
//////////////////////////////////////////////////////////////////////////////
void EmuConsole::LoadHexFile( string Filename )
{
printf("LoadHex\n");
int i, j, RecLength, LoadOffset, RecType, Data, Checksum;
char Line[ 250 ];
ifstream HexFile( Filename.c_str() );
try {
if ( ! HexFile )
throw ErrorOpeningFile();
while( ! HexFile.eof() ) {
i = 0;
Checksum = 0;
HexFile.getline( Line, 250, '\n' );
if ( Line[ i++ ] != ':' )
throw ErrorHexFileFormat();
RecLength = Ascii2Hex( &Line[ i ], 2 );
i += 2;
Checksum += RecLength;
LoadOffset = Ascii2Hex( &Line[i], 4 );
Checksum += LoadOffset / 256;
Checksum += LoadOffset % 256;
i += 4;
RecType = Ascii2Hex( &Line[i],2);
i += 2;
Checksum += RecType;
if ( RecType == 1 ) {
Checksum += Ascii2Hex( &Line[ i ], 2 );
if ( Checksum &= 0x000000FF )
throw ErrorHexFileFormat();
throw FinishedLoading();
}
if ( RecType )
throw ErrorHexFileFormat();
for ( j = 0; j < RecLength; j++ ) {
Data = Ascii2Hex( &Line[ i ], 2 );
CPU->WritePGM( (unsigned int)(LoadOffset + j), (unsigned char)Data );
i += 2;
Checksum += Data;
}
RecType = Ascii2Hex( &Line[ i ], 2 );
Checksum += RecType;
if ( Checksum &= 0x000000FF )
throw ErrorHexFileFormat();
}
throw ErrorHexFileFormat();
}
catch ( ErrorOpeningFile ) {
cout << "Error opening file " << Filename << endl;
}
catch ( ErrorHexFileFormat ) {
cout << "Invalid format for " << Filename << " file..." << endl;
}
catch ( SyntaxError ) {
cout << "Invalid format for " << Filename << " file..." << endl;
}
catch ( MissingParameter ) {
cout << "Invalid format for " << Filename << " file..." << endl;
}
catch ( FinishedLoading ) {
cout << "Using file " << Filename << " as input program." << endl;
}
HexFile.close();
}
//////////////////////////////////////////////////////////////////////////////
// unsigned int EmuConsole::Ascii2Hex( string istring, int length )
//
//////////////////////////////////////////////////////////////////////////////
unsigned int EmuConsole::Ascii2Hex( string istring, unsigned int length )
{
if ( !length || ( length > istring.size() ) )
length = istring.size();
if ( istring.empty() )
throw MissingParameter();
unsigned int result = 0;
unsigned int i, ascii_code;
for ( i = 0; i < length; i++ ) {
ascii_code = istring[ i ];
if ( ascii_code > 0x39 )
ascii_code &= 0xDF;
if ( ( ascii_code >= 0x30 && ascii_code <= 0x39 ) || ( ascii_code >= 0x41 && ascii_code <= 0x46 ) ) {
ascii_code -= 0x30;
if ( ascii_code > 9 )
ascii_code -= 7;
result <<= 4;
result += ascii_code;
}
else {
throw SyntaxError();
}
}
return result;
}

View File

@ -1,65 +0,0 @@
#ifndef _EMUCONSOLE_HPP_
#define _EMUCONSOLE_HPP_
#include "CPU8051.hpp"
#include <string>
#include "exceptions.hpp"
using namespace std;
// Maximum number of BreakPoints
#define MAXBP 32
#define ENDLINE "\n"
//////////////////////////////////////////////////////////////////////////////
// EmuConsole
// Implements the Console User Interface as an Object
//////////////////////////////////////////////////////////////////////////////
class EmuConsole {
public:
EmuConsole( int argc, char **argv, CPU8051 *mCPU );
~EmuConsole( );
void Main( );
void Reset( );
void Trace( string Address );
void Exec( string Address, string NumberInst );
void ShowBreakpoints( );
void SetBreakpoint( unsigned int Address );
void ClearBreakpoint( unsigned int Address );
int IsBreakpoint( unsigned int Address );
void Disasm( string Address, string NumberInst );
void DisasmN( unsigned int Address, int NumberInst );
void DumpPGM( string Address );
void DumpD( string Address );
void DumpInt( string Address );
void DumpExt( string Address );
void DumpI( string Address );
void ShowRegisters( );
void SetRegister( string Register, string NewValue );
private:
CPU8051 *CPU;
int NbBreakpoints;
unsigned int Breakpoints[ MAXBP ];
void LoadHexFile( string Filename );
unsigned int Ascii2Hex( string istring, unsigned int length );
void Capitalize( string *InputString );
void RemoveSpaces( string *InputString );
};
#endif

View File

@ -1,735 +0,0 @@
// EmuGtk.cpp
#include <iostream>
#include <stdio.h>
#include "config.h"
#include "CPU8051.hpp"
#include "EmuGtk.hpp"
#include "exceptions.hpp"
#include "pixmaps/reset.xpm"
#include "pixmaps/run.xpm"
#include "pixmaps/stop.xpm"
#include "pixmaps/step.xpm"
int EmuGtkNumber = 0;
int NbSignals = 0;
int SignalsData[ 32 ];
EmuGtk *EmuGtkPtr;
enum
{
DestroySignal=0,
DeleteSignal,
OpenISignal,
QuitISignal,
AboutISignal,
ResetBSignal,
RunBSignal,
StopBSignal,
StepBSignal
};
int main( int argc, char **argv )
{
CPU8051 *maincpu = new CPU8051;
EmuGtk *emuUI = new EmuGtk( argc, argv, maincpu );
emuUI->Main();
printf( "End of program.\n" );
delete emuUI;
delete maincpu;
return 0;
}
//////////////////////////////////////////////////////////////////////////////
// EmuGtk::EmuGtk( )
// EmuGtk constructor
//////////////////////////////////////////////////////////////////////////////
EmuGtk::EmuGtk( int argc, char **argv, CPU8051 *mCPU )
{
CPU = mCPU;
RunningState = 0;
g_print( "\n" );
gtk_init( &argc, &argv );
emuwin = gtk_window_new( GTK_WINDOW_TOPLEVEL );
gtk_window_set_title( GTK_WINDOW( emuwin ), "emu8051" );
gtk_container_set_border_width( GTK_CONTAINER( emuwin ), 0 );
gtk_widget_show( emuwin );
emufixed = gtk_fixed_new();
gtk_widget_set_usize( GTK_WIDGET( emufixed ), MAIN_WIN_WIDTH, MAIN_WIN_HEIGHT );
gtk_container_add( GTK_CONTAINER( emuwin ), emufixed );
gtk_widget_show( emufixed );
// EmuMenuBar( );
// Main window
emumainfixed = gtk_fixed_new();
gtk_widget_set_usize( GTK_WIDGET( emumainfixed ), MAIN_WIN_WIDTH, REG_WIN_HEIGHT + MEM_WIN_HEIGHT + BUTTONS_BAR_HEIGHT + 10 );
gtk_fixed_put( GTK_FIXED( emufixed ), emumainfixed, 0, 25 );
gtk_widget_show( emumainfixed );
ShowMenu();
AddButtons();
// Registers frame
regfrm = gtk_frame_new( 0 );
gtk_frame_set_shadow_type( GTK_FRAME( regfrm ), GTK_SHADOW_ETCHED_OUT );
gtk_widget_set_usize( GTK_WIDGET( regfrm ), REG_WIN_WIDTH, REG_WIN_HEIGHT );
gtk_fixed_put( GTK_FIXED( emumainfixed ), regfrm, 0, BUTTONS_BAR_HEIGHT );
regwin = new RegWin( regfrm );
gtk_widget_show( regfrm );
// Program disassembly frame
pgmfrm = gtk_frame_new( 0 );
gtk_frame_set_shadow_type( GTK_FRAME( pgmfrm ), GTK_SHADOW_ETCHED_OUT );
gtk_widget_set_usize( GTK_WIDGET( pgmfrm ), PGM_WIN_WIDTH, PGM_WIN_HEIGHT );
gtk_fixed_put( GTK_FIXED( emumainfixed ), pgmfrm, REG_WIN_WIDTH + 10, BUTTONS_BAR_HEIGHT );
pgmwin = new PgmWin( pgmfrm, CPU );
gtk_widget_show( pgmfrm );
// Memory dump frame
memfrm = gtk_frame_new( 0 );
gtk_frame_set_shadow_type( GTK_FRAME( memfrm ), GTK_SHADOW_ETCHED_OUT );
gtk_widget_set_usize( GTK_WIDGET( memfrm ), MEM_WIN_WIDTH, MEM_WIN_HEIGHT );
gtk_fixed_put( GTK_FIXED( emumainfixed ), memfrm, 0, REG_WIN_HEIGHT + BUTTONS_BAR_HEIGHT );
memwin = new MemWin( memfrm );
gtk_widget_show( memfrm );
if ( EmuGtkNumber >= 1 )
g_print( "WARNING! Signal too much EmuGtk Objects to handle signals!\n");
else
{
EmuGtkPtr = this;
NbSignals = 0;
// Window DESTROY signal
SignalsData[ NbSignals ] = DestroySignal;
gtk_signal_connect( GTK_OBJECT( emuwin ), "destroy", GTK_SIGNAL_FUNC( EmuGtkSignalStub2 ), &SignalsData[ NbSignals ] );
NbSignals++;
// Window DELETE event
SignalsData[ NbSignals ] = DeleteSignal;
gtk_signal_connect( GTK_OBJECT( emuwin ), "delete_event", GTK_SIGNAL_FUNC( EmuGtkSignalStub3 ), &SignalsData[ NbSignals ] );
NbSignals++;
// File->Open
SignalsData[ NbSignals ] = OpenISignal;
gtk_signal_connect( GTK_OBJECT( OpenItem ), "activate", GTK_SIGNAL_FUNC( EmuGtkSignalStub2 ), &SignalsData[ NbSignals ] );
NbSignals++;
// File->Quit
SignalsData[ NbSignals ] = QuitISignal;
gtk_signal_connect( GTK_OBJECT( QuitItem ), "activate", GTK_SIGNAL_FUNC( EmuGtkSignalStub2 ), &SignalsData[ NbSignals ] );
NbSignals++;
// Help->About
SignalsData[ NbSignals ] = AboutISignal;
gtk_signal_connect( GTK_OBJECT( AboutItem ), "activate", GTK_SIGNAL_FUNC( EmuGtkSignalStub2 ), &SignalsData[ NbSignals ] );
NbSignals++;
// RESET button
SignalsData[ NbSignals ] = ResetBSignal;
gtk_signal_connect( GTK_OBJECT( ButtonReset ), "button-press-event", GTK_SIGNAL_FUNC( EmuGtkSignalStub3 ), &SignalsData[ NbSignals ] );
NbSignals++;
// RUN button
SignalsData[ NbSignals ] = RunBSignal;
gtk_signal_connect( GTK_OBJECT( ButtonRun ), "button-press-event", GTK_SIGNAL_FUNC( EmuGtkSignalStub3 ), &SignalsData[ NbSignals ] );
NbSignals++;
// STOP button
SignalsData[ NbSignals ] = StopBSignal;
gtk_signal_connect( GTK_OBJECT( ButtonStop ), "button-press-event", GTK_SIGNAL_FUNC( EmuGtkSignalStub3 ), &SignalsData[ NbSignals ] );
NbSignals++;
// STEP button
SignalsData[ NbSignals ] = StepBSignal;
gtk_signal_connect( GTK_OBJECT( ButtonStep ), "button-press-event", GTK_SIGNAL_FUNC( EmuGtkSignalStub3 ), &SignalsData[ NbSignals ] );
NbSignals++;
EmuGtkNumber++;
}
if ( argc > 1 )
LoadHexFile( argv[1] );
}
//////////////////////////////////////////////////////////////////////////////
// void AddButtons()
// Create and show the Reset, Run, Stop, Trace and Step buttons
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::AddButtons( void )
{
//GtkStyle *Style = gtk_widget_get_style( GTK_WIDGET( emuwin ) );
RESET_pixmap = gdk_pixmap_colormap_create_from_xpm_d( NULL,
gtk_widget_get_default_colormap(),
&RESET_mask,
NULL,
( gchar ** ) reset_xpm );
RESET_widget = gtk_pixmap_new( RESET_pixmap, RESET_mask );
RUN_pixmap = gdk_pixmap_colormap_create_from_xpm_d( NULL,
gtk_widget_get_default_colormap(),
&RUN_mask,
NULL,
( gchar ** ) run_xpm );
RUN_widget = gtk_pixmap_new( RUN_pixmap, RUN_mask );
STOP_pixmap = gdk_pixmap_colormap_create_from_xpm_d( NULL,
gtk_widget_get_default_colormap(),
&STOP_mask,
NULL,
( gchar ** ) stop_xpm );
STOP_widget = gtk_pixmap_new( STOP_pixmap, STOP_mask );
STEP_pixmap = gdk_pixmap_colormap_create_from_xpm_d( NULL,
gtk_widget_get_default_colormap(),
&STEP_mask,
NULL,
( gchar ** ) step_xpm );
STEP_widget = gtk_pixmap_new( STEP_pixmap, STEP_mask );
ButtonTable = gtk_table_new( 1, 4, TRUE );
gtk_widget_set_usize( GTK_WIDGET( ButtonTable ), BUTTONS_BAR_WIDTH, BUTTONS_BAR_HEIGHT );
gtk_fixed_put( GTK_FIXED( emumainfixed ), ButtonTable, 0, 0 );
ButtonReset = gtk_button_new();
ButtonRun = gtk_button_new();
ButtonStop = gtk_button_new();
ButtonStep = gtk_button_new();
gtk_container_add( GTK_CONTAINER( ButtonReset ), RESET_widget );
gtk_container_add( GTK_CONTAINER( ButtonRun ), RUN_widget );
gtk_container_add( GTK_CONTAINER( ButtonStop ), STOP_widget );
gtk_container_add( GTK_CONTAINER( ButtonStep ), STEP_widget );
gtk_widget_set_usize( GTK_WIDGET( ButtonReset ), BUTTON_WIDTH, BUTTON_HEIGHT );
gtk_widget_set_usize( GTK_WIDGET( ButtonRun ), BUTTON_WIDTH, BUTTON_HEIGHT );
gtk_widget_set_usize( GTK_WIDGET( ButtonStop ), BUTTON_WIDTH, BUTTON_HEIGHT );
gtk_widget_set_usize( GTK_WIDGET( ButtonStep ), BUTTON_WIDTH, BUTTON_HEIGHT );
gtk_table_attach_defaults( GTK_TABLE( ButtonTable ), ButtonReset, 0, 1, 0, 1);
gtk_table_attach_defaults( GTK_TABLE( ButtonTable ), ButtonRun, 1, 2, 0, 1);
gtk_table_attach_defaults( GTK_TABLE( ButtonTable ), ButtonStop, 2, 3, 0, 1);
gtk_table_attach_defaults( GTK_TABLE( ButtonTable ), ButtonStep, 3, 4, 0, 1);
gtk_widget_show( GTK_WIDGET( ButtonReset ) );
gtk_widget_show( GTK_WIDGET( ButtonRun ) );
gtk_widget_show( GTK_WIDGET( ButtonStop ) );
gtk_widget_show( GTK_WIDGET( ButtonStep ) );
gtk_widget_show_all( GTK_WIDGET( ButtonTable ) );
}
//////////////////////////////////////////////////////////////////////////////
// EmuGtk::~EmuGtk( )
// EmuGtk destructor
//////////////////////////////////////////////////////////////////////////////
EmuGtk::~EmuGtk( )
{
g_print( "EmuGtk::~EmuGtk( )\n" );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuGtk::Reset( )
// CPU reset and Gtk UI update
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::Reset( )
{
CPU->Reset( );
regwin->Show( CPU );
pgmwin->Disasm( );
memwin->DumpD( CPU, 0 );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuGtk::Step( )
// CPU Step and Gtk UI update
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::Step( )
{
CPU->Exec( );
regwin->Show( CPU );
pgmwin->Disasm( );
memwin->DumpD( CPU, 0 );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuGtk::Main( )
// Gtk UI Main function
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::Main( )
{
Reset( );
gtk_main();
g_print( "End of EmuGtk::Main( )\n" );
}
//////////////////////////////////////////////////////////////////////////////
// void EmuGtk::ShowMenu( )
// Show the menu
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::ShowMenu( )
{
FileMenu = gtk_menu_new( );
OpenItem = gtk_menu_item_new_with_label( "Open" );
QuitItem = gtk_menu_item_new_with_label( "Quit" );
gtk_menu_append( GTK_MENU( FileMenu ), GTK_WIDGET( OpenItem ) );
gtk_menu_append( GTK_MENU( FileMenu ), GTK_WIDGET( QuitItem ) );
gtk_widget_show( GTK_WIDGET( OpenItem ) );
gtk_widget_show( GTK_WIDGET( QuitItem ) );
ViewMenu = gtk_menu_new( );
ExtMemItem = gtk_menu_item_new_with_label( "External Memory Dump" );
IntMemItem = gtk_menu_item_new_with_label( "Internal Memory Dump" );
//PgmMemItem = gtk_menu_item_new_with_label( "Program Memory Dump" );
gtk_menu_append( GTK_MENU( ViewMenu ), GTK_WIDGET( ExtMemItem ) );
gtk_menu_append( GTK_MENU( ViewMenu ), GTK_WIDGET( IntMemItem ) );
//gtk_menu_append( GTK_MENU( ViewMenu ), GTK_WIDGET( PgmMemItem ) );
gtk_widget_show( GTK_WIDGET( ExtMemItem ) );
gtk_widget_show( GTK_WIDGET( IntMemItem ) );
//gtk_widget_show( GTK_WIDGET( PgmMemItem ) );
HelpMenu = gtk_menu_new( );
AboutItem = gtk_menu_item_new_with_label( "About" );
gtk_menu_append( GTK_MENU( HelpMenu ), GTK_WIDGET( AboutItem ) );
gtk_widget_show( GTK_WIDGET( AboutItem ) );
MenuBar = gtk_menu_bar_new( );
gtk_fixed_put( GTK_FIXED( emufixed ), MenuBar, 0, 0 );
gtk_widget_show( GTK_WIDGET( MenuBar ) );
FileItem = gtk_menu_item_new_with_label( "File" );
ViewItem = gtk_menu_item_new_with_label( "View" );
HelpItem = gtk_menu_item_new_with_label( "Help" );
gtk_widget_show( GTK_WIDGET( FileItem ) );
gtk_widget_show( GTK_WIDGET( ViewItem ) );
gtk_widget_show( GTK_WIDGET( HelpItem ) );
gtk_menu_item_set_submenu( GTK_MENU_ITEM( FileItem ), FileMenu );
gtk_menu_item_set_submenu( GTK_MENU_ITEM( ViewItem ), ViewMenu );
gtk_menu_item_set_submenu( GTK_MENU_ITEM( HelpItem ), HelpMenu );
gtk_menu_bar_append( GTK_MENU_BAR( MenuBar ), FileItem );
gtk_menu_bar_append( GTK_MENU_BAR( MenuBar ), ViewItem );
gtk_menu_bar_append( GTK_MENU_BAR( MenuBar ), HelpItem );
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtk::DeleteEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
// Signal DeleteEvent
//////////////////////////////////////////////////////////////////////////////
gboolean EmuGtk::DeleteEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
{
g_print( "EmuGtk::DeleteEvent(...)\n" );
StopRunning( );
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtk::DestroyEvent( GtkWidget *widget, gpointer data )
// Signal DestroyEvent
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::DestroyEvent( GtkWidget *widget, gpointer data )
{
g_print( "EmuGtk::DestroyEvent(...)\n" );
gtk_main_quit();
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtk::AboutEvent( GtkWidget *widget, gpointer data )
// Signal AboutEvent ( Help->About in menu )
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::AboutEvent( GtkWidget *widget, gpointer data )
{
char about_string[256];
GtkWidget *about_window;
GtkWidget *text_window;
sprintf( about_string, "%s\n\nversion %s\n\n\nAuthors:\nHugo Villeneuve\nJonathan St-André\n", PACKAGE, VERSION );
about_window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
gtk_window_set_title( GTK_WINDOW( about_window ), "About" );
gtk_container_set_border_width( GTK_CONTAINER( about_window ), 20 );
text_window = gtk_label_new( about_string );
gtk_container_add( GTK_CONTAINER( about_window ), text_window );
gtk_widget_show_all( GTK_WIDGET( about_window ) );
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtk::OpenEvent( GtkWidget *widget, gpointer data )
// Signal OpenEvent ( File->Open in menu )
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::OpenEvent( GtkWidget *widget, gpointer data )
{
GtkWidget *FileOpendialog;
// g_print( "EmuGtk::OpenEvent(...)\n" );
FileOpendialog = gtk_file_selection_new( "Open Intel Hex file" );
// Connect the file dialog's OK button up to a handler.
gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION ( FileOpendialog ) -> ok_button ),
"clicked",
GTK_SIGNAL_FUNC( FileOpenDialog_OK ),
FileOpendialog );
// Connect the file dialog's CANCEL button up to a handler.
gtk_signal_connect( GTK_OBJECT( GTK_FILE_SELECTION ( FileOpendialog ) -> cancel_button ),
"clicked",
GTK_SIGNAL_FUNC( FileOpenDialog_CANCEL ),
FileOpendialog );
// Set the 'File Open dialog' to show only Intel HEX files (.hex).
// gtk_file_selection_complete( GTK_FILE_SELECTION( FileOpendialog ), "*.hex" );
// Show the dialog
gtk_widget_show( GTK_WIDGET( FileOpendialog ) );
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
void FileOpenDialog_OK( GtkButton *button, gpointer data )
{
g_print( "EmuGtk::FileOpenDialog_OK Event(...)\n" );
const gchar *SelectedFile;
SelectedFile = gtk_file_selection_get_filename ( GTK_FILE_SELECTION ( data ) );
g_print( "EmuGtk::File = %s\n", SelectedFile );
EmuGtkPtr->StopRunning( );
EmuGtkPtr->LoadHexFile( SelectedFile );
gtk_widget_destroy( GTK_WIDGET( data ) );
EmuGtkPtr->Reset( );
EmuGtkPtr->UpdateDisplay();
}
void EmuGtk::UpdateDisplay( void )
{
regwin->Show( CPU );
pgmwin->Disasm( );
memwin->DumpD( CPU, 0 );
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
void FileOpenDialog_CANCEL( GtkButton *button, gpointer data )
{
g_print( "EmuGtk::FileOpenDialog_CANCEL Event(...)\n" );
gtk_widget_destroy( GTK_WIDGET( data ) );
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtk::QuitEvent( GtkWidget *widget, gpointer data )
// Signal QuitEvent ( File->Quit in menu )
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::QuitEvent( GtkWidget *widget, gpointer data )
{
g_print( "EmuGtk::QuitEvent(...)\n" );
StopRunning( );
gtk_main_quit( );
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtk::ResetEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
// Signal ResetEvent ( ResetButton )
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::ResetEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
{
g_print( "EmuGtk::ResetEvent(...)\n" );
StopRunning( );
Reset( );
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtk::RunEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
// Signal RunEvent ( RunButton )
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::RunEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
{
g_print( "EmuGtk::RunEvent(...)\n" );
if ( RunningState ) {
// g_print( "Getting out of RunningState! \n" );
StopRunning( );
}
else {
// g_print( "Going In RunningState! \n" );
StartRunning( );
}
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtk::StopEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
// Signal StopEvent ( StopButton )
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::StopEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
{
g_print( "EmuGtk::StopEvent(...)\n" );
StopRunning( );
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtk::StepEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
// Signal StepEvent ( StepButton )
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::StepEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
{
g_print( "EmuGtk::StepEvent(...)\n" );
StopRunning( );
Step( );
}
//////////////////////////////////////////////////////////////////////////////
// unsigned int EmuGtk::Ascii2Hex( string istring, int length = 0 )
// Convert an ascii string to an hexadecimal number
//////////////////////////////////////////////////////////////////////////////
unsigned int EmuGtk::Ascii2Hex( string istring, int length = 0 )
{
if ( !length || ( length > (int) istring.size() ) )
length = istring.size();
if ( istring.empty() )
throw MissingParameter();
unsigned int result = 0;
int i, ascii_code;
for ( i = 0; i < length; i++ ) {
ascii_code = istring[ i ];
if ( ascii_code > 0x39 )
ascii_code &= 0xDF;
if ( ( ascii_code >= 0x30 && ascii_code <= 0x39 ) || ( ascii_code >= 0x41 && ascii_code <= 0x46 ) ) {
ascii_code -= 0x30;
if ( ascii_code > 9 )
ascii_code -= 7;
result <<= 4;
result += ascii_code;
}
else {
throw SyntaxError();
}
}
return result;
}
//////////////////////////////////////////////////////////////////////////////
// void EmuGtk::LoadHexFile( string Filename )
// Load an HEX file into program memory
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::LoadHexFile( string Filename )
{
printf("LoadHex\n");
int i, j, RecLength, LoadOffset, RecType, Data, Checksum;
char Line[ 250 ];
ifstream HexFile( Filename.c_str() );
try {
if ( ! HexFile )
throw ErrorOpeningFile();
while( ! HexFile.eof() ) {
i = 0;
Checksum = 0;
HexFile.getline( Line, 250, '\n' );
if ( Line[ i++ ] != ':' )
throw ErrorHexFileFormat();
RecLength = Ascii2Hex( &Line[ i ], 2 );
i += 2;
Checksum += RecLength;
LoadOffset = Ascii2Hex( &Line[i], 4 );
Checksum += LoadOffset / 256;
Checksum += LoadOffset % 256;
i += 4;
RecType = Ascii2Hex( &Line[i],2);
i += 2;
Checksum += RecType;
if ( RecType == 1 ) {
Checksum += Ascii2Hex( &Line[ i ], 2 );
if ( Checksum &= 0x000000FF )
throw ErrorHexFileFormat();
throw FinishedLoading();
}
if ( RecType )
throw ErrorHexFileFormat();
for ( j = 0; j < RecLength; j++ ) {
Data = Ascii2Hex( &Line[ i ], 2 );
CPU->WritePGM( (unsigned int)(LoadOffset + j), (unsigned char)Data );
i += 2;
Checksum += Data;
}
RecType = Ascii2Hex( &Line[ i ], 2 );
Checksum += RecType;
if ( Checksum &= 0x000000FF )
throw ErrorHexFileFormat();
}
throw ErrorHexFileFormat();
}
catch ( ErrorOpeningFile ) {
cout << "Error opening file " << Filename << endl;
}
catch ( ErrorHexFileFormat ) {
cout << "Invalid format for " << Filename << " file..." << endl;
}
catch ( SyntaxError ) {
cout << "Invalid format for " << Filename << " file..." << endl;
}
catch ( MissingParameter ) {
cout << "Invalid format for " << Filename << " file..." << endl;
}
catch ( FinishedLoading ) {
cout << "Using file " << Filename << " as input program." << endl;
}
HexFile.close();
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtkSignalStub2( GtkWidget *widget, gpointer data )
// Signal Stub with 2 parameters
//////////////////////////////////////////////////////////////////////////////
void EmuGtkSignalStub2( GtkWidget *widget, gpointer data )
{
//g_print( "EmuGtkSignalStub2(...)\n");
int SigNumber = (* ( static_cast< int * >( data ) ) );
switch( SigNumber )
{
case DestroySignal:
EmuGtkPtr->DestroyEvent( widget, 0 );
break;
case AboutISignal:
EmuGtkPtr->AboutEvent( widget, 0 );
break;
case OpenISignal:
EmuGtkPtr->OpenEvent( widget, 0 );
break;
case QuitISignal:
EmuGtkPtr->QuitEvent( widget, 0 );
break;
default:
g_print( "*** error: EmuGtkSignalStub2: default case reached\n" );
break;
};
}
//////////////////////////////////////////////////////////////////////////////
// gint EmuGtkSignalStub3( GtkWidget *widget, GdkEvent *event, gpointer data )
// Signal Stub with 3 parameters
//////////////////////////////////////////////////////////////////////////////
void EmuGtkSignalStub3( GtkWidget *widget, GdkEvent *event, gpointer data )
{
//g_print( "EmuGtkSignalStub3(...)\n");
int SigNumber = (* ( static_cast< int * >( data ) ) );
switch( SigNumber )
{
case DeleteSignal:
EmuGtkPtr->DeleteEvent( widget, event, 0 );
break;
case ResetBSignal:
EmuGtkPtr->ResetEvent( widget, event, 0 );
break;
case RunBSignal:
EmuGtkPtr->RunEvent( widget, event, 0 );
break;
case StopBSignal:
EmuGtkPtr->StopEvent( widget, event, 0 );
break;
case StepBSignal:
EmuGtkPtr->StepEvent( widget, event, 0 );
break;
default:
g_print( "*** error: EmuGtkSignalStub3: default case reached\n" );
break;
};
}
//////////////////////////////////////////////////////////////////////////////
// void EmuGtk::Running( )
// Running called by RunningFunction( )
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::Running( )
{
CPU->Exec( );
if ( pgmwin->IsBreakpoint( CPU->GetPC( ) ) ) {
g_print( "Breakpoint Hit, stopping!\n" );
StopRunning( );
}
}
//////////////////////////////////////////////////////////////////////////////
// gint RunningFunction( )
// RunningFunction called when idle from gtk_main
//////////////////////////////////////////////////////////////////////////////
gint RunningFunction( )
{
EmuGtkPtr->Running( );
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
// void EmuGtk::StartRunning( )
// Get in the RunningState
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::StartRunning( )
{
if ( !RunningState ) {
printf( "EmuGtk::StartRunning( )\n" );
RunFuncTag = gtk_idle_add( GtkFunction( RunningFunction ),0 );
RunningState = 1;
// gtk_widget_hide( GTK_WIDGET( ButtonRun ) );
// gtk_widget_show_now( GTK_WIDGET( ButtonStop ) );
// gtk_table_attach_defaults( GTK_TABLE( ButtonTable ), ButtonStop, 3, 4, 0, 1);
}
}
//////////////////////////////////////////////////////////////////////////////
// void EmuGtk::StopRunning( )
// Step out of RunningState
//////////////////////////////////////////////////////////////////////////////
void EmuGtk::StopRunning( )
{
if (RunningState) {
printf( "EmuGtk::StopRunning( )\n" );
gtk_idle_remove( RunFuncTag );
RunningState = 0;
//gtk_widget_hide( GTK_WIDGET( ButtonStop ) );
//gtk_widget_show( GTK_WIDGET( ButtonRun ) );
// gtk_table_attach_defaults( GTK_TABLE( ButtonTable ), ButtonRun, 3, 4, 0, 1);
regwin->Show( CPU );
pgmwin->Disasm( );
memwin->DumpD( CPU, 0 );
}
}

View File

@ -1,111 +0,0 @@
#ifndef _EMUGTK_HPP_
#define _EMUGTK_HPP_
#include <gtk/gtk.h>
#include <string>
#include <fstream>
#include "CPU8051.hpp"
#include "MemWin.hpp"
#include "PgmWin.hpp"
#include "RegWin.hpp"
#include "GtkSizes.hpp"
#include "exceptions.hpp"
using namespace std;
//////////////////////////////////////////////////////////////////////////////
// EmuGtk
// Implements the Gtk+ Graphical User Interface as an Object
//////////////////////////////////////////////////////////////////////////////
class EmuGtk {
public:
EmuGtk( int argc , char **argv, CPU8051 *mCPU );
~EmuGtk( );
void Main( );
void Reset( );
void Step( );
// void Step( );
// void Exec( );
void AddButtons( );
void ShowMenu( );
gboolean DeleteEvent( GtkWidget *widget, GdkEvent *event, gpointer data );
void DestroyEvent( GtkWidget *widget, gpointer data );
void OpenEvent( GtkWidget *widget, gpointer data );
void QuitEvent( GtkWidget *widget, gpointer data );
void AboutEvent( GtkWidget *widget, gpointer data );
void ResetEvent( GtkWidget *widget, GdkEvent *event, gpointer data );
void RunEvent( GtkWidget *widget, GdkEvent *event, gpointer data );
void StopEvent( GtkWidget *widget, GdkEvent *event, gpointer data );
void StepEvent( GtkWidget *widget, GdkEvent *event, gpointer data );
void StartRunning( );
void StopRunning( );
void Running( );
void LoadHexFile( string Filename );
void UpdateDisplay();
private:
int EmuGtkID;
CPU8051 *CPU;
int RunningState;
int RunFuncTag;
MemWin *memwin;
PgmWin *pgmwin;
RegWin *regwin;
GtkWidget *emuwin, *emufixed, *emumainfixed;
GtkWidget *regfrm, *pgmfrm, *memfrm;
GtkWidget *ButtonTable;
// GdkPixmap *PixMapT, *PixMapRun, *PixMapR, *PixMapQ;
// GtkWidget *PixMapWidT, *PixMapWidRun, *PixMapWidR, *PixMapWidQ;
// GdkBitmap *mask;
GtkWidget *FileMenu, *OpenItem, *QuitItem, *FileItem;
GtkWidget *ViewMenu, *ExtMemItem, *IntMemItem, *ViewItem;
// GtkWidget *ViewMenu, *ExtMemItem, *IntMemItem, *PgmMemItem, *ViewItem;
GtkWidget *HelpMenu, *AboutItem, *LicenseItem, *HelpItem;
GtkWidget *MenuBar;
// RESET button
GdkBitmap *RESET_mask;
GdkPixmap *RESET_pixmap;
GtkWidget *RESET_widget;
GtkWidget *ButtonReset;
// RUN button
GdkBitmap *RUN_mask;
GdkPixmap *RUN_pixmap;
GtkWidget *RUN_widget;
GtkWidget *ButtonRun;
// STOP button
GdkBitmap *STOP_mask;
GdkPixmap *STOP_pixmap;
GtkWidget *STOP_widget;
GtkWidget *ButtonStop;
// STEP button
GdkBitmap *STEP_mask;
GdkPixmap *STEP_pixmap;
GtkWidget *STEP_widget;
GtkWidget *ButtonStep;
unsigned int Ascii2Hex( string istring, int length );
};
void EmuGtkSignalStub3( GtkWidget *widget, GdkEvent *event, gpointer data );
void EmuGtkSignalStub2( GtkWidget *widget, gpointer data );
void FileOpenDialog_OK( GtkButton *button, gpointer data );
void FileOpenDialog_CANCEL( GtkButton *button, gpointer data );
gint RunningFunction( );
#endif

View File

@ -1,24 +0,0 @@
#ifndef _GTKSIZES_HPP_
#define _GTKSIZES_HPP_
#define NUMBER_OF_BUTTONS 5
#define BUTTON_WIDTH 60
#define BUTTON_HEIGHT 60
#define BUTTONS_BAR_WIDTH (NUMBER_OF_BUTTONS * BUTTON_WIDTH)
#define BUTTONS_BAR_HEIGHT BUTTON_HEIGHT
#define REG_WIN_WIDTH 100
#define REG_WIN_HEIGHT 390
#define PGM_WIN_WIDTH 480
#define PGM_WIN_HEIGHT 390
#define MEM_WIN_WIDTH 590
#define MEM_WIN_HEIGHT 280
#define MENU_BAR_HEIGHT 0
#define MAIN_WIN_WIDTH (REG_WIN_WIDTH + PGM_WIN_WIDTH)
#define MAIN_WIN_HEIGHT (BUTTONS_BAR_HEIGHT + REG_WIN_HEIGHT + MEM_WIN_HEIGHT)
#endif

View File

@ -1,266 +0,0 @@
#ifndef __INST_DEF_HPP_
#define __INST_DEF_HPP_
// Do not modify this file directly, it was created by Opcode2cpp.pl
// Any modification made directly on this file will be lost
int OP_00( );
int OP_01( );
int OP_02( );
int OP_03( );
int OP_04( );
int OP_05( );
int OP_06( );
int OP_07( );
int OP_08( );
int OP_09( );
int OP_0A( );
int OP_0B( );
int OP_0C( );
int OP_0D( );
int OP_0E( );
int OP_0F( );
int OP_10( );
int OP_11( );
int OP_12( );
int OP_13( );
int OP_14( );
int OP_15( );
int OP_16( );
int OP_17( );
int OP_18( );
int OP_19( );
int OP_1A( );
int OP_1B( );
int OP_1C( );
int OP_1D( );
int OP_1E( );
int OP_1F( );
int OP_20( );
int OP_21( );
int OP_22( );
int OP_23( );
int OP_24( );
int OP_25( );
int OP_26( );
int OP_27( );
int OP_28( );
int OP_29( );
int OP_2A( );
int OP_2B( );
int OP_2C( );
int OP_2D( );
int OP_2E( );
int OP_2F( );
int OP_30( );
int OP_31( );
int OP_32( );
int OP_33( );
int OP_34( );
int OP_35( );
int OP_36( );
int OP_37( );
int OP_38( );
int OP_39( );
int OP_3A( );
int OP_3B( );
int OP_3C( );
int OP_3D( );
int OP_3E( );
int OP_3F( );
int OP_40( );
int OP_41( );
int OP_42( );
int OP_43( );
int OP_44( );
int OP_45( );
int OP_46( );
int OP_47( );
int OP_48( );
int OP_49( );
int OP_4A( );
int OP_4B( );
int OP_4C( );
int OP_4D( );
int OP_4E( );
int OP_4F( );
int OP_50( );
int OP_51( );
int OP_52( );
int OP_53( );
int OP_54( );
int OP_55( );
int OP_56( );
int OP_57( );
int OP_58( );
int OP_59( );
int OP_5A( );
int OP_5B( );
int OP_5C( );
int OP_5D( );
int OP_5E( );
int OP_5F( );
int OP_60( );
int OP_61( );
int OP_62( );
int OP_63( );
int OP_64( );
int OP_65( );
int OP_66( );
int OP_67( );
int OP_68( );
int OP_69( );
int OP_6A( );
int OP_6B( );
int OP_6C( );
int OP_6D( );
int OP_6E( );
int OP_6F( );
int OP_70( );
int OP_71( );
int OP_72( );
int OP_73( );
int OP_74( );
int OP_75( );
int OP_76( );
int OP_77( );
int OP_78( );
int OP_79( );
int OP_7A( );
int OP_7B( );
int OP_7C( );
int OP_7D( );
int OP_7E( );
int OP_7F( );
int OP_80( );
int OP_81( );
int OP_82( );
int OP_83( );
int OP_84( );
int OP_85( );
int OP_86( );
int OP_87( );
int OP_88( );
int OP_89( );
int OP_8A( );
int OP_8B( );
int OP_8C( );
int OP_8D( );
int OP_8E( );
int OP_8F( );
int OP_90( );
int OP_91( );
int OP_92( );
int OP_93( );
int OP_94( );
int OP_95( );
int OP_96( );
int OP_97( );
int OP_98( );
int OP_99( );
int OP_9A( );
int OP_9B( );
int OP_9C( );
int OP_9D( );
int OP_9E( );
int OP_9F( );
int OP_A0( );
int OP_A1( );
int OP_A2( );
int OP_A3( );
int OP_A4( );
int OP_A5( );
int OP_A6( );
int OP_A7( );
int OP_A8( );
int OP_A9( );
int OP_AA( );
int OP_AB( );
int OP_AC( );
int OP_AD( );
int OP_AE( );
int OP_AF( );
int OP_B0( );
int OP_B1( );
int OP_B2( );
int OP_B3( );
int OP_B4( );
int OP_B5( );
int OP_B6( );
int OP_B7( );
int OP_B8( );
int OP_B9( );
int OP_BA( );
int OP_BB( );
int OP_BC( );
int OP_BD( );
int OP_BE( );
int OP_BF( );
int OP_C0( );
int OP_C1( );
int OP_C2( );
int OP_C3( );
int OP_C4( );
int OP_C5( );
int OP_C6( );
int OP_C7( );
int OP_C8( );
int OP_C9( );
int OP_CA( );
int OP_CB( );
int OP_CC( );
int OP_CD( );
int OP_CE( );
int OP_CF( );
int OP_D0( );
int OP_D1( );
int OP_D2( );
int OP_D3( );
int OP_D4( );
int OP_D5( );
int OP_D6( );
int OP_D7( );
int OP_D8( );
int OP_D9( );
int OP_DA( );
int OP_DB( );
int OP_DC( );
int OP_DD( );
int OP_DE( );
int OP_DF( );
int OP_E0( );
int OP_E1( );
int OP_E2( );
int OP_E3( );
int OP_E4( );
int OP_E5( );
int OP_E6( );
int OP_E7( );
int OP_E8( );
int OP_E9( );
int OP_EA( );
int OP_EB( );
int OP_EC( );
int OP_ED( );
int OP_EE( );
int OP_EF( );
int OP_F0( );
int OP_F1( );
int OP_F2( );
int OP_F3( );
int OP_F4( );
int OP_F5( );
int OP_F6( );
int OP_F7( );
int OP_F8( );
int OP_F9( );
int OP_FA( );
int OP_FB( );
int OP_FC( );
int OP_FD( );
int OP_FE( );
int OP_FF( );
void InitFuncPtr( );
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +0,0 @@
// Keyboard.hpp
#ifndef _KEYBOARD_HPP_
#define _KEYBOARD_HPP_
#include <termios.h>
#include <unistd.h>
static struct termios orig, newtio;
static int peek = -1;
int kbhit()
{
char ch;
int nread;
if(peek != -1) return 1;
newtio.c_cc[VMIN]=0;
tcsetattr(0, TCSANOW, &newtio);
nread = read(0,&ch,1);
newtio.c_cc[VMIN]=1;
tcsetattr(0, TCSANOW, &newtio);
if(nread == 1) {
peek = ch;
return 1;
}
return 0;
}
int getch()
{
char ch;
if(peek != -1) {
ch = peek;
peek = -1;
return ch;
}
read(0,&ch,1);
return ch;
}
void InitUnixKB( )
{
tcgetattr(0, &orig);
newtio = orig;
newtio.c_lflag &= ~ICANON;
newtio.c_lflag &= ~ECHO;
newtio.c_lflag &= ~ISIG;
newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &newtio);
}
void ResetUnixKB( )
{
tcsetattr(0,TCSANOW, &orig);
}
#endif

View File

@ -1,37 +0,0 @@
# This file is processed by GNU automake to generate Makefile.in
INCLUDES = -I$(top_srcdir)/pixmaps
bin_PROGRAMS = emu8051 emu8051_console
emu8051_SOURCES = EmuGtk.hpp EmuGtk.cpp CPU8051.hpp CPU8051.cpp Memory.hpp Memory.cpp \
MemWin.hpp MemWin.cpp PgmWin.hpp PgmWin.cpp RegWin.hpp RegWin.cpp
emu8051_console_SOURCES = EmuConsole.hpp EmuConsole.cpp CPU8051.hpp CPU8051.cpp Memory.hpp \
Memory.cpp Keyboard.hpp
# These headers will be included in the distribution tarball, but will not be
# installed by 'make install'
noinst_HEADERS = Inst_Def.hpp EmuConsole.hpp Keyboard.hpp Reg8051.hpp GtkSizes.hpp disasm.hpp \
exceptions.hpp
CLEANFILES = *~
DISTCLEANFILES = .deps/*.P
MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = Opcode2cpp.pl opcodes.lst Inst_Imp.cpp
# This rule is used to bypass the default rule which is generated by Automake, in order
# to get rid of all the cluttered informations that are displayed by Make before
# calling the compiler like in the following example:
# source='programming.c' object='programming.o' libtool=no \
# depfile='.deps/programming.Po' tmpdepfile='.deps/programming.TPo' \
# depmode=gcc3 /bin/sh ../config/depcomp \
# gcc -DHAVE_CONFIG_H -I. -I. -I.. -c `test -f 'main.c' || echo './'`main.c
.c.o:
$(COMPILE) -c $<
.cpp.o:
$(CXXCOMPILE) -c $<

View File

@ -1,128 +0,0 @@
/* memwin.cpp */
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include "MemWin.hpp"
#include <stdio.h>
//////////////////////////////////////////////////////////////////////////////
// MemWin::MemWin( GtkWidget *parentwin )
// MemWin constructor
//////////////////////////////////////////////////////////////////////////////
MemWin::MemWin( GtkWidget *parentwin )
{
int i;
GtkStyle *style;
GdkFont *fixedfont;
fixedfont = gdk_font_load( "-adobe-courier-medium-r-normal--12-120-75-75-m-70-iso8859-1" );
memclist = gtk_clist_new( 18 );
gtk_clist_set_selection_mode( GTK_CLIST( memclist ), GTK_SELECTION_SINGLE );
gtk_widget_set_usize( GTK_WIDGET( memclist ), 620, 250 );
for ( i = 0; i < 18; i++ ) gtk_clist_set_column_justification( GTK_CLIST( memclist ), i, GTK_JUSTIFY_LEFT );
gtk_clist_set_column_width( GTK_CLIST( memclist ), 0, 5*8 );
for ( i = 1; i < 17; i++ ) gtk_clist_set_column_width( GTK_CLIST( memclist ), i, 2*8 );
gtk_clist_set_column_width( GTK_CLIST( memclist ), 17, 16*8 );
style = gtk_widget_get_style( GTK_WIDGET( memclist ) );
#ifdef USE_GTK2
gtk_style_set_font( style, fixedfont );
#else
style->font = fixedfont;
#endif
gtk_widget_set_style( GTK_WIDGET( memclist ), style );
char *memdummy[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
for ( i = 0; i < 16; i++ ) gtk_clist_append( GTK_CLIST( memclist ), memdummy );
gtk_container_add( GTK_CONTAINER( parentwin ), memclist );
gtk_widget_show( memclist );
}
//////////////////////////////////////////////////////////////////////////////
// MemWin::~MemWin( )
// MemWin destructor
//////////////////////////////////////////////////////////////////////////////
MemWin::~MemWin( )
{
}
//////////////////////////////////////////////////////////////////////////////
// void MemWin::DumpD( CPU8051 *mCPU, unsigned int Address )
// Dump 16 rows of 16 bytes from Address in Memory (direct addressing)
//////////////////////////////////////////////////////////////////////////////
void MemWin::DumpD( CPU8051 *mCPU, unsigned int Address)
{
char TextTmp[255];
int row, column, TextLength;
gtk_clist_freeze( GTK_CLIST( memclist ) );
for ( row = 0; row < 16; row++ ) {
sprintf( TextTmp, "%.4X", Address );
gtk_clist_set_text( GTK_CLIST( memclist ), row, 0, TextTmp );
for ( column = 0; column < 16; column++ ) {
sprintf( TextTmp, "%.2X", ( int ) mCPU->ReadD( Address + column ) );
gtk_clist_set_text( GTK_CLIST( memclist ), row, column + 1, TextTmp );
}
TextLength = 0;
for ( column = 0; column < 16; column++ ) {
if ( ( ( int ) mCPU->ReadD( Address + column ) >= 32 ) && ( ( int ) mCPU->ReadD( Address + column ) <= 126 ) )
TextLength += sprintf( &TextTmp[ TextLength ], "%c", mCPU->ReadD( Address + column ) );
else TextLength += sprintf( &TextTmp[ TextLength ], "." );
}
gtk_clist_set_text( GTK_CLIST( memclist ), row, 17, TextTmp );
Address += 16;
}
gtk_clist_select_row( GTK_CLIST( memclist ), 0, 0 );
gtk_clist_thaw( GTK_CLIST( memclist ) );
}
//////////////////////////////////////////////////////////////////////////////
// void MemWin::DumpI( CPU8051 *mCPU, unsigned int Address )
// Dump 16 rows of 16 bytes from Address in Memory (indirect addressing)
//////////////////////////////////////////////////////////////////////////////
void MemWin::DumpI( CPU8051 *mCPU, unsigned int Address)
{
char TextTmp[255];
int row, column, TextLength;
gtk_clist_freeze( GTK_CLIST( memclist ) );
for ( row = 0; row < 16; row++ ) {
sprintf( TextTmp, "%.4X", Address );
gtk_clist_set_text( GTK_CLIST( memclist ), row, 0, TextTmp );
for ( column = 0; column < 16; column++ ) {
sprintf( TextTmp, "%.2X", ( int ) mCPU->ReadI( Address + column ) );
gtk_clist_set_text( GTK_CLIST( memclist ), row, column + 1, TextTmp );
}
TextLength = 0;
for ( column = 0; column < 16; column++ ) {
if ( ( ( int ) mCPU->ReadI( Address + column ) >= 32 ) && ( ( int ) mCPU->ReadI( Address + column ) <= 126 ) )
TextLength += sprintf( &TextTmp[ TextLength ], "%c", mCPU->ReadI( Address + column ) );
else TextLength += sprintf( &TextTmp[ TextLength ], "." );
}
gtk_clist_set_text( GTK_CLIST( memclist ), row, 17, TextTmp );
Address += 16;
}
gtk_clist_thaw( GTK_CLIST( memclist ) );
}

View File

@ -1,29 +0,0 @@
#ifndef _MEMWIN_HPP_
#define _MEMWIN_HPP_
#include <gtk/gtk.h>
#include "CPU8051.hpp"
//////////////////////////////////////////////////////////////////////////////
// MemWin
// Implements a memory Window in Gtk+ as an Object
//////////////////////////////////////////////////////////////////////////////
class MemWin {
public:
MemWin( GtkWidget *parentwin );
~MemWin( );
void DumpD( CPU8051 *mCPU, unsigned int Address );
void DumpI( CPU8051 *mCPU, unsigned int Address );
private:
GtkWidget *memwin;
GtkWidget *memclist;
};
#endif

View File

@ -1,51 +0,0 @@
#include "Memory.hpp"
//////////////////////////////////////////////////////////////////////////////
// Memory::Memory( unsigned long MemSize )
// Memory object constructor
//////////////////////////////////////////////////////////////////////////////
Memory::Memory( unsigned long MemSize )
{
memsize = MemSize;
memarray = new unsigned char[memsize];
}
//////////////////////////////////////////////////////////////////////////////
// Memory::~Memory( )
// Memory object destructor
//////////////////////////////////////////////////////////////////////////////
Memory::~Memory( )
{
delete[] memarray;
memarray = 0;
memsize = 0;
}
//////////////////////////////////////////////////////////////////////////////
// unsigned long Memory::GetSize( )
// Get Memory size
//////////////////////////////////////////////////////////////////////////////
unsigned long Memory::GetSize( )
{
return memsize;
}
//////////////////////////////////////////////////////////////////////////////
// void Memory::Write8( unsigned long Address, unsigned char Value )
// Write 8-bit Value at Address into Memory
//////////////////////////////////////////////////////////////////////////////
void Memory::Write8( unsigned long Address, unsigned char Value )
{
if (Address >= memsize) return;
memarray[Address] = Value;
}
//////////////////////////////////////////////////////////////////////////////
// unsigned char Memory::Read8( unsigned long Address )
// Read 8-bit value at Address in Memory
//////////////////////////////////////////////////////////////////////////////
unsigned char Memory::Read8( unsigned long Address )
{
if (Address < memsize) { return memarray[Address]; }
return 0;
}

View File

@ -1,24 +0,0 @@
#ifndef _MEMORY_HPP_
#define _MEMORY_HPP_
//////////////////////////////////////////////////////////////////////////////
// Memory
// Implements a Memory array to be used by the CPU8051 as an Object
//////////////////////////////////////////////////////////////////////////////
class Memory {
public:
Memory( unsigned long MemSize );
~Memory( );
unsigned long GetSize( );
void Write8( unsigned long Address, unsigned char Value );
unsigned char Read8( unsigned long Address );
unsigned char *memarray;
unsigned long memsize;
};
#endif

View File

@ -1,785 +0,0 @@
#!/usr/bin/perl
open INST_DEF,">Inst_Def.hpp" or die "Erreur ouverture Inst_Def.hpp : $!\n";
open INST_IMP,">Inst_Imp.cpp" or die "Erreur ouverture Inst_Imp.hpp : $!\n";
open OPCODELST,"opcodes.lst" or die "Erreur ouverture opcodes.lst : $!\n";
open DISASM_HPP,">disasm.hpp" or die "Erreur ouverture disasm.hpp : $!\n";
print INST_IMP "#ifndef __INST_IMP_HPP_\n";
print INST_IMP "#define __INST_IMP_HPP_\n\n";
print INST_IMP "// Do not modify this file directly, it was created by Opcode2cpp.pl\n";
print INST_IMP "// Any modification made directly on this file will be lost\n\n\n";
print INST_DEF "#ifndef __INST_DEF_HPP_\n";
print INST_DEF "#define __INST_DEF_HPP_\n";
print INST_DEF "// Do not modify this file directly, it was created by Opcode2cpp.pl\n";
print INST_DEF "// Any modification made directly on this file will be lost\n\n\n";
print DISASM_HPP "#ifndef __DISASM_HPP_\n";
print DISASM_HPP "#define __DISASM_HPP_\n";
print DISASM_HPP "// Do not modify this file directly, it was created by Opcode2cpp.pl\n";
print DISASM_HPP "// Any modification made directly on this file will be lost\n\n\n";
$nbinst=0;
$nbaddr=0;
$nbargs=0;
$instnumb=0;
$ligne=<OPCODELST>;
$ligne=<OPCODELST>;
while($ligne=<OPCODELST>) {
chop $ligne;
if (length $ligne < 2) {next;}
@wordlist=split ' ',$ligne;
$nbword=@wordlist;
$instruction=$wordlist[2];
for($i=3;$i<($nbword-2);$i++) {$instruction="$instruction $wordlist[$i]";}
$a_instruction[$instnumb]=$instruction;
$a_bytes[$instnumb]=$wordlist[$nbword-2];
$a_cycles[$instnumb]=$wordlist[$nbword-1];
$a_opcodehex[$instnumb]=$wordlist[1];
$a_opcodebin[$instnumb]=$wordlist[0];
$instfunction[$instnumb]="CPU8051::OP_$wordlist[1]";
$instargs[$instnumb << 2]=$instargs[($instnumb << 2) + 1]=$instargs[($instnumb << 2) + 2]=$instargs[($instnumb << 2) + 3]=0;
if ($nbword > 5) {
@argslist=split /\,/,$wordlist[3];
$argslistsize=@argslist;
$instargs[$instnumb << 2]=$argslistsize;
for ($i=0;$i<$argslistsize;$i++) {
if (not exists $argstypes{$argslist[$i]}) {
$argstypes[$nbargs]=$argslist[$i];
$argstypes{$argslist[$i]}=$nbargs++;
}
$instargs[($instnumb << 2) + $i + 1]=$argstypes{$argslist[$i]};
}
}
if (not exists $insttext{$wordlist[2]}) {
$insttext[$nbinst]=$wordlist[2];
$insttext{$wordlist[2]}=$nbinst++;
}
$insttype[$instnumb]=$insttext{$wordlist[2]};
if ( not exists $addrmode{$wordlist[3]}) {
$addrmode[$nbaddr]=$wordlist[3];
$addrmode{$wordlist[3]}=$nbaddr++;
}
$nbbytes[$instnumb]=$wordlist[$nbword-2];
$instaddr[$instnumb]=$addrmode{$wordlist[3]};
$instnumb++;
}
# ------------------------------------------------------------------------------
print DISASM_HPP "// For all 256 opcodes, the value in this table gives the instruction type\n";
print DISASM_HPP "// ex.: MOV, INC, CLR, CPL,...\n";
print DISASM_HPP "// To know what is the instruction type, use the number as an offset in the InstTextTbl[]\n";
print DISASM_HPP "static int InstTypesTbl[] = {\n";
for($i=0;$i<256;$i++) {
print DISASM_HPP " $insttype[$i]";
($i != 255) and print DISASM_HPP ",";
if (($i+1) % 16 == 0) { print DISASM_HPP "\n"; }
}
print DISASM_HPP "};\n";
print DISASM_HPP "\n\n";
# ------------------------------------------------------------------------------
print DISASM_HPP "// Size(in bytes) of each instruction (offset in table is instruction opcode)\n";
print DISASM_HPP "static int InstSizesTbl[] = {\n";
for($i=0;$i<256;$i++) {
print DISASM_HPP " $nbbytes[$i]";
($i != 255) and print DISASM_HPP ",";
if (($i+1) % 16 == 0) { print DISASM_HPP "\n"; }
}
print DISASM_HPP "};\n";
print DISASM_HPP "\n\n";
# ------------------------------------------------------------------------------
print DISASM_HPP "// List of instructions types referenced by InstTypesTbl[]\n";
$nbelement=@insttext;
print DISASM_HPP "\#define InstTextTblLength $nbelement\n";
$elementnb=0;
print DISASM_HPP "static char *InstTextTbl[] = {\n";
foreach $instruc (@insttext) {
print DISASM_HPP " \"$instruc\"";
($elementnb++ < $nbelement-1) and print DISASM_HPP ",";
print DISASM_HPP "\n";
}
print DISASM_HPP "};\n";
print DISASM_HPP "\n\n";
# ------------------------------------------------------------------------------
print DISASM_HPP "// Table describing all arguments types of an instruction\n";
print DISASM_HPP "// The table is indexed InstArgTbl[ opcode * 4]\n";
print DISASM_HPP "// InstArgTbl[opcode*4 + 1] gives the number of arguments the instruction has\n";
print DISASM_HPP "// InstArgTbl[opcode*4 + i] for i=1,2 and 3 give the type of each argument\n";
print DISASM_HPP "// for most instructions, the 3rd argument isn't used\n";
print DISASM_HPP "// the argument type is referecing to ArgsTextTbl[]\n";
print DISASM_HPP "\#define InstArgTblLength 256\n";
print DISASM_HPP "static int InstArgTbl[] = {\n";
for($i=0;$i<1024;$i++) {
print DISASM_HPP " $instargs[$i]";
($i != 1023) and print DISASM_HPP ",";
if (($i+1) % 16 == 0) { print DISASM_HPP "\n"; }
}
print DISASM_HPP "};\n";
print DISASM_HPP "\n\n";
# ------------------------------------------------------------------------------
print DISASM_HPP "// List all types of arguments available to instructions\n";
print DISASM_HPP "// Referenced by InstArgsTbl[]\n";
$nbelement=@argstypes;
print DISASM_HPP "\#define ArgsTextTblLength $nbelement\n";
$elementnb=0;
print DISASM_HPP "static char *ArgsTextTbl[] = {\n";
foreach $args (@argstypes) {
print DISASM_HPP " \"$args\"";
($elementnb++ < $nbelement-1) and print DISASM_HPP ",";
print DISASM_HPP "\n";
}
print DISASM_HPP "};\n";
print DISASM_HPP "\n\n";
# ------------------------------------------------------------------------------
for ($i=0 ; $i< 256; $i++) {
print INST_IMP "/"x78,"\n";
print INST_IMP "// void CPU8051::OP_$a_opcodehex[$i]( )\n";
print INST_IMP "// Instruction \"$a_instruction[$i]\" takes $a_cycles[$i] cycle(s) and $a_bytes[$i] byte(s)\n";
print INST_IMP "/"x78,"\n";
print INST_IMP "int CPU8051::OP_$a_opcodehex[$i]( )\n";
print INST_DEF "int OP_$a_opcodehex[$i]( );\n";
print INST_IMP "{\n";
if ($i == 0x85) {
# Cas particulier pour MOV direct,direct -> src et dest sont inverses dans la memoire
print INST_IMP "unsigned char srcaddr = PGMMem->Read8( PC++ );\n";
print INST_IMP "unsigned char source = ReadD( srcaddr );\n";
print INST_IMP "unsigned char destaddr = PGMMem->Read8( PC++ );\n";
print INST_IMP "unsigned char destination = ReadD( destaddr );\n";
print INST_IMP "destination = source;\n";
print INST_IMP "WriteD( destaddr, destination );\n";
} else {
if ($instargs[$i*4] > 0) {
$op_destination=$instargs[$i*4+1];
if ($op_destination == 0) { # addr11
print INST_IMP "unsigned int addr11 = ( ( PGMMem->Read8( PC - 1 ) << 3 ) & 0xF00 ) + PGMMem->Read8( PC++ );\n";
}
if ($op_destination == 1) { # addr16
print INST_IMP "unsigned int addr16 = ( PGMMem->Read8( PC++ ) << 8 );\n";
print INST_IMP "addr16 += PGMMem->Read8( PC++ );\n";
}
if ($op_destination == 2) { # A
print INST_IMP "unsigned char destination = ReadD( _ACC_ );\n";
}
if ($op_destination == 3) { # direct
print INST_IMP "unsigned char destaddr = PGMMem->Read8( PC++ );\n";
print INST_IMP "unsigned char destination = ReadD( destaddr );\n";
}
if ($op_destination == 4) { # @R0
print INST_IMP "unsigned char destination = ReadI ( ReadD( BANKPSW + _R0_ ) );\n";
}
if ($op_destination == 5) { # @R1
print INST_IMP "unsigned char destination = ReadI ( ReadD( BANKPSW + _R1_ ) );\n";
}
if ($op_destination == 6) { # R0
print INST_IMP "unsigned char destination = ReadD( BANKPSW + _R0_ );\n";
}
if ($op_destination == 7) { # R1
print INST_IMP "unsigned char destination = ReadD( BANKPSW + _R1_ );\n";
}
if ($op_destination == 8) { # R2
print INST_IMP "unsigned char destination = ReadD( BANKPSW + _R2_ );\n";
}
if ($op_destination == 9) { # R3
print INST_IMP "unsigned char destination = ReadD( BANKPSW + _R3_ );\n";
}
if ($op_destination == 10) { # R4
print INST_IMP "unsigned char destination = ReadD( BANKPSW + _R4_ );\n";
}
if ($op_destination == 11) { # R5
print INST_IMP "unsigned char destination = ReadD( BANKPSW + _R5_ );\n";
}
if ($op_destination == 12) { # R6
print INST_IMP "unsigned char destination = ReadD( BANKPSW + _R6_ );\n";
}
if ($op_destination == 13) { # R7
print INST_IMP "unsigned char destination = ReadD( BANKPSW + _R7_ );\n";
}
if ($op_destination == 14) { # bitaddr
print INST_IMP "unsigned char destination, dstbitaddr = PGMMem->Read8( PC++ );\n";
print INST_IMP "destination = ReadB( dstbitaddr );\n";
}
if ($op_destination == 15) { # reladdr
print INST_IMP "PC++;\n";
print INST_IMP "unsigned int destination = ( ( PGMMem->Read8( PC - 1 ) + PC ) & 0xFF ) + ( PC & 0xFF00 );\n";
}
if ($op_destination == 16) { # #data
print INST_IMP "unsigned char destination = PGMMem->Read8( PC++ );\n";
}
if ($op_destination == 17) { # C
print INST_IMP "unsigned char destination = ( ReadD( _PSW_ ) >> 7 );\n";
}
if ($op_destination == 18) { # @A+DPTR
print INST_IMP "unsigned int destination = ReadI( ReadD( _ACC_ ) + ReadD( _DPTRLOW_ ) + ( ReadD( _DPTRHIGH_ ) << 8 ) );\n";
}
# Mis en commentaire car donnait un warning (destination et source unused variables...)
# if ($op_destination == 20) { # AB
# print INST_IMP "unsigned char destination = ReadD( _ACC_ );\n";
# print INST_IMP "unsigned char source = ReadD( _B_ );\n";
# }
if ($op_destination == 21) { # DPTR
print INST_IMP "unsigned int destination = ( ReadD( _DPTRHIGH_ ) << 8 ) + ReadD( _DPTRLOW_ );\n";
}
if ($op_destination == 22) { # #data16
print INST_IMP "unsigned char destination = ( PGMMem->Read8( PC++ ) << 8 );\n";
print INST_IMP "destination += PGMMem->Read8( PC++ );\n";
}
if ($op_destination == 23) { # /bitaddr
print INST_IMP "unsigned char destination, dstbitaddr = PGMMem->Read8( PC++ );\n";
print INST_IMP "destination = ( ReadB( dstbitaddr ) ^ 1 );\n";
}
if ($op_destination == 24) { # @DPTR
print INST_IMP "unsigned char destination = ReadI( ( ReadD( _DPTRHIGH_ ) << 8 ) + ReadD( _DPTRLOW_) );\n";
}
}
if ($instargs[$i*4] > 1) {
$op_source=$instargs[$i*4+2];
if ($op_source == 0) { # addr11
print INST_IMP "unsigned int addr11 = ( ( PGMMem->Read8( PC - 1 ) << 3 ) & 0xF00 ) + PGMMem->Read8( PC++ );\n";
}
if ($op_source == 1) { # addr16
print INST_IMP "unsigned int addr16 = ( PGMMem->Read8( PC++ ) << 8 );\n";
print INST_IMP "addr16 += PGMMem->Read8( PC++ );\n";
}
if ($op_source == 2) { # A
print INST_IMP "unsigned char source = ReadD( _ACC_ );\n";
}
if ($op_source == 3) { # direct
print INST_IMP "unsigned char srcaddr = PGMMem->Read8( PC++ );\n";
print INST_IMP "unsigned char source = ReadD( srcaddr );\n";
}
if ($op_source == 4) { # @R0
print INST_IMP "unsigned char source = ReadI ( ReadD( BANKPSW + _R0_ ) );\n";
}
if ($op_source == 5) { # @R1
print INST_IMP "unsigned char source = ReadI ( ReadD( BANKPSW + _R1_ ) );\n";
}
if ($op_source == 6) { # R0
print INST_IMP "unsigned char source = ReadD( BANKPSW + _R0_ );\n";
}
if ($op_source == 7) { # R1
print INST_IMP "unsigned char source = ReadD( BANKPSW + _R1_ );\n";
}
if ($op_source == 8) { # R2
print INST_IMP "unsigned char source = ReadD( BANKPSW + _R2_ );\n";
}
if ($op_source == 9) { # R3
print INST_IMP "unsigned char source = ReadD( BANKPSW + _R3_ );\n";
}
if ($op_source == 10) { # R4
print INST_IMP "unsigned char source = ReadD( BANKPSW + _R4_ );\n";
}
if ($op_source == 11) { # R5
print INST_IMP "unsigned char source = ReadD( BANKPSW + _R5_ );\n";
}
if ($op_source == 12) { # R6
print INST_IMP "unsigned char source = ReadD( BANKPSW + _R6_ );\n";
}
if ($op_source == 13) { # R7
print INST_IMP "unsigned char source = ReadD( BANKPSW + _R7_ );\n";
}
if ($op_source == 14) { # bitaddr
print INST_IMP "unsigned char source, srcbitaddr = PGMMem->Read8( PC++ );\n";
print INST_IMP "source = ReadB( srcbitaddr );\n";
}
if ($op_source == 15) { # reladdr
print INST_IMP "PC++;\n";
print INST_IMP "unsigned int source = ( ( PGMMem->Read8( PC - 1 ) + PC ) & 0xFF ) + ( PC & 0xFF00 );\n";
}
if ($op_source == 16) { # #data
print INST_IMP "unsigned char source = PGMMem->Read8( PC++ );\n";
}
if ($op_source == 17) { # C
print INST_IMP "unsigned char source = ( ReadD( _PSW_ ) >> 7 );\n";
}
if ($op_source == 18) { # @A+DPTR
print INST_IMP "unsigned char source = PGMMem->Read8( ReadD( _ACC_ ) + ReadD( _DPTRLOW_ ) + ( ReadD( _DPTRHIGH_ ) << 8 ) );\n";
}
if ($op_source == 19) { # @A+PC
print INST_IMP "unsigned char source = PGMMem->Read8( ReadD( _ACC_ ) + ( ++PC ) );\n";
}
if ($op_source == 21) { # DPTR
print INST_IMP "unsigned int source = ( ReadD( _DPTRHIGH_ ) << 8 ) + ReadD( _DPTRLOW_ );\n";
}
if ($op_source == 22) { # #data16
print INST_IMP "unsigned char source = ( PGMMem->Read8( PC++ ) << 8 );\n";
print INST_IMP "source += PGMMem->Read8( PC++ );\n";
}
if ($op_source == 23) { # /bitaddr
print INST_IMP "unsigned char source, srcbitaddr = PGMMem->Read8( PC++ );\n";
print INST_IMP "source = ( ReadB( srcbitaddr ) ^ 1 );\n";
}
if ($op_source == 24) { # @DPTR
print INST_IMP "unsigned char source = ReadI( ( ReadD( _DPTRHIGH_ ) << 8 ) + ReadD( _DPTRLOW_) );\n";
}
}
##############################################################################
$modifysrc=0;
# print INST_IMP "\n// Inserer le code ici\n\n";
# RR
if ($insttype[$i] == 3) {
print INST_IMP "destination = ( destination >> 1 ) | ( destination << 7 );\n";
}
# INC
if ($insttype[$i] == 4) {
print INST_IMP "destination++;\n";
}
# JBC
if ($insttype[$i] == 5) {
print INST_IMP "if ( destination == 1 ) { PC = source; destination = 0; }\n";
}
# ACALL
if ($insttype[$i] == 6) {
print INST_IMP "unsigned char SP = ReadD( _SP_ );\n";
print INST_IMP "WriteI( ++SP, ( PC & 0x00FF ) );\n";
print INST_IMP "WriteI( ++SP, ( PC >> 8 ) );\n";
print INST_IMP "WriteD( _SP_, SP );\n";
}
# LCALL
if ($insttype[$i] == 7) {
print INST_IMP "unsigned char SP = ReadD( _SP_ );\n";
print INST_IMP "WriteI( ++SP, ( PC & 0x00FF ) );\n";
print INST_IMP "WriteI( ++SP, ( PC >> 8 ) );\n";
print INST_IMP "WriteD( _SP_, SP );\n";
}
# RRC
if ($insttype[$i] == 8) {
print INST_IMP "unsigned char tmpval = destination;\n";
print INST_IMP "destination = ( destination >> 1 ) | ( ReadD( _PSW_ ) & 0x80 );\n";
print INST_IMP "WriteD( _PSW_, ( ReadD( _PSW_ ) & 0x7F ) | ( tmpval << 7 ) );\n";
}
# DEC
if ($insttype[$i] == 9) {
print INST_IMP "destination--;\n";
}
# JB
if ($insttype[$i] == 10) {
print INST_IMP "if ( destination == 1 ) { PC = source; }\n";
}
# RET
if ($insttype[$i] == 11) {
print INST_IMP "unsigned char SP = ReadD( _SP_ );\n";
print INST_IMP "PC = ( ReadI( SP-- ) << 8 );\n";
print INST_IMP "PC += ReadI ( SP-- );\n";
print INST_IMP "WriteD( _SP_, SP );\n";
}
# RL
if ($insttype[$i] == 12) {
print INST_IMP "destination = ( destination << 1 ) | ( destination >> 7 );\n";
}
# ADD
if ($insttype[$i] == 13) {
print INST_IMP "WriteD( _PSW_, ( ReadD( _PSW_ ) & 0x3B ) );\n";
print INST_IMP "if ( destination + source > 0xFF ) {\n";
print INST_IMP " WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x80 ) );\n";
print INST_IMP " if ( ( destination & 0x7F ) + ( source & 0x7F ) < 0x80 ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x04 ) );\n";
print INST_IMP "} else if ( ( destination & 0x7F ) + ( source & 0x7F ) > 0x7F ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x04 ) );\n";
print INST_IMP "if ( ( destination & 0x0F ) + ( source & 0x0F ) > 0x0F ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x04 ) );\n";
print INST_IMP "destination += source;\n";
}
# JNB
if ($insttype[$i] == 14) {
print INST_IMP "if ( destination == 0 ) { PC = source; }\n";
}
# RETI
if ($insttype[$i] == 15) {
print INST_IMP "ActivePriority = -1;\n";
print INST_IMP "unsigned char SP = ReadD( _SP_ );\n";
print INST_IMP "PC = ( ReadI( SP-- ) << 8 );\n";
print INST_IMP "PC += ReadI( SP-- );\n";
}
# RLC
if ($insttype[$i] == 16) {
print INST_IMP "unsigned char tmpval = destination;\n";
print INST_IMP "destination = ( destination << 1 ) | ( ( ReadD( _PSW_ ) & 0x80 ) >> 7 );\n";
print INST_IMP "WriteD( _PSW_, ( ReadD( _PSW_ ) & 0x7F ) | ( tmpval & 0x80 ) );\n";
}
# ADDC
if ($insttype[$i] == 17) {
print INST_IMP "unsigned char carryflag = ( ReadD( _PSW_ ) >> 7 );\n";
print INST_IMP "WriteD( _PSW_, ( ReadD( _PSW_ ) & 0x3B ) );\n";
print INST_IMP "if ( destination + source + carryflag > 0xFF ) {\n";
print INST_IMP " WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x80 ) );\n";
print INST_IMP " if ( ( destination & 0x7F ) + ( source & 0x7F ) + carryflag < 0x80 ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x04 ) );\n";
print INST_IMP "} else if ( ( destination & 0x7F ) + ( source & 0x7F ) + carryflag > 0x7F ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x04 ) );\n";
print INST_IMP "if ( ( destination & 0x0F ) + ( source & 0x0F ) + carryflag > 0x0F ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x40 ) );\n";
print INST_IMP "destination += source;\n";
}
# JC
if ($insttype[$i] == 18) {
print INST_IMP "if ( ReadD( _PSW_ ) > 0x7F) { PC = destination; }\n";
}
# ORL
if ($insttype[$i] == 19) {
if ($instargs[$i*4+1] == 17) {
# sur des bits
print INST_IMP "WriteD( _PSW_ , ( ( destination | source ) << 7 ) );\n";
} else {
# sur des bytes
print INST_IMP "destination |= source;\n";
}
}
# JNC
if ($insttype[$i] == 20) {
print INST_IMP "if ( ReadD( _PSW_ ) < 0x80 ) { PC = destination; }\n";
}
# ANL
if ($insttype[$i] == 21) {
if ($instargs[$i*4+1] == 17) {
# sur des bits
print INST_IMP "WriteD( _PSW_, ( ( destination & source) << 7 ) );\n";
} else {
# sur des bytes
print INST_IMP "destination &= source;\n";
}
}
# JZ
if ($insttype[$i] == 22) {
print INST_IMP "if ( ReadD( _ACC_ ) == 0 ) { PC = destination; }\n";
}
# XRL
if ($insttype[$i] == 23) {
print INST_IMP "destination ^= source;\n";
}
# JNZ
if ($insttype[$i] == 24) {
print INST_IMP "if ( ReadD( _ACC_ ) != 0 ) { PC = destination; }\n";
}
# JMP
if ($insttype[$i] == 25) {
print INST_IMP "PC = destination;\n";
}
# MOV
if ($insttype[$i] == 26) {
print INST_IMP "destination = source;\n";
}
# SJMP
if ($insttype[$i] == 27) {
print INST_IMP "PC = destination;\n";
}
# MOVC
if ($insttype[$i] == 28) {
print INST_IMP "destination = source;\n";
}
# DIV
if ($insttype[$i] == 29) {
print INST_IMP "unsigned char A = ReadD( _ACC_ ), B = ReadD( _B_ );\n";
print INST_IMP "WriteD( _PSW_, ( ReadD( _PSW_ ) & 0x7B ) );\n";
print INST_IMP "if ( B != 0 ) {\n";
print INST_IMP "WriteD( _ACC_, A/B ); WriteD( _B_, A%B );\n";
print INST_IMP "} else WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x04 ) );\n";
}
# SUBB
if ($insttype[$i] == 30) {
print INST_IMP "unsigned char carryflag = ReadD( _PSW_ ) >> 7;\n";
print INST_IMP "WriteD( _PSW_, ( ReadD( _PSW_ ) & 0x3B ) );\n";
print INST_IMP "if ( destination < ( source + carryflag ) ) {\n";
print INST_IMP " WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x80 ) );\n";
print INST_IMP " if ( ( destination & 0x7F ) > ( ( source + carryflag ) & 0x7F ) ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x04 ) );\n";
print INST_IMP "} else if ( ( destination & 0x7F ) < ( ( source + carryflag ) & 0x7F ) ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x04 ) );\n";
print INST_IMP "if ( ( destination & 0x0F ) < ( ( source + carryflag ) & 0x0F ) ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x40 ) );\n";
print INST_IMP "destination -= source + carryflag;\n";
}
# MUL
if ($insttype[$i] == 31) {
print INST_IMP "unsigned char A = ReadD( _ACC_ ), B = ReadD( _B_ );\n";
print INST_IMP "WriteD( _PSW_, ( ReadD( _PSW_ ) & 0x7B ) );\n";
print INST_IMP "WriteD( _ACC_ , ( ( A * B ) & 0x00FF ) ); WriteD( _B_, ( A * B ) / 0x100 );\n";
print INST_IMP "if ( ReadD( _B_ ) > 0) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x04 ) );\n";
}
# CPL
if ($insttype[$i] == 33) {
if ($instargs[$i*4+1] == 2) { print INST_IMP "destination ^= 0xFF;\n"; }
else { print INST_IMP "destination ^= 0x01;\n"; }
}
# CJNE
if ($insttype[$i] == 34) {
print INST_IMP "unsigned int reladdr = ( ( PGMMem->Read8( PC ) + ( ( PC + 1 ) & 0x00FF ) ) & 0x00FF ) + ( ( PC + 1 ) & 0xFF00 );\n";
print INST_IMP "WriteD( _PSW_, ( ReadD( _PSW_ ) & 0x7F ) );\n";
print INST_IMP "if ( destination < source ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x80 ) );\n";
print INST_IMP "if ( destination != source ) PC = reladdr;\n";
}
# PUSH
if ($insttype[$i] == 35) {
print INST_IMP "unsigned char SP = ReadD( _SP_ );\n";
print INST_IMP "WriteI( ++SP, destination );\n";
print INST_IMP "WriteD( _SP_, SP );\n";
}
# CLR
if ($insttype[$i] == 36) {
print INST_IMP "destination = 0;\n";
}
# SWAP
if ($insttype[$i] == 37) {
print INST_IMP "destination = ( destination << 4 ) + ( destination >> 4 );\n";
}
# XCH
if ($insttype[$i] == 38) {
print INST_IMP "unsigned char tmpval = destination;\n";
print INST_IMP "destination = source; source = tmpval;\n";
$modifysrc=1;
}
# POP
if ($insttype[$i] == 39) {
print INST_IMP "unsigned char SP = ReadD( _SP_ );\n";
print INST_IMP "destination = ReadI( SP-- );\n";
print INST_IMP "WriteD( _SP_, SP );\n";
}
# SETB
if ($insttype[$i] == 40) {
print INST_IMP "destination = 1;\n";
}
# DA
if ($insttype[$i] == 41) {
print INST_IMP "if ( ( ( destination & 0x0F ) > 9) || ( ReadD( _PSW_ ) | 0x40)) {\n";
print INST_IMP " if ( ( destination + 6 ) > 0xFF) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x80 ) );\n";
print INST_IMP " destination += 6;\n";
print INST_IMP "}\n";
print INST_IMP "if ( ( ReadD( _PSW_ ) & 0x80) || ( ( destination & 0xF0 ) > 0x90 ) ) {\n";
print INST_IMP " if ( ( destination + 0x60 ) > 0xFF ) WriteD( _PSW_, ( ReadD( _PSW_ ) | 0x80 ) );\n";
print INST_IMP " destination += 0x60;\n";
print INST_IMP "}\n";
}
# DJNZ
if ($insttype[$i] == 42) {
print INST_IMP "destination--;\n";
print INST_IMP "if ( destination != 0 ) PC = source;\n";
}
# XCHD
if ($insttype[$i] == 43) {
print INST_IMP "unsigned char tmpval = ( destination & 0x0F );\n";
print INST_IMP "destination = ( destination & 0xF0 ) + ( source & 0x0F );\n";
print INST_IMP "source = ( source & 0xF0 ) + tmpval;\n";
$modifysrc=1;
}
# MOVX
if ($insttype[$i] == 44) {
print INST_IMP "destination = source;\n";
}
##############################################################################
if ($instargs[$i*4] > 0) {
$op_destination=$instargs[$i*4+1];
if ($op_destination == 0) { # addr11
print INST_IMP "PC = ( PC & 0xF800 ) | addr11;\n";
}
if ($op_destination == 1) { # addr16
print INST_IMP "PC = addr16;\n";
}
if ($op_destination == 2) { # A
print INST_IMP "WriteD( _ACC_, destination );\n";
}
if ($op_destination == 3) { # direct
print INST_IMP "WriteD( destaddr, destination );\n";
}
if ($op_destination == 4) { # @R0
print INST_IMP "WriteI( ReadD( BANKPSW + _R0_ ), destination );\n";
}
if ($op_destination == 5) { # @R1
print INST_IMP "WriteI( ReadD( BANKPSW + _R1_ ), destination );\n";
}
if ($op_destination == 6) { # R0
print INST_IMP "WriteD( BANKPSW + _R0_, destination );\n";
}
if ($op_destination == 7) { # R1
print INST_IMP "WriteD( BANKPSW + _R1_, destination );\n";
}
if ($op_destination == 8) { # R2
print INST_IMP "WriteD( BANKPSW + _R2_, destination );\n";
}
if ($op_destination == 9) { # R3
print INST_IMP "WriteD( BANKPSW + _R3_, destination );\n";
}
if ($op_destination == 10) { # R4
print INST_IMP "WriteD( BANKPSW + _R4_, destination );\n";
}
if ($op_destination == 11) { # R5
print INST_IMP "WriteD( BANKPSW + _R5_, destination );\n";
}
if ($op_destination == 12) { # R6
print INST_IMP "WriteD( BANKPSW + _R6_, destination );\n";
}
if ($op_destination == 13) { # R7
print INST_IMP "WriteD( BANKPSW + _R7_, destination );\n";
}
if ($op_destination == 14) { # bitaddr
print INST_IMP "WriteB( dstbitaddr, destination );\n";
}
if ($op_destination == 17) { # C
print INST_IMP "WriteD( _PSW_, ( ( ReadD( _PSW_ ) & 0x7F) | ( destination << 7 ) ) );\n";
}
if ($op_destination == 21) { # DPTR
print INST_IMP "WriteD( _DPTRHIGH_, ( destination >> 8 ) );\n";
print INST_IMP "WriteD( _DPTRLOW_, ( destination & 0xFF ) );\n";
}
if ($op_destination == 23) { # /bitaddr
print INST_IMP "WriteB( dstbitaddr, destination );\n";
}
if ($op_destination == 24) { # @DPTR
print INST_IMP "WriteI( ( ReadD( _DPTRHIGH_ ) << 8 ) + ReadD( _DPTRLOW_ ), destination );\n";
}
}
if ($modifysrc == 1) {
if ($instargs[$i*4] > 1) {
$op_source=$instargs[$i*4+2];
if ($op_source == 0) { # addr11
print INST_IMP "PC = ( PC & 0xF800 ) | addr11;\n";
}
if ($op_source == 1) { # addr16
print INST_IMP "PC = addr16;\n";
}
if ($op_source == 2) { # A
print INST_IMP "WriteD( _ACC_, source );\n";
}
if ($op_source == 3) { # direct
print INST_IMP "WriteD( srcaddr, source );\n";
}
if ($op_source == 4) { # @R0
print INST_IMP "WriteI( ReadD( BANKPSW + _R0_ ), source );\n";
}
if ($op_source == 5) { # @R1
print INST_IMP "WriteI( ReadD( BANKPSW + _R1_ ), source );\n";
}
if ($op_source == 6) { # R0
print INST_IMP "WriteD( BANKPSW + _R0_, source );\n";
}
if ($op_source == 7) { # R1
print INST_IMP "WriteD( BANKPSW + _R1_, source );\n";
}
if ($op_source == 8) { # R2
print INST_IMP "WriteD( BANKPSW + _R2_, source );\n";
}
if ($op_source == 9) { # R3
print INST_IMP "WriteD( BANKPSW + _R3_, source );\n";
}
if ($op_source == 10) { # R4
print INST_IMP "WriteD( BANKPSW + _R4_, source );\n";
}
if ($op_source == 11) { # R5
print INST_IMP "WriteD( BANKPSW + _R5_, source );\n";
}
if ($op_source == 12) { # R6
print INST_IMP "WriteD( BANKPSW + _R6_, source );\n";
}
if ($op_source == 13) { # R7
print INST_IMP "WriteD( BANKPSW + _R7_, source );\n";
}
if ($op_source == 14) { # bitaddr
print INST_IMP "WriteB( srcbitaddr, source );\n";
}
if ($op_source == 17) { # C
print INST_IMP "WriteD( _PSW_, ( ( ReadD( _PSW_ ) & 0x7F) | ( source << 7 ) ) );\n";
}
if ($op_source == 21) { # DPTR
print INST_IMP "WriteD( _DPTRHIGH_, ( source >> 8 ) );\n";
print INST_IMP "WriteD( _DPTRLOW_, ( source & 0xFF ) );\n";
}
if ($op_source == 23) { # /bitaddr
print INST_IMP "WriteB( srcbitaddr, source );\n";
}
if ($op_source == 24) { # @DPTR
print INST_IMP "WriteI( ( ReadD( _DPTRHIGH_ ) << 8 ) + ReadD( _DPTRLOW_ ), source );\n";
}
}
}
}
print INST_IMP "return $a_cycles[$i];\n";
print INST_IMP "}\n";
print INST_IMP "\n\n";
}
# ------------------------------------------------------------------------------
print INST_IMP "\n\n";
print INST_IMP "/"x78,"\n";
print INST_IMP "// void CPU8051::InitFuncPtr( )\n";
print INST_IMP "// Initialize Functions Pointers\n";
print INST_IMP "/"x78,"\n";
print INST_IMP "void CPU8051::InitFuncPtr( )\n";
print INST_DEF "void InitFuncPtr( );\n";
print INST_IMP "{\n";
#print INST_IMP "static int (*instfnc[])() = {\n";
for ($i=0;$i<256;$i++) {
$ifunc=substr($instfunction[$i], 9);
print INST_IMP " funcptr[$i]=&CPU8051::$ifunc;\n";
# ($i < 255) and print INST_IMP ",\n";
# (($i+1) % 4 == 0) and print INST_IMP "\n";
}
print INST_IMP "\n}\n";
print INST_IMP "\n\n#endif\n";
print INST_DEF "\n\n#endif\n";
print DISASM_HPP "\n\n#endif\n";
close DISASM_HPP;
close OPCODELST;
close INST_DEF;
close INST_IMP;

View File

@ -1,186 +0,0 @@
/* pgmwin.cpp */
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include "PgmWin.hpp"
#include <stdio.h>
int PgmWinNumber = 0;
int PgmWinNumbers[ 1 ];
PgmWin *PgmWinPtrs[ 1 ];
//////////////////////////////////////////////////////////////////////////////
// PgmWin::PgmWin( GtkWidget *parentwin, CPU8051 *mCPU )
// PgmWin constructor
//////////////////////////////////////////////////////////////////////////////
PgmWin::PgmWin( GtkWidget *parentwin, CPU8051 *mCPU )
{
CPU = mCPU;
int i;
GtkStyle *style;
GdkFont *fixedfont;
fixedfont = gdk_font_load( "-adobe-courier-medium-r-normal--12-120-75-75-m-70-iso8859-1" );
pgmclist = gtk_clist_new( 1 );
gtk_clist_set_selection_mode( GTK_CLIST( pgmclist ), GTK_SELECTION_SINGLE );
gtk_widget_set_usize( GTK_WIDGET( pgmclist ), PGM_WIN_WIDTH, PGM_WIN_HEIGHT );
gtk_clist_set_column_justification( GTK_CLIST( pgmclist ), 0, GTK_JUSTIFY_LEFT );
gtk_clist_set_column_width( GTK_CLIST( pgmclist ), 0, PGM_WIN_WIDTH-10 );
style = gtk_widget_get_style( GTK_WIDGET( pgmclist ) );
#ifdef USE_GTK2
gtk_style_set_font( style, fixedfont );
#else
style->font = fixedfont;
#endif
gtk_widget_set_style( GTK_WIDGET( pgmclist ), style );
char *pgmdummy[] = { 0 };
for ( i = 0; i < 24; i++ ) gtk_clist_append( GTK_CLIST( pgmclist ), pgmdummy );
gtk_container_add( GTK_CONTAINER( parentwin ), pgmclist );
gtk_widget_show( pgmclist );
NbBreakpoints = 0;
if ( PgmWinNumber >= 1 ) g_print( "WARNING! Too many PgmWin objects to handle signals!\n");
else {
PgmWinPtrs[ PgmWinNumber ] = this;
PgmWinNumbers[ PgmWinNumber ] = PgmWinNumber;
gtk_signal_connect( GTK_OBJECT( pgmclist ), "button-press-event", GTK_SIGNAL_FUNC( PgmWinButtonPress ), &PgmWinNumbers[ PgmWinNumber++ ] );
}
}
//////////////////////////////////////////////////////////////////////////////
// PgmWin::~PgmWin( )
// PgmWin destructor
//////////////////////////////////////////////////////////////////////////////
PgmWin::~PgmWin( )
{
}
//////////////////////////////////////////////////////////////////////////////
// void PgmWin::Disasm( )
// Disasm 24 lines from CPU
//////////////////////////////////////////////////////////////////////////////
void PgmWin::Disasm( )
{
char TextTmp[255];
int row;
//int TextLength;
int InstSize;
unsigned int Address;
Address = CPU->GetPC( );
gtk_clist_freeze( GTK_CLIST( pgmclist ) );
for ( row = 0; row < 24; row++ ) {
InstSize = CPU->Disasm( Address, TextTmp );
if ( IsBreakpoint( Address ) ) TextTmp[0] = '*';
gtk_clist_set_text( GTK_CLIST( pgmclist ), row, 0, TextTmp );
DisasmAddresses[ row ] = Address;
Address += InstSize;
}
gtk_clist_select_row( GTK_CLIST( pgmclist ), 0, 0 );
gtk_clist_thaw( GTK_CLIST( pgmclist ) );
}
//////////////////////////////////////////////////////////////////////////////
// gint PgmWin::ButtonPressEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
// Mouse button pressed in the window
//////////////////////////////////////////////////////////////////////////////
gint PgmWin::ButtonPressEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
{
gint row, column;
char TextTmp[ 255 ];
//g_print( "PgmWin::ButtonPressEvent(...)\n" );
gtk_clist_get_selection_info( GTK_CLIST( pgmclist ), ( int )event->button.x ,( int )event->button.y, &row, &column );
if (row >= 24 || row < 0)
return TRUE;
if (column >= 1 || column < 0)
return TRUE;
sprintf( TextTmp, "PgmWin::ButtonPressEvent( ) at %d,%d\n", column, row );
g_print( TextTmp );
ToggleBreakpoint( DisasmAddresses[ row ] );
Disasm( );
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// gint PgmWinButtonPress( GtkWidget *widget, GdkEvent *event, gpointer data )
// Signal Stub with 3 parameters
//////////////////////////////////////////////////////////////////////////////
void PgmWinButtonPress( GtkWidget *widget, GdkEvent *event, gpointer data )
{
int PWNumber = (* ( static_cast< int * >( data ) ) );
PgmWinPtrs[ PWNumber ]->ButtonPressEvent( widget, event, 0 );
}
//////////////////////////////////////////////////////////////////////////////
// void PgmWin::ShowBreakpoints( )
// Show Breakpoints list
//////////////////////////////////////////////////////////////////////////////
void PgmWin::ShowBreakpoints( )
{
for ( int Index = 0; Index < NbBreakpoints ; Index++ )
printf( "Breakpoint at Address = %.4X\n", Breakpoints[ Index ] );
}
//////////////////////////////////////////////////////////////////////////////
// void PgmWin::ClearBreakpoint( unsigned int Address )
// Clear Breakpoint at Address from list
//////////////////////////////////////////////////////////////////////////////
void PgmWin::ClearBreakpoint( unsigned int Address )
{
int Index = 0;
while ( Index < NbBreakpoints && Breakpoints[ Index ] != Address ) Index++;
if ( Breakpoints[ Index ] != Address ) return;
Breakpoints[ Index ] = Breakpoints[ NbBreakpoints - 1 ];
NbBreakpoints--;
}
//////////////////////////////////////////////////////////////////////////////
// void PgmWin::SetBreakpoint( unsigned int Address )
// Set Breakpoint at Address from list
//////////////////////////////////////////////////////////////////////////////
void PgmWin::SetBreakpoint( unsigned int Address )
{
if ( IsBreakpoint( Address ) ) return;
if ( NbBreakpoints < MAXBP ) Breakpoints[ NbBreakpoints++ ] = Address;
}
//////////////////////////////////////////////////////////////////////////////
// int PgmWin::IsBreakpoint( unsigned int Address )
// Is the a breakpoint at Address
//////////////////////////////////////////////////////////////////////////////
int PgmWin::IsBreakpoint( unsigned int Address )
{
int Index = 0;
while ( Index < NbBreakpoints && Breakpoints[ Index ] != Address ) Index++;
return ( Breakpoints[ Index ] == Address && Index < NbBreakpoints );
}
//////////////////////////////////////////////////////////////////////////////
// void PgmWin::ToggleBreakpoint( unsigned int Address )
// Toggle the breakpoint at Address
//////////////////////////////////////////////////////////////////////////////
void PgmWin::ToggleBreakpoint( unsigned int Address )
{
if ( IsBreakpoint( Address ) ) ClearBreakpoint( Address );
else SetBreakpoint( Address );
}

View File

@ -1,41 +0,0 @@
#ifndef _PGMWIN_HPP_
#define _PGMWIN_HPP_
#include <gtk/gtk.h>
#include "CPU8051.hpp"
#include "GtkSizes.hpp"
#define MAXBP 32
//////////////////////////////////////////////////////////////////////////////
// PgmWin
// Implements a Program Window in Gtk+ as an Object
//////////////////////////////////////////////////////////////////////////////
class PgmWin {
public:
PgmWin( GtkWidget *parentwin, CPU8051 *mCPU );
~PgmWin( );
void Disasm( );
gint ButtonPressEvent( GtkWidget *widget, GdkEvent *event, gpointer data );
void ShowBreakpoints( );
void SetBreakpoint( unsigned int Address );
void ClearBreakpoint( unsigned int Address );
int IsBreakpoint( unsigned int Address );
void ToggleBreakpoint( unsigned int Address );
private:
CPU8051 *CPU;
GtkWidget *pgmwin;
GtkWidget *pgmclist;
int NbBreakpoints;
unsigned int Breakpoints[ MAXBP ];
unsigned int DisasmAddresses[ 24 ];
};
void PgmWinButtonPress( GtkWidget *widget, GdkEvent *event, gpointer data );
#endif

View File

@ -1,44 +0,0 @@
#ifndef __REGISTRES8051_HPP_
#define __REGISTRES8051_HPP_
// SFR Registers ( $80 - $FF )
#define _ACC_ 0xE0
#define _B_ 0xF0
#define _PSW_ 0xD0
#define _SP_ 0x81
#define _DPTRLOW_ _DPL_
#define _DPTRHIGH_ _DPH_
#define _DPL_ 0x82
#define _DPH_ 0x83
#define _P0_ 0x80
#define _P1_ 0x90
#define _P2_ 0xA0
#define _P3_ 0xB0
#define _IP_ 0xB8
#define _IE_ 0xA8
#define _TMOD_ 0x89
#define _TCON_ 0x88
#define _TH0_ 0x8C
#define _TL0_ 0x8A
#define _TH1_ 0x8D
#define _TL1_ 0x8B
#define _SCON_ 0x98
#define _SBUF_ 0x99
#define _PCON_ 0x87
#define _T2CON_ 0xC8
#define _R0_ 0x00
#define _R1_ 0x01
#define _R2_ 0x02
#define _R3_ 0x03
#define _R4_ 0x04
#define _R5_ 0x05
#define _R6_ 0x06
#define _R7_ 0x07
#define _BANK0_ 0x00
#define _BANK1_ 0x08
#define _BANK2_ 0x10
#define _BANK3_ 0x18
#endif

View File

@ -1,131 +0,0 @@
/* regwin.cpp */
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include "RegWin.hpp"
//////////////////////////////////////////////////////////////////////////////
// RegWin::RegWin( GtkWidget *parentwin )
// RegWin constructor
//////////////////////////////////////////////////////////////////////////////
RegWin::RegWin( GtkWidget *parentwin )
{
int i;
GtkStyle *style;
GdkFont *fixedfont;
fixedfont = gdk_font_load( "-adobe-courier-medium-r-normal--12-120-75-75-m-70-iso8859-1" );
regclist = gtk_clist_new( 1 );
gtk_clist_set_selection_mode( GTK_CLIST( regclist ), GTK_SELECTION_SINGLE );
gtk_widget_set_usize( GTK_WIDGET( regclist ), REG_WIN_WIDTH, REG_WIN_HEIGHT );
gtk_clist_set_column_justification( GTK_CLIST( regclist ), 0, GTK_JUSTIFY_LEFT );
gtk_clist_set_column_width( GTK_CLIST( regclist ), 0, REG_WIN_WIDTH );
style = gtk_widget_get_style( GTK_WIDGET( regclist ) );
#ifdef USE_GTK2
gtk_style_set_font( style, fixedfont );
#else
style->font = fixedfont;
#endif
gtk_widget_set_style( GTK_WIDGET( regclist ), style );
char *regdummy[] = { 0 };
for ( i = 0; i < 24; i++ )
gtk_clist_append( GTK_CLIST( regclist ), regdummy );
gtk_container_add( GTK_CONTAINER( parentwin ), regclist );
gtk_widget_show( regclist );
}
//////////////////////////////////////////////////////////////////////////////
// RegWin::~RegWin( )
// RegWin destructor
//////////////////////////////////////////////////////////////////////////////
RegWin::~RegWin( )
{
}
//////////////////////////////////////////////////////////////////////////////
// void RegWin::Show( CPU8051 *CPU )
// Show registers
//////////////////////////////////////////////////////////////////////////////
void RegWin::Show( CPU8051 *CPU )
{
char TextTmp[255];
int row = 0;
unsigned char PSW = CPU->ReadD( _PSW_ );
unsigned char Rbank;
gtk_clist_freeze( GTK_CLIST( regclist ) );
// Main registers
sprintf( TextTmp , "PC = %.4X", CPU->GetPC( ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "SP = %.2X", CPU->ReadD( _SP_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "A = %.2X", CPU->ReadD( _ACC_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "B = %.2X", CPU->ReadD( _B_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "DPTR = %.4X", ( CPU->ReadD( _DPTRHIGH_ ) << 8 ) + CPU->ReadD( _DPTRLOW_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
// Program Status Word
sprintf( TextTmp , "PSW = %.2X",PSW);
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
// Ports registers
sprintf( TextTmp , "P0 = %.2X", CPU->ReadD( _P0_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "P1 = %.2X", CPU->ReadD( _P1_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "P2 = %.2X", CPU->ReadD( _P2_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "P3 = %.2X", CPU->ReadD( _P3_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
// Misc Registers
sprintf( TextTmp , "TCON = %.2X", CPU->ReadD( _TCON_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "TMOD = %.2X", CPU->ReadD( _TMOD_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "SCON = %.2X", CPU->ReadD( _SCON_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "IE = %.2X", CPU->ReadD( _IE_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "IP = %.2X", CPU->ReadD( _IP_ ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
// R0-R7 Registers in current Bank
Rbank = CPU->ReadD( _PSW_ ) & 0x18;
sprintf( TextTmp , "Bank = %.2X", Rbank);
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "R0 = %.2X", CPU->ReadD( _R0_ + Rbank ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "R1 = %.2X", CPU->ReadD( _R1_ + Rbank ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "R2 = %.2X", CPU->ReadD( _R2_ + Rbank ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "R3 = %.2X", CPU->ReadD( _R3_ + Rbank ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "R4 = %.2X", CPU->ReadD( _R4_ + Rbank ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "R5 = %.2X", CPU->ReadD( _R5_ + Rbank ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "R6 = %.2X", CPU->ReadD( _R6_ + Rbank ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
sprintf( TextTmp , "R7 = %.2X", CPU->ReadD( _R7_ + Rbank ) );
gtk_clist_set_text( GTK_CLIST( regclist ), row++, 0, TextTmp );
gtk_clist_select_row(GTK_CLIST(regclist),0,0);
gtk_clist_thaw( GTK_CLIST( regclist ) );
}

View File

@ -1,26 +0,0 @@
#ifndef _REGWIN_HPP_
#define _REGWIN_HPP_
#include <gtk/gtk.h>
#include "CPU8051.hpp"
#include "GtkSizes.hpp"
//////////////////////////////////////////////////////////////////////////////
// RegWin
// Implements a Registers Window in Gtk+ as an Object
//////////////////////////////////////////////////////////////////////////////
class RegWin {
public:
RegWin( GtkWidget *parentwin );
~RegWin( );
void Show( CPU8051 *CPU );
private:
GtkWidget *regwin;
GtkWidget *regclist;
};
#endif

36
src/cli/Makefile.am Normal file
View File

@ -0,0 +1,36 @@
# This file is processed by GNU automake to generate Makefile.in
AM_CPPFLAGS = \
$(WARNINGCFLAGS) \
-I$(top_srcdir)/src/common \
-I$(top_builddir)/src/common
# Option --header-file: produce header file scanner.h.
# Using abs_builddir as a workaround for automake-1.11
# broken ylwrap script.
AM_LFLAGS = --header-file=$(abs_builddir)/scanner.h
# Option -d: produce header file parser.h
AM_YFLAGS = -d
LDADD = \
$(LIBREADLINE) \
$(top_builddir)/src/common/libemu8051.a
bin_PROGRAMS = emu8051-cli
emu8051_cli_SOURCES = \
parser.y scanner.l \
main.c \
menu.c menu.h \
keyboard.c keyboard.h
# We want these in the dist tarball
EXTRA_DIST = scanner.h
CLEANFILES = *~
MAINTAINERCLEANFILES = \
Makefile.in \
scanner.h scanner.c \
parser.h parser.c

72
src/cli/keyboard.c Normal file
View File

@ -0,0 +1,72 @@
/*
* keyboard.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#include <termios.h>
#include <unistd.h>
static struct termios orig, newtio;
static int peek = -1;
int
kbhit(void)
{
char ch;
int nread;
if (peek != -1)
return 1;
newtio.c_cc[VMIN] = 0;
tcsetattr(0, TCSANOW, &newtio);
nread = read(0, &ch, 1);
newtio.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &newtio);
if (nread == 1) {
peek = ch;
return 1;
}
return 0;
}
int
getch(void)
{
char ch;
if (peek != -1) {
ch = peek;
peek = -1;
return ch;
}
read(0, &ch, 1);
return ch;
}
void
keyboard_init(void)
{
tcgetattr(0, &orig);
newtio = orig;
newtio.c_lflag &= ~ICANON;
newtio.c_lflag &= ~ECHO;
newtio.c_lflag &= ~ISIG;
newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &newtio);
}
void
keyboard_reset(void)
{
tcsetattr(0, TCSANOW, &orig);
}

25
src/cli/keyboard.h Normal file
View File

@ -0,0 +1,25 @@
/*
* keyboard.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef _KEYBOARD_H_
#define _KEYBOARD_H_
int
kbhit(void);
int
getch(void);
void
keyboard_init(void);
void
keyboard_reset(void);
#endif /* _KEYBOARD_H_ */

50
src/cli/main.c Normal file
View File

@ -0,0 +1,50 @@
/*
* main.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include "common.h"
#include "cpu8051.h"
#include "options.h"
#include "hexfile.h"
#include "menu.h"
#include "parser.h"
extern struct options_t options;
int
main(int argc, char **argv)
{
int rc;
parse_command_line_options(argc, argv);
cpu8051_init();
if (options.filename != NULL) {
rc = hexfile_load(options.filename);
if (!rc)
exit(EXIT_FAILURE);
}
console_reset();
if (options.stop_address != 0) {
/* Automatically run program and stop at specified address. */
console_exec(-1);
} else {
menu_display_usage();
(void) yyparse();
}
exit(EXIT_SUCCESS);
}

287
src/cli/menu.c Normal file
View File

@ -0,0 +1,287 @@
/*
* menu.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#include "config.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifdef HAVE_LIBREADLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif /* HAVE_LIBREADLINE */
#include "common.h"
#include "cpu8051.h"
#include "reg8051.h"
#include "sfr.h"
#include "memory.h"
#include "timers.h"
#include "options.h"
#include "hexfile.h"
#include "keyboard.h"
#include "scanner.h"
#include "menu.h"
extern struct options_t options;
#define YY_NULL 0
#define MENU_PROMPT "-> "
int
menu_get_input(char *buf, ssize_t size)
{
char *line;
int max_len;
max_len = size - 2;
if (feof(yyin))
return YY_NULL;
#ifdef HAVE_LIBREADLINE
/* Get the input line, and if non-empty, place it in the history. */
line = readline(MENU_PROMPT);
if (!line)
return YY_NULL;
if (line && *line)
add_history(line);
if ((int) strlen(line) > max_len) {
printf("input line too long");
free(line);
return YY_NULL;
}
strcpy(buf, line);
/* Readline never gives you the last '\n', so add it back for Lex. */
strcat(buf, "\n");
free(line);
#else
/* It's okay to print a prompt if we are redirecting stdout,
* as long as stdin is still a tty. Otherwise, don't print
* a prompt at all if stdin is redirected.
*/
(void) fputs(MENU_PROMPT, stdout);
(void) fflush(stdout); /* for svr4 */
line = fgets(buf, max_len, stdin);
if (!line)
return YY_NULL;
#endif
return strlen(buf);
}
void
menu_display_usage(void)
{
int id;
printf(" " PACKAGE_NAME " commands, [] = options:\n"
"\n"
" sb [ADDRESS] Set breakpoint at PC or ADDRESS\n"
" rb [ADDRESS] Remove breakpoint at PC or ADDRESS\n"
" ADDRESS = all: clear all breakpoints\n"
" db Display breakpoints\n"
" de ADDRESS NUM Dump NUM bytes from ADDRESS in external data"
" memory\n"
" di ADDRESS NUM Dump NUM bytes from ADDRESS in internal data"
" memory\n"
" dp ADDRESS NUM Dump NUM bytes from ADDRESS in program"
" memory\n"
" dr Display registers\n"
" h or ? Display this help menu\n"
" q Quit\n"
" r [NUM] Run until breakpoint or for NUM "
"instructions\n"
" s Step (execute 1 instruction)\n"
" u [ADDRESS] [NUM] Unassemble NUM instructions at ADDRESS\n"
" we ADDRESS VAL Write VAL at ADDRESS in external data memory\n"
" wi ADDRESS VAL Write VAL at ADDRESS in internal data memory\n"
" wp ADDRESS VAL Write VAL at ADDRESS in program memory\n"
" wr REGISTER VAL Write VAL at REGISTER (REGISTER is name of"
" register)\n"
" z Reset processor\n"
" zt ID Reset emulator timer ID (");
for (id = 0; id < GP_TIMERS_COUNT; id++) {
printf("%c", 'A' + id);
if (id < (GP_TIMERS_COUNT - 1))
printf(", ");
}
printf(")\n");
}
/* Disassemble num instructions at address */
void
disassemble_num(unsigned int address, int num)
{
char str[255];
int row;
for (row = 0; row < num; row++) {
address += cpu8051_disasm(address, str);
printf("%s\n", str);
if (address > 0xFFFF)
return;
}
}
/* Capitalize all letters in buffer */
static void
uppercase(char *buffer)
{
size_t k;
for (k = 0; k < strlen(buffer); k++)
buffer[k] = toupper(buffer[k]);
}
/* Set NewValue to Register */
void
register_set(char *name, int value)
{
struct regwin_infos_t *regwin_infos;
uppercase(name);
log_debug(" Modify register %s to $%04X", name, value);
regwin_infos = sfr_get_infos(name);
if (regwin_infos == NULL) {
printf("Invalid register name\n");
return;
}
regwin_write(regwin_infos, value);
}
/* CPU reset and Console UI update */
void
console_reset(void)
{
log_info("Resetting...");
cpu8051_reset();
log_info("Done");
}
/*
* CPU exec and Console UI update
* num = number of instructions to execute.
* set to -1: run to infinity
*/
void
console_exec(int num)
{
keyboard_init();
log_info("Program executing...");
(void) cpu8051_run(num, kbhit);
if (kbhit()) {
(void) getch(); /* Flush key */
log_info("Caught break signal!");
}
keyboard_reset();
console_show_registers();
disassemble_num(cpu8051.pc, 1);
}
/* CPU trace and Console UI update */
void
console_trace(void)
{
(void) cpu8051_exec();
console_show_registers();
disassemble_num(cpu8051.pc, 1);
}
/* Show CPU registers, one per line */
static void
console_dump_sfr_registers_detailed(void)
{
int k;
for (k = 0; k < SFR_REGS; k++) {
struct regwin_infos_t *regwin_infos;
int val;
regwin_infos = sfr_get_infos_from_row(k);
printf("%s = ", regwin_infos->name);
val = regwin_read(k);
if (regwin_infos->w == 2)
printf("$%02X", val);
else if (regwin_infos->w == 4)
printf("$%04X", val);
printf("\n");
}
}
/* Show CPU registers, compact format */
static void
console_dump_sfr_registers_compact(void)
{
int id;
unsigned char PSW = mem_read_direct(_PSW_);
int bank_sel = (PSW & 0x18);
printf("----------------------------------------------------------------------\n");
printf("| PC | SP | DPTR | ACC | B | PSW: CY AC F0 RS1 RS0 OV - P |\n");
printf("| %.4X | %.2X | %.4X | %.2X | %.2X |", cpu8051.pc,
mem_read_direct(_SP_), mem_sfr_read_dptr(),
mem_read_direct(_ACC_), mem_read_direct(_B_));
printf(" %d %d %d %d %d %d %d %d |",
(PSW >> 7) & 1, (PSW >> 6) & 1, (PSW >> 5) & 1, (PSW >> 4) & 1,
(PSW >> 3) & 1, (PSW >> 2) & 1, (PSW >> 1) & 1, PSW & 1);
printf("\n");
printf("----------------------------------------------------------------------\n");
printf("| TCON | TMOD | IE | IP | R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7 | |\n");
printf("| %.2X | %.2X | %.2X | %.2X ", mem_read_direct(_TCON_),
mem_read_direct(_TMOD_), mem_read_direct(_IE_), mem_read_direct(_IP_));
printf("| %.2X | %.2X | %.2X | %.2X ",
mem_read_direct(bank_sel + _R0_),
mem_read_direct(bank_sel + _R1_),
mem_read_direct(bank_sel + _R2_),
mem_read_direct(bank_sel + _R3_));
printf("| %.2X | %.2X | %.2X | %.2X ",
mem_read_direct(bank_sel + _R4_),
mem_read_direct(bank_sel + _R5_),
mem_read_direct(bank_sel + _R6_),
mem_read_direct(bank_sel + _R7_));
printf("| |\n");
printf("----------------------------------------------------------------------\n");
for (id = 0; id < GP_TIMERS_COUNT; id++)
printf("| Emulator timer %c: %08d |\n", 'A' + id, gp_timer_read(id));
printf("------------------------------\n");
}
/* Show CPU registers */
void
console_show_registers(void)
{
if (options.stop_address != 0)
console_dump_sfr_registers_detailed();
else
console_dump_sfr_registers_compact();
}

40
src/cli/menu.h Normal file
View File

@ -0,0 +1,40 @@
/*
* menu.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef _MENU_H_
#define _MENU_H_
int
yyparse(void);
int
menu_get_input(char *buf, ssize_t size);
void
menu_display_usage(void);
void
console_show_registers(void);
void
register_set(char *name, int value);
void
console_reset(void);
void
console_exec(int num);
void
console_trace(void);
void
disassemble_num(unsigned int address, int num);
#endif /* _MENU_H_ */

262
src/cli/parser.y Normal file
View File

@ -0,0 +1,262 @@
%{
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "log.h"
#include "menu.h"
#include "memory.h"
#include "timers.h"
#include "memory.h"
#include "cpu8051.h"
/* int yydebug = 1; */
/* To get rid of compiler warning. */
int yylex();
int yyerror(const char *str)
{
fprintf(stderr,"error: %s\n", str);
return 0;
}
%}
%union
{
int number;
char *string;
}
%token <number> NUMBER
%token <string> WORD
%token TOK_ENTER TOK_ALL
%token TOK_SB TOK_RB TOK_DB
%token TOK_DE TOK_DI TOK_DP TOK_DR
%token TOK_HELP
%token TOK_RUN
%token TOK_RST TOK_RST_TIMER
%token TOK_STEP
%token TOK_UNASM
%token TOK_MOD_EXT TOK_MOD_INT TOK_MOD_PROG TOK_MOD_REG
%token TOK_QUIT
%token TOK_A TOK_B TOK_C TOK_D
%%
start : start command
| error TOK_ENTER {
/* In case of error, discard entire line */
yyerrok;
}
| start TOK_ENTER
|
;
command:
breakpoint_clr
|
breakpoint_set
|
breakpoint_display
|
dump_mem
|
display_regs
|
help
|
modify
|
quit
|
reset
|
run
|
step
|
unasm
;
breakpoint_clr:
TOK_RB NUMBER TOK_ENTER
{
log_debug(" Remove breakpoint at $%04X", $2);
breakpoint_clr($2);
}
|
TOK_RB TOK_ENTER
{
log_debug(" Remove breakpoint at PC");
breakpoint_clr(cpu8051.pc);
}
|
TOK_RB TOK_ALL TOK_ENTER
{
log_debug(" Remove all breakpoints");
breakpoints_clr_all();
}
;
breakpoint_set:
TOK_SB TOK_ENTER
{
log_debug(" Set breakpoint at PC");
breakpoint_set(cpu8051.pc);
}
|
TOK_SB NUMBER TOK_ENTER
{
log_debug(" Set breakpoint at $%04X", $2);
breakpoint_set($2);
}
;
breakpoint_display:
TOK_DB TOK_ENTER
{
log_debug(" Display breakpoints");
breakpoints_show();
}
;
dump_mem:
TOK_DE NUMBER NUMBER TOK_ENTER
{
log_debug(" Dump External Data Memory at $%04X, len %d", $2, $3);
mem_dump($2, $3, EXT_MEM_ID);
}
|
TOK_DI NUMBER NUMBER TOK_ENTER
{
log_debug(" Dump Internal Data Memory at $%04X, len %d", $2, $3);
mem_dump($2, $3, INT_MEM_ID);
}
|
TOK_DP NUMBER NUMBER TOK_ENTER
{
log_debug(" Dump Program Memory at $%04X, len %d", $2, $3);
mem_dump($2, $3, PGM_MEM_ID);
}
;
display_regs:
TOK_DR TOK_ENTER
{
log_debug(" Display Registers");
console_show_registers();
}
;
modify:
TOK_MOD_EXT NUMBER NUMBER TOK_ENTER
{
log_debug(" Modify external memory");
mem_write8(EXT_MEM_ID, $2, $3);
}
|
TOK_MOD_INT NUMBER NUMBER TOK_ENTER
{
log_debug(" Modify internal memory");
mem_write8(INT_MEM_ID, $2, $3);
}
|
TOK_MOD_PROG NUMBER NUMBER TOK_ENTER
{
log_debug(" Modify program memory");
mem_write8(PGM_MEM_ID, $2, $3);
}
|
TOK_MOD_REG WORD NUMBER TOK_ENTER
{
register_set($2, $3);
}
;
quit:
TOK_QUIT TOK_ENTER
{
printf(" Quit");
YYACCEPT;
}
;
run:
TOK_RUN TOK_ENTER
{
log_debug(" Run");
console_exec(-1);
}
|
TOK_RUN NUMBER TOK_ENTER
{
log_debug(" Run %d instructions", $2);
console_exec($2);
}
;
help:
TOK_HELP TOK_ENTER
{
menu_display_usage();
}
;
reset:
TOK_RST TOK_ENTER
{
cpu8051_reset();
}
|
TOK_RST_TIMER TOK_A TOK_ENTER
{
gp_timer_reset(0);
}
|
TOK_RST_TIMER TOK_B TOK_ENTER
{
gp_timer_reset(1);
}
|
TOK_RST_TIMER TOK_C TOK_ENTER
{
gp_timer_reset(2);
}
|
TOK_RST_TIMER TOK_D TOK_ENTER
{
gp_timer_reset(3);
}
;
step:
TOK_STEP TOK_ENTER
{
console_trace();
}
;
unasm:
TOK_UNASM NUMBER NUMBER TOK_ENTER
{
disassemble_num($2, $3);
}
|
TOK_UNASM NUMBER TOK_ENTER
{
disassemble_num(cpu8051.pc, $2);
}
;
|
TOK_UNASM TOK_ENTER
{
disassemble_num(cpu8051.pc, 16);
}
;

68
src/cli/scanner.l Normal file
View File

@ -0,0 +1,68 @@
%option noyywrap
%option noinput
%option nounput
%{
#include "menu.h"
#include "parser.h"
#include "hexfile.h"
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result = menu_get_input(buf, max_size);
%}
digit [0-9]
alpha [a-fA-F]
hextail ({digit}|{alpha}){1,8}
hex1 0[xX]{hextail}
hex2 ${hextail}
%%
{hex1} {
/*
* No need to check return value of asciihex2int, because lex
* always passes a valid ASCII hex string.
*/
yylval.number = asciihex2int(&yytext[2]); /* Skip "0x" prefix */
return NUMBER;
}
{hex2} {
/*
* No need to check return value of asciihex2int, because lex
* always passes a valid ASCII hex string.
*/
yylval.number = asciihex2int(&yytext[1]); /* Skip "$" prefix */
return NUMBER;
}
[0-9]+ { yylval.number = atoi(yytext); return NUMBER; }
[h?] return TOK_HELP;
sb return TOK_SB;
rb return TOK_RB;
db return TOK_DB;
de return TOK_DE;
di return TOK_DI;
dp return TOK_DP;
dr return TOK_DR;
r return TOK_RUN;
q return TOK_QUIT;
s return TOK_STEP;
u return TOK_UNASM;
we return TOK_MOD_EXT;
wi return TOK_MOD_INT;
wp return TOK_MOD_PROG;
wr return TOK_MOD_REG;
z return TOK_RST;
zt return TOK_RST_TIMER;
all return TOK_ALL;
a return TOK_A;
b return TOK_B;
c return TOK_C;
d return TOK_D;
[a-z0-9]+ { yylval.string = strdup(yytext); return WORD; }
[\n] return TOK_ENTER;
[ \t]+ { /* ignore whitespace */ }
. { return yytext[0]; }
%%

48
src/common/Makefile.am Normal file
View File

@ -0,0 +1,48 @@
# This file is processed by GNU automake to generate Makefile.in
AM_CPPFLAGS = \
$(WARNINGCFLAGS) \
-I$(builddir)
VPATH = $(srcdir) $(builddir)
noinst_LIBRARIES = libemu8051.a
BUILT_SOURCES = \
instructions_8051.c instructions_8051.h \
opcodes.h opcodes.c
PERL_SRC = \
opcodes2c.pl \
opcodes.lst
libemu8051_a_SOURCES = \
options.c options.h \
log.c log.h \
hexfile.c hexfile.h \
cpu8051.c cpu8051.h \
memory.c memory.h \
psw.c psw.h \
sfr.c sfr.h \
operations.c operations.h \
timers.c timers.h \
common.h \
reg8051.h
nodist_libemu8051_a_SOURCES = \
$(BUILT_SOURCES)
# These files are generated automatically by a perl script.
$(BUILT_SOURCES) : $(PERL_SRC)
@echo " PERL opcodes2c.pl"
@$(srcdir)/opcodes2c.pl $(srcdir)/opcodes.lst $(builddir)
CLEANFILES = \
*~ \
$(BUILT_SOURCES)
MAINTAINERCLEANFILES = \
Makefile.in
EXTRA_DIST = \
$(PERL_SRC)

48
src/common/common.h Normal file
View File

@ -0,0 +1,48 @@
/*
* common.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef COMMON_H
#define COMMON_H 1
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#if STDC_HEADERS
# include <string.h>
#elif HAVE_STRINGS_H
# include <strings.h>
#endif
#include "log.h"
#define FIXED_FONT "monospace 12"
#define MAX_FILENAME_LENGTH 1024
/* Common constants. */
#ifndef EXIT_SUCCESS
# define EXIT_SUCCESS 0
# define EXIT_FAILURE 1
#endif
/* Returns TRUE if the strings 'a' and 'b' are equal. */
#define STREQ(a, b) (strcasecmp((a), (b)) == 0)
/* Returns TRUE if the first 'c' characters of strings 'a' and 'b' are equal. */
#define STREQ_LEN(a, b, c) (strncasecmp((a), (b), (c)) == 0)
void *
xmalloc(size_t size, const char *filename, int line_number);
#endif /* COMMON_H */

559
src/common/cpu8051.c Normal file
View File

@ -0,0 +1,559 @@
/*
* cpu8051.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
/* Define only here, for not having extern scope on local variables. */
#define CPU8051_M 1
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "common.h"
#include "reg8051.h"
#include "cpu8051.h"
#include "memory.h"
#include "psw.h"
#include "timers.h"
#include "opcodes.h"
#include "options.h"
#include "instructions_8051.h"
extern struct options_t options;
/* Check if the address is a breakpoint */
int
breakpoint_is_defined(unsigned int address)
{
int k;
for (k = 0; k < cpu8051.bp_count; k++) {
if (cpu8051.bp[k] == address)
return true;
}
/* The address was not found in the list of breakpoints */
return false;
}
/* Show Breakpoints list */
void
breakpoints_show(void)
{
int k;
if (cpu8051.bp_count) {
printf("Breakpoints:\n");
for (k = 0; k < cpu8051.bp_count; k++)
printf(" $%.4X\n", cpu8051.bp[k]);
} else {
printf("No breakpoints defined\n");
}
}
/* Set Breakpoint at address at the end of the breakpoint list */
void
breakpoint_set(unsigned int address)
{
int rc;
rc = mem_check_address(PGM_MEM_ID, address, DISPLAY_ERROR_YES);
if (!rc)
return; /* Error */
/* Check if breakpoint is already defined. */
if ((breakpoint_is_defined(address) == false) &&
(cpu8051.bp_count < MAXBP))
cpu8051.bp[cpu8051.bp_count++] = address;
}
/* Clear Breakpoint at Address from list */
void
breakpoint_clr(unsigned int address)
{
int k;
int rc;
rc = mem_check_address(PGM_MEM_ID, address, DISPLAY_ERROR_YES);
if (!rc)
return; /* Error */
/* Check if breakpoint is defined. */
if (breakpoint_is_defined(address) == false) {
log_err("No breakpoint defined at address $%X", address);
return;
}
for (k = 0; k < cpu8051.bp_count; k++) {
if (cpu8051.bp[k] == address) {
/* Fill removed breakpoint slot with last entry */
cpu8051.bp[k] = cpu8051.bp[cpu8051.bp_count - 1];
cpu8051.bp_count--;
}
}
}
/* Clear all breakpoints */
void
breakpoints_clr_all(void)
{
cpu8051.bp_count = 0;
}
/* Toggle the breakpoint at Address. */
void
breakpoint_toggle(unsigned int address)
{
if (breakpoint_is_defined(address))
breakpoint_clr(address);
else
breakpoint_set(address);
}
/* Check if the address is a stop point */
static int
stop_point_is_defined(unsigned int address)
{
if ((options.stop_address != 0) && (options.stop_address == address))
return true;
else
return false;
}
void
cpu8051_init(void)
{
int id;
mem_init();
for (id = 0; id < GP_TIMERS_COUNT; id++)
gp_timer_reset(id);
cpu8051.pc = 0;
cpu8051.clock = 0;
cpu8051.active_priority = -1;
cpu8051.bp_count = 0;
}
/* Reset the registers and CPU state */
void
cpu8051_reset(void)
{
cpu8051.pc = 0;
cpu8051.clock = 0;
cpu8051.active_priority = -1;
/* Clear IRAM and SFR. */
mem_clear(INT_MEM_ID);
mem_sfr_write8(_P0_, 0xFF);
mem_sfr_write8(_P1_, 0xFF);
mem_sfr_write8(_P2_, 0xFF);
mem_sfr_write8(_P3_, 0xFF);
/* The default value of SP (after system reset) is 07 */
mem_sfr_write8(_SP_, 0x07);
}
static int
cpu8051_interrupt_fire(int interrupt_no, int priority)
{
if (mem_read_direct(_IP_) & INTERRUPT_MASK(interrupt_no))
return priority;
else
return !priority;
}
static int
cpu8051_interrupt_enabled(int interrupt_no)
{
return (mem_read_direct(_IE_) & INTERRUPT_MASK(interrupt_no)) ?
1 : 0;
}
static void
cpu8051_process_interrupt(int pc, int pri)
{
stack_push16(cpu8051.pc);
cpu8051.pc = pc;
cpu8051.active_priority = pri;
}
/* Check interrupts state and process them as needed */
static void
cpu8051_check_interrupts(void)
{
int i;
if ((mem_read_direct(_IE_) & 0x80) == 0)
return;
for (i = INTERRUPT_PRIORITY_HIGH; i >= INTERRUPT_PRIORITY_LOW; i--) {
if (cpu8051.active_priority < i) {
/* Interrupt timer 0 */
if (cpu8051_interrupt_enabled(INTERRUPT_1) &&
cpu8051_interrupt_fire(INTERRUPT_1, i) &&
(mem_read_direct(_TCON_) & 0x20)) {
mem_write_direct(
_TCON_,
mem_read_direct(_TCON_) & 0xDF);
cpu8051_process_interrupt(0x0B, i);
return;
}
/* Interrupt timer 1 */
if (cpu8051_interrupt_enabled(INTERRUPT_3) &&
cpu8051_interrupt_fire(INTERRUPT_3, i) &&
(mem_read_direct(_TCON_) & 0x80)) {
mem_write_direct(
_TCON_,
mem_read_direct(_TCON_) & 0x7F);
cpu8051_process_interrupt(0x1B, i);
return;
}
/* Serial Interrupts */
if (cpu8051_interrupt_enabled(INTERRUPT_4) &&
cpu8051_interrupt_fire(INTERRUPT_4, i) &&
(mem_read_direct(_SCON_) & 0x03)) {
cpu8051_process_interrupt(0x23, i);
return;
}
/* Interrupt timer 2 */
if (cpu8051_interrupt_enabled(INTERRUPT_5) &&
cpu8051_interrupt_fire(INTERRUPT_5, i) &&
(mem_read_direct(_T2CON_) & 0x80)) {
cpu8051_process_interrupt(0x2B, i);
return;
}
}
}
}
/* Execute at address cpu8051.pc from PGMMem */
int
cpu8051_exec(void)
{
int i;
int rc;
unsigned char opcode;
int insttiming;
/* Basic address check (may fail later if opcode has operands). */
rc = mem_check_address(PGM_MEM_ID, cpu8051.pc, DISPLAY_ERROR_NO);
if (!rc) {
log_err("Trying to run past program memory limit");
return false; /* Error */
}
opcode = mem_read8(PGM_MEM_ID, cpu8051.pc);
cpu8051.pc++;
insttiming = (*opcode_table[opcode])(); /* Function callback. */
/*
* Parity bit (p): is automatically set or cleared in each machine
* cycle to establish even parity in the accumulator.
*/
psw_compute_parity_bit();
gp_timers_increment(insttiming);
for (i = 0; i < insttiming; i++) {
cpu8051_check_interrupts();
timers_check();
cpu8051.clock++;
}
return true;
}
/*
* Run specified number of instructions, or when encountering a
* breakpoint or a stop point.
* Set instr_count to -1 to disable running for a specific number
* of instructions.
*
* Returns TRUE when a breakpoint is encountered.
*/
int
cpu8051_run(int instr_count, int (*interface_stop)(void))
{
int rc;
int run = true;
int breakpoint_hit = false;
while (run) {
rc = cpu8051_exec();
if (!rc) {
run = false;
} else {
if (instr_count > 0)
instr_count--;
if (instr_count == 0) {
run = false;
log_info("Number of instructions reached");
}
if (breakpoint_is_defined(cpu8051.pc)) {
run = false;
breakpoint_hit = true;
log_info("Breakpoint hit at %.4X", cpu8051.pc);
}
if (stop_point_is_defined(cpu8051.pc)) {
run = false;
log_info("Stoppoint hit at %.4X", cpu8051.pc);
}
if (interface_stop != NULL) {
if (interface_stop()) {
run = false;
log_info("Caught break signal");
}
}
}
}
return breakpoint_hit;
}
/*
* Addressing modes defined in the order as they appear in disasm.h
* from table argstext[]
*/
#define ADDR11 0
#define ADDR16 1
#define DIRECT 3
#define BITADDR 14
#define RELADDR 15
#define DATAIMM 16
#define DATA16 22
#define CBITADDR 23
/*
* SFR Memory map [80h - FFh]
* ---------------------------------------------------------------
* F8 | | | | | | | | | FF
* F0 | B | | | | | | | | F7
* E8 | | | | | | | | | EF
* E0 | ACC | | | | | | | | E7
* D8 | | | | | | | | | DF
* D0 | PSW | | | | | | | | D7
* C8 | T2CON| |RCAP2L|RCAP2H| TL2 | TH2 | | | CF
* C0 | | | | | | | | | C7
* B8 | IP | | | | | | | | BF
* B0 | P3 | | | | | | | | B7
* A8 | IE | | | | | | | | AF
* A0 | P2 | | | | | | | | A7
* 98 | SCON | SBUF | | | | | | | 9F
* 90 | P1 | | | | | | | | 97
* 88 | TCON | TMOD | TL0 | TL1 | TH0 | TH1 | | | 8F
* 80 | P0 | SP | DPL | DPH | | | | PCON | 87
* ---------------------------------------------------------------
*/
/* Return as Text the name of the SFR register at Address if any */
static int
cpu8051_sfr_mem_info(unsigned int address, char *text)
{
switch (address) {
case 0x80: return sprintf(text, "P0");
case 0x81: return sprintf(text, "SP");
case 0x82: return sprintf(text, "DPL");
case 0x83: return sprintf(text, "DPH");
case 0x87: return sprintf(text, "PCON");
case 0x88: return sprintf(text, "TCON");
case 0x89: return sprintf(text, "TMOD");
case 0x8A: return sprintf(text, "TL0");
case 0x8B: return sprintf(text, "TL1");
case 0x8C: return sprintf(text, "TH0");
case 0x8D: return sprintf(text, "TH1");
case 0x90: return sprintf(text, "P1");
case 0x98: return sprintf(text, "SCON");
case 0x99: return sprintf(text, "SBUF");
case 0xA0: return sprintf(text, "P2");
case 0xA8: return sprintf(text, "IE");
case 0xB0: return sprintf(text, "P3");
case 0xB8: return sprintf(text, "IP");
case 0xC8: return sprintf(text, "T2CON");
case 0xCA: return sprintf(text, "RCAP2L");
case 0xCB: return sprintf(text, "RCAP2H");
case 0xCC: return sprintf(text, "TL2");
case 0xCD: return sprintf(text, "TH2");
case 0xD0: return sprintf(text, "PSW");
case 0xE0: return sprintf(text, "ACC");
case 0xF0: return sprintf(text, "B");
default: return sprintf(text, "%.2XH", address);
}
}
/* Return as text the decoded bit address */
static void
cpu8051_int_mem_bit_info(uint8_t bit_address, char *text)
{
uint8_t byte_address;
uint8_t bit_number;
int len;
mem_convert_bit_address(bit_address, &byte_address, &bit_number);
len = cpu8051_sfr_mem_info(byte_address, text);
sprintf(&text[len], ".%X", bit_address);
}
/* Display instruction mnemonic. */
int
cpu8051_disasm_mnemonic(unsigned char opcode, char *buf)
{
return sprintf(buf, "%s", opcodes_get_instr_type_str(opcode));
}
/* Disasm instruction arguments starting at address into a text string */
void
cpu8051_disasm_args(unsigned int address, char *buf)
{
int len = 0;
char str[20];
unsigned char opcode;
int args_table_offset;
int i;
buf[0] = '\0';
opcode = mem_read8(PGM_MEM_ID, address);
args_table_offset = opcode << 2;
address++;
/*
* MOV direct, direct (opcode 85h) is peculiar, the operands
* are inverted
*/
if (opcode == 0x85) {
cpu8051_sfr_mem_info(mem_read8(PGM_MEM_ID, address + 1),
str);
len += sprintf(&buf[len], "%s,", str);
cpu8051_sfr_mem_info(mem_read8(PGM_MEM_ID, address),
str);
len += sprintf(&buf[len], "%s", str);
address += 2;
return;
}
for (i = 1; i <= opcodes_get_instr_arg_type_id(args_table_offset);
i++) {
switch (opcodes_get_instr_arg_type_id(args_table_offset + i)) {
case ADDR11: {
len += sprintf(&buf[len],
"%.4XH", ((opcode << 3) & 0xF00) +
(mem_read8(PGM_MEM_ID, address)));
address++;
break;
}
case ADDR16: {
len += sprintf(
&buf[len], "%.4XH",
((mem_read8(PGM_MEM_ID, address) << 8) +
mem_read8(PGM_MEM_ID, address + 1)));
address += 2;
break;
}
case DIRECT: {
cpu8051_sfr_mem_info(mem_read8(PGM_MEM_ID, address),
str);
len += sprintf(&buf[len], "%s", str);
address++;
break;
}
case BITADDR: {
cpu8051_int_mem_bit_info(
(mem_read8(PGM_MEM_ID, address) & 0xF8),
str);
len += sprintf(&buf[len], "%s.%X" , str,
(mem_read8(PGM_MEM_ID, address) & 7));
address++;
break;
}
case RELADDR: {
address++;
len += sprintf(&buf[len], "%.4XH", (address & 0xFF00) +
(((address & 0xFF) +
mem_read8(PGM_MEM_ID,
address - 1)) & 0xFF));
break;
}
case DATAIMM: {
len += sprintf(&buf[len], "#%.2XH",
mem_read8(PGM_MEM_ID, address));
address++;
break;
}
case DATA16: {
len += sprintf(&buf[len], "#%.4XH",
((mem_read8(PGM_MEM_ID,
address) << 8) +
mem_read8(PGM_MEM_ID, address+1)));
address += 2;
break;
}
case CBITADDR: {
cpu8051_int_mem_bit_info((mem_read8(PGM_MEM_ID,
address) & 0xF8),
str);
len += sprintf(&buf[len], "/%s.%X", str,
(mem_read8(PGM_MEM_ID, address) & 7));
address++;
break;
}
default: {
len += sprintf(&buf[len], "%s",
opcodes_get_instr_arg_type_str(
args_table_offset + i));
}
}
if (i < opcodes_get_instr_arg_type_id(args_table_offset))
len += sprintf(&buf[len], ",");
}
}
/* Disasm one instruction at address into a Text string */
int
cpu8051_disasm(unsigned int address, char *text)
{
int len = 0;
unsigned char opcode;
int inst_size;
int i;
/* Display address. */
len += sprintf(text, " %.4X ", address);
opcode = mem_read8(PGM_MEM_ID, address);
inst_size = opcodes_get_instr_size(opcode);
/* Display hex bytes. */
for (i = 0; i < inst_size; i++)
len += sprintf(&text[len], " %.2X",
mem_read8(PGM_MEM_ID, address + i));
/* Padd remaining area with spaces. */
for (; len < 17;)
len += sprintf(&text[len], " ");
/* Display instruction mnemonic. */
len += cpu8051_disasm_mnemonic(opcode, &text[len]);
/* Padd remaining area with spaces. */
for (; len < 25;)
len += sprintf(&text[len], " ");
/* Display instruction arguments. */
cpu8051_disasm_args(address, &text[len]);
return inst_size;
}

86
src/common/cpu8051.h Normal file
View File

@ -0,0 +1,86 @@
/*
* cpu8051.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef CPU8051_H
#define CPU8051_H 1
#include <stdint.h>
/* Maximum number of BreakPoints */
#define MAXBP 32
#define INTERRUPT_0 (0)
#define INTERRUPT_1 (1)
#define INTERRUPT_2 (2)
#define INTERRUPT_3 (3)
#define INTERRUPT_4 (4)
#define INTERRUPT_5 (5)
#define INTERRUPT_MASK(n) (1 << n)
#define INTERRUPT_PRIORITY_HIGH (1)
#define INTERRUPT_PRIORITY_LOW (0)
struct cpu8051_t {
unsigned int pc; /* Program counter */
unsigned long clock;
int active_priority;
int bp_count;
unsigned int bp[MAXBP]; /* List of breakpoints */
};
/* Exported variables */
#undef _SCOPE_
#ifdef CPU8051_M
# define _SCOPE_ /**/
#else
# define _SCOPE_ extern
#endif
_SCOPE_ struct cpu8051_t cpu8051;
int
breakpoint_is_defined(unsigned int address);
void
breakpoints_show(void);
void
breakpoint_set(unsigned int address);
void
breakpoint_clr(unsigned int address);
void
breakpoints_clr_all(void);
void
breakpoint_toggle(unsigned int address);
void
cpu8051_init(void);
int
cpu8051_exec(void);
int
cpu8051_run(int instr_count, int (*interface_stop)(void));
void
cpu8051_reset(void);
int
cpu8051_disasm_mnemonic(unsigned char opcode, char *buf);
void
cpu8051_disasm_args(unsigned int address, char *buf);
int
cpu8051_disasm(unsigned int address, char *text);
#endif /* CPU8051_H */

205
src/common/hexfile.c Normal file
View File

@ -0,0 +1,205 @@
/*
* Functions for loading an Intel HEX file.
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#if STDC_HEADERS
# include <string.h>
#elif HAVE_STRINGS_H
# include <strings.h>
#endif
#include "common.h"
#include "memory.h"
/* Maximum of 75 digits with 32-bytes data records. */
#define HEXFILE_LINE_BUFFER_LEN 128
static int asciihex2int_error;
int
asciihex2int_get_error(void)
{
return asciihex2int_error;
}
/* Convert integer to ASCII hex string. */
void
int2asciihex(int val, char *str, int width)
{
if (width == 1)
sprintf(str , "%.1X", (uint8_t) val);
else if (width == 2)
sprintf(str , "%.2X", (uint8_t) val);
else if (width == 4)
sprintf(str , "%.4X", (uint16_t) val);
else
sprintf(str , "Err");
}
/*
* Convert ASCII string in hexadecimal notation to integer, up to length
* characters.
* The string contains only [0-9] and [a-f] characters (no "0x" prefix).
*/
static unsigned int
asciihex2int_len(char *str, int length)
{
unsigned int result = 0;
int i, ascii_code;
asciihex2int_error = false;
if (!length || (length > (int) strlen(str)))
length = strlen(str);
for (i = 0; i < length; i++) {
ascii_code = str[i];
if (ascii_code > 0x39)
ascii_code &= 0xDF;
if ((ascii_code >= 0x30 && ascii_code <= 0x39) ||
(ascii_code >= 0x41 && ascii_code <= 0x46)) {
ascii_code -= 0x30;
if (ascii_code > 9)
ascii_code -= 7;
result <<= 4;
result += ascii_code;
} else {
log_err("ASCII to hex conversion failure");
asciihex2int_error = true;
return 0;
}
}
return result;
}
/*
* Convert ASCII string in hexadecimal notation to integer, up to \0 end character.
* The string must not contain prefix "0x", only [0-9] and [a-f] characters.
*/
unsigned int
asciihex2int(char *str)
{
/* Set length to zero to use full length of string. */
return asciihex2int_len(str, 0);
}
/*
* Return value:
* true: success
* false: failure
*/
int
hexfile_load(const char *filename)
{
int i, j, rec_len, load_offset, rec_type, data, checksum;
FILE *fp;
int status;
char line[HEXFILE_LINE_BUFFER_LEN];
int valid = false;
int line_num = 1;
log_debug("LoadHexFile");
if (filename == NULL) {
log_err("No file specified");
return false;
}
/* Trying to open the file. */
fp = fopen(filename, "r");
if (fp == NULL) {
log_err("Error opening hex file <%s>: %s", filename,
strerror(errno));
return false;
}
/* Reading one line of data from the hex file. */
/* char *fgets(char *s, int size, FILE *stream);
Reading stops after an EOF or a newline. If a newline is read, it is
stored into the buffer. A '\0' is stored after the last character
in the buffer.
*/
while (fgets(line, HEXFILE_LINE_BUFFER_LEN, fp) != NULL) {
i = 0;
checksum = 0;
if (line[i++] != ':') {
log_err("hexfile line not beginning with \":\"");
goto close_file;
}
rec_len = asciihex2int_len(&line[i], 2);
i += 2;
checksum += rec_len;
load_offset = asciihex2int_len(&line[i], 4);
checksum += load_offset / 256;
checksum += load_offset % 256;
i += 4;
rec_type = asciihex2int_len(&line[i], 2);
i += 2;
checksum += rec_type;
if (rec_type == 0) {
for (j = 0; j < rec_len; j++) {
data = asciihex2int_len(&line[i], 2);
mem_write8(PGM_MEM_ID,
(unsigned int) (load_offset + j),
(unsigned char) data);
i += 2;
checksum += data;
}
}
/* Read and add checksum value */
checksum += asciihex2int_len(&line[i], 2);
checksum &= 0x000000FF;
if (asciihex2int_error) {
log_err("hexfile parse error at line %d", line_num);
goto close_file;
} else if (checksum) {
log_err("hexfile checksum mismatch");
goto close_file;
}
if (rec_type == 0) {
log_debug("hex record: data");
} else if (rec_type == 1) {
log_debug("hex record: End Of File");
valid = true;
goto close_file;
} else {
log_warn("hex record: Unsupported ($%02X)", rec_type);
}
line_num++;
}
close_file:
status = fclose(fp);
if (status != EXIT_SUCCESS) {
log_err("Error closing hex file");
valid = false;
} else if (!valid) {
log_err("Error parsing hex file");
}
return valid;
}

25
src/common/hexfile.h Normal file
View File

@ -0,0 +1,25 @@
/*
* hexfile.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef HEXFILE_H
#define HEXFILE_H 1
int
asciihex2int_get_error(void);
void
int2asciihex(int val, char *str, int width);
unsigned int
asciihex2int(char *str);
int
hexfile_load(const char *filename);
#endif /* HEXFILE_H */

127
src/common/log.c Normal file
View File

@ -0,0 +1,127 @@
/*
* log.c -- debug functions for logging.
*
* Copyright (C) 2011 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "common.h"
#include "options.h"
#include "log.h"
#define PREFIX_PACKAGE_NAME 1
#define ADD_LINEFEED 1
extern struct options_t options;
static void
log_prefix_package_name(FILE *stream, const char *severity)
{
#if PREFIX_PACKAGE_NAME
/* Printing the name of the program first if desired. */
fprintf(stream, "%s %s: ", PACKAGE_NAME, severity);
#endif /* PREFIX_PACKAGE_NAME */
}
static void
log_suffix_newline(FILE *stream)
{
#if ADD_LINEFEED
fprintf(stream, "\n");
#endif /* ADD_LINEFEED */
}
void
log_debug(const char *format, ...)
{
FILE *stream = stdout;
if (options.log >= LOG_LEVEL_DEBUG) {
va_list ap;
log_prefix_package_name(stream, "debug");
va_start(ap, format);
(void) vfprintf(stream, format, ap);
va_end(ap);
log_suffix_newline(stream);
}
}
void
log_info(const char *format, ...)
{
FILE *stream = stdout;
if (options.log >= LOG_LEVEL_INFO) {
va_list ap;
log_prefix_package_name(stream, "info");
va_start(ap, format);
(void) vfprintf(stream, format, ap);
va_end(ap);
log_suffix_newline(stream);
}
}
void
log_warn(const char *format, ...)
{
FILE *stream = stderr;
if (options.log >= LOG_LEVEL_WARN) {
va_list ap;
log_prefix_package_name(stream, "warn");
va_start(ap, format);
(void) vfprintf(stream, format, ap);
va_end(ap);
log_suffix_newline(stream);
}
}
void
log_err(const char *format, ...)
{
FILE *stream = stderr;
va_list ap;
log_prefix_package_name(stream, "error");
va_start(ap, format);
(void) vfprintf(stream, format, ap);
va_end(ap);
log_suffix_newline(stream);
}
/* Log error message and exits with error code. */
void
log_fail(const char *format, ...)
{
FILE *stream = stderr;
va_list ap;
log_prefix_package_name(stream, "error");
va_start(ap, format);
(void) vfprintf(stream, format, ap);
va_end(ap);
log_suffix_newline(stream);
exit(EXIT_FAILURE);
}

43
src/common/log.h Normal file
View File

@ -0,0 +1,43 @@
/*
* log.h
*
* Copyright (C) 2011 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef LOG_H
#define LOG_H 1
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include "common.h"
enum LOG_LEVEL {
LOG_LEVEL_ERR = 0, /* Display only errors */
LOG_LEVEL_WARN, /* Display warnings */
LOG_LEVEL_INFO, /* Display information messages */
LOG_LEVEL_DEBUG, /* Display all messages */
};
void
log_debug(const char *format, ...);
void
log_info(const char *format, ...);
void
log_warn(const char *format, ...);
void
log_err(const char *format, ...);
/* Log error message and exits with error code. */
void
log_fail(const char *format, ...);
#endif /* LOG_H */

340
src/common/memory.c Normal file
View File

@ -0,0 +1,340 @@
/*
* memory.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "cpu8051.h"
#include "reg8051.h"
#include "hexfile.h"
#include "memory.h"
#include "options.h"
struct mem_infos_t {
int size;
int max_size;
uint8_t *buf;
};
struct mem_infos_t mem_infos[MEM_ID_COUNT];
extern struct options_t options;
/* Init each 8051 memory sections. */
void
mem_init(void)
{
int k;
struct mem_infos_t *m;
/* Set desired and maximum allowable sizes for each memory type. */
mem_infos[PGM_MEM_ID].size = options.pram_size;
mem_infos[PGM_MEM_ID].max_size = PGM_MEM_MAX_SIZE;
mem_infos[INT_MEM_ID].size = options.iram_size;
mem_infos[INT_MEM_ID].max_size = INT_MEM_MAX_SIZE;
mem_infos[EXT_MEM_ID].size = options.xram_size;
mem_infos[EXT_MEM_ID].max_size = EXT_MEM_MAX_SIZE;
/* Verify if desired sizes are valid, and if so allocate memory. */
for (k = 0; k < MEM_ID_COUNT; k++) {
m = &mem_infos[k];
if (m->size > m->max_size) {
log_fail("Memory size invalid (max = %d)", m->max_size);
}
m->buf = malloc(m->size);
if (m->buf == NULL) {
log_fail("%s", strerror(errno));
}
memset(m->buf, 0x00, m->size);
}
}
/* Return true if address is valid, false otherwise. */
int
mem_check_address(enum mem_id_t id, unsigned long address, int display_error)
{
if (address >= (unsigned long) mem_infos[id].max_size) {
if (display_error == DISPLAY_ERROR_YES)
log_err("Address out of range ($%X >= $%X", address,
mem_infos[id].max_size - 1);
return false;
} else {
return true;
}
}
void
mem_convert_bit_address(uint8_t bit_address, uint8_t *byte_address,
uint8_t *bit_number)
{
if (bit_address > 0x7F) {
/* SFR 80-FF */
*byte_address = bit_address & 0xF8;
*bit_number = bit_address & 0x07;
} else {
/* 20-2F */
*byte_address = (bit_address >> 3) + 0x20;
*bit_number = bit_address & 0x07;
}
}
uint8_t *
mem_getbuf(enum mem_id_t id, unsigned long address)
{
return &mem_infos[id].buf[address];
}
void
mem_clear(enum mem_id_t id)
{
memset(mem_infos[id].buf, 0, mem_infos[id].size);
}
void
mem_write8(enum mem_id_t id, unsigned long address, uint8_t value)
{
if (address >= (unsigned long) mem_infos[id].max_size) {
log_err("Error writing to memory ID: %d\n"
" Address (%lu) greater than maximum memory size",
id, address);
return;
} else {
mem_infos[id].buf[address] = value;
}
}
/* Write with a direct addressing mode at Address the new Value */
void
mem_write_direct(unsigned int address, unsigned char value)
{
mem_write8(INT_MEM_ID, address, value);
}
/* Write with an indirect addressing mode at Address the new Value */
void
mem_write_indirect(unsigned int address, unsigned char value)
{
if (address > 0x7F) {
mem_write8(EXT_MEM_ID, address, value);
return;
}
mem_write8(INT_MEM_ID, address, value);
}
/* Write with a bit addressing mode at BitAddress the new Value */
void
mem_write_bit(uint8_t bit_address, uint8_t value)
{
uint8_t byte_address;
uint8_t bit_number;
unsigned char byte_val, byte_mask;
mem_convert_bit_address(bit_address, &byte_address, &bit_number);
byte_mask = ((1 << bit_number) ^ 0xFF);
byte_val = mem_read_direct(byte_address) & byte_mask;
byte_val += value << bit_number;
mem_write_direct(byte_address, byte_val);
}
void
mem_sfr_write8(unsigned long address, uint8_t value)
{
/* SFR registers are from addresses $80 to $FF. */
mem_write8(INT_MEM_ID, address, value);
}
void
mem_sfr_write_dptr(uint16_t value)
{
mem_write8(INT_MEM_ID, _DPTRHIGH_, value >> 8);
mem_write8(INT_MEM_ID, _DPTRLOW_, (uint8_t) value);
}
uint8_t
mem_read8(enum mem_id_t id, unsigned long address)
{
if (address >= (unsigned long) mem_infos[id].max_size) {
log_err("Error reading from memory ID: %d\n"
" Address (%lu) greater than maximum memory size",
id, address);
return 0;
} else {
return mem_infos[id].buf[address];
}
}
/* Read with a direct addressing mode at Address */
unsigned char
mem_read_direct(unsigned int address)
{
if (address > 0xFF)
return mem_read8(EXT_MEM_ID, address);
else
return mem_read8(INT_MEM_ID, address);
}
/* Read with a indirect addressing mode at Address */
unsigned char
mem_read_indirect(unsigned int address)
{
if (address > 0x7F)
return mem_read8(EXT_MEM_ID, address);
else
return mem_read8(INT_MEM_ID, address);
}
/* Read with a bit addressing mode at bit_address */
unsigned char
mem_read_bit(uint8_t bit_address)
{
uint8_t byte_address;
uint8_t bit_number;
unsigned char bit_value;
mem_convert_bit_address(bit_address, &byte_address, &bit_number);
bit_value = (mem_read_direct(byte_address) >> bit_number);
bit_value &= 1;
return bit_value;
}
uint8_t
mem_sfr_read8(unsigned long address)
{
/* SFR registers are from addresses $80 to $FF. */
return mem_read8(INT_MEM_ID, address);
}
uint16_t
mem_sfr_read_dptr(void)
{
return (mem_read8(INT_MEM_ID, _DPTRHIGH_) << 8) +
mem_read8(INT_MEM_ID, _DPTRLOW_);
}
void
stack_push8(uint8_t value)
{
uint8_t sp;
sp = mem_read8(INT_MEM_ID, _SP_);
mem_write8(INT_MEM_ID, ++sp, value);
mem_write8(INT_MEM_ID, _SP_, sp); /* Save new stack pointer */
}
void
stack_push16(uint16_t value)
{
uint8_t sp;
sp = mem_read8(INT_MEM_ID, _SP_);
mem_write8(INT_MEM_ID, ++sp, (uint8_t) value); /* Write LSB */
mem_write8(INT_MEM_ID, ++sp, value >> 8); /* Write MSB */
mem_write8(INT_MEM_ID, _SP_, sp); /* Save new stack pointer */
}
uint8_t
stack_pop8(void)
{
uint8_t sp;
uint8_t value;
sp = mem_read8(INT_MEM_ID, _SP_);
value = mem_read8(INT_MEM_ID, sp--);
mem_write8(INT_MEM_ID, _SP_, sp); /* Save new stack pointer */
return value;
}
uint16_t
stack_pop16(void)
{
uint8_t sp;
uint16_t value;
sp = mem_read8(INT_MEM_ID, _SP_);
value = mem_read8(INT_MEM_ID, sp--) << 8; /* Read MSB */
value |= mem_read8(INT_MEM_ID, sp--); /* Read LSB */
mem_write8(INT_MEM_ID, _SP_, sp); /* Save new stack pointer */
return value;
}
/* Read a 16-bit address from PGM memory, starting at <base> offset */
uint16_t
pgm_read_addr16(uint16_t base)
{
uint16_t addr;
addr = mem_read8(PGM_MEM_ID, base) << 8; /* MSB */
addr |= mem_read8(PGM_MEM_ID, base + 1); /* LSB */
return addr;
}
/* Dump memory */
void
mem_dump(unsigned int address, int size, enum mem_id_t id)
{
int rc;
int offset, col;
if (size == 0) {
log_err("invalid size: 0");
return;
}
/* Validate start address. */
rc = mem_check_address(id, address, DISPLAY_ERROR_YES);
if (!rc) {
/* Validate end address. */
rc = mem_check_address(id, address + (size - 1),
DISPLAY_ERROR_NO);
if (!rc)
log_err("Trying to read beyond memory limit");
}
if (!rc)
return;
for (offset = 0; offset < size; offset += 16) {
uint8_t data[16];
printf("%.4X ", address + offset);
for (col = 0; col < 16; col++) {
data[col] = mem_read8(id, address + offset + col);
printf(" %.2X", data[col]);
}
printf(" ");
/* Display any ASCII characters */
for (col = 0; col < 16; col++) {
if ((int) data[col] >= 32 &&
(int) data[col] <= 126)
printf("%c", (char) data[col]);
else
printf(".");
}
printf("\n");
}
}

107
src/common/memory.h Normal file
View File

@ -0,0 +1,107 @@
/*
* memory.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef MEMORY_H
#define MEMORY_H 1
#include <stdint.h>
#define PGM_MEM_MAX_SIZE 65536
/*
* Direct addressing $00 to $7F = IRAM (8051)
* Direct addressing $80 to $FF = SFR (8051)
* Indirect addressing $80 to $FF = IRAM (8052)
*/
#define INT_MEM_MAX_SIZE 256
#define EXT_MEM_MAX_SIZE 65536
#define PGM_MEM_DEFAULT_SIZE PGM_MEM_MAX_SIZE
#define EXT_MEM_DEFAULT_SIZE 256
enum mem_id_t {
PGM_MEM_ID,
INT_MEM_ID,
EXT_MEM_ID,
MEM_ID_COUNT
};
#define DISPLAY_ERROR_NO 0
#define DISPLAY_ERROR_YES 1
void
mem_init(void);
int
mem_check_address(enum mem_id_t id, unsigned long address, int display_error);
void
mem_convert_bit_address(uint8_t bit_address, uint8_t *byte_address,
uint8_t *bit_number);
uint8_t *
mem_getbuf(enum mem_id_t id, unsigned long address);
void
mem_clear(enum mem_id_t id);
void
mem_write8(enum mem_id_t id, unsigned long address, uint8_t value);
void
mem_write_direct(unsigned int address, unsigned char value);
void
mem_write_indirect(unsigned int address, unsigned char value);
void
mem_write_bit(uint8_t bit_address, uint8_t value);
void
mem_sfr_write8(unsigned long address, uint8_t value);
void
mem_sfr_write_dptr(uint16_t value);
uint8_t
mem_read8(enum mem_id_t id, unsigned long address);
unsigned char
mem_read_direct(unsigned int address);
unsigned char
mem_read_indirect(unsigned int address);
unsigned char
mem_read_bit(uint8_t bit_address);
uint8_t
mem_sfr_read8(unsigned long address);
uint16_t
mem_sfr_read_dptr(void);
void
stack_push8(uint8_t value);
void
stack_push16(uint16_t value);
uint8_t
stack_pop8(void);
uint16_t
stack_pop16(void);
uint16_t
pgm_read_addr16(uint16_t base);
void
mem_dump(unsigned int address, int size, enum mem_id_t id);
#endif /* MEMORY_H */

258
src/common/opcodes.lst Normal file
View File

@ -0,0 +1,258 @@
Opcode Instruction Bytes Cycles
----------------------------------------------
00 NOP 1 1
01 AJMP addr11 2 2
02 LJMP addr16 3 2
03 RR A 1 1
04 INC A 1 1
05 INC direct 2 1
06 INC @R0 1 1
07 INC @R1 1 1
08 INC R0 1 1
09 INC R1 1 1
0A INC R2 1 1
0B INC R3 1 1
0C INC R4 1 1
0D INC R5 1 1
0E INC R6 1 1
0F INC R7 1 1
10 JBC bitaddr,reladdr 3 2
11 ACALL addr11 2 2
12 LCALL addr16 3 2
13 RRC A 1 1
14 DEC A 1 1
15 DEC direct 2 1
16 DEC @R0 1 1
17 DEC @R1 1 1
18 DEC R0 1 1
19 DEC R1 1 1
1A DEC R2 1 1
1B DEC R3 1 1
1C DEC R4 1 1
1D DEC R5 1 1
1E DEC R6 1 1
1F DEC R7 1 1
20 JB bitaddr,reladdr 3 2
21 AJMP addr11 2 2
22 RET 1 2
23 RL A 1 1
24 ADD A,#data 2 1
25 ADD A,direct 2 1
26 ADD A,@R0 1 1
27 ADD A,@R1 1 1
28 ADD A,R0 1 1
29 ADD A,R1 1 1
2A ADD A,R2 1 1
2B ADD A,R3 1 1
2C ADD A,R4 1 1
2D ADD A,R5 1 1
2E ADD A,R6 1 1
2F ADD A,R7 1 1
30 JNB bitaddr,reladdr 3 2
31 ACALL addr11 2 2
32 RETI 1 2
33 RLC A 1 1
34 ADDC A,#data 2 1
35 ADDC A,direct 2 1
36 ADDC A,@R0 1 1
37 ADDC A,@R1 1 1
38 ADDC A,R0 1 1
39 ADDC A,R1 1 1
3A ADDC A,R2 1 1
3B ADDC A,R3 1 1
3C ADDC A,R4 1 1
3D ADDC A,R5 1 1
3E ADDC A,R6 1 1
3F ADDC A,R7 1 1
40 JC reladdr 2 2
41 AJMP addr11 2 2
42 ORL direct,A 2 1
43 ORL direct,#data 3 2
44 ORL A,#data 2 1
45 ORL A,direct 2 1
46 ORL A,@R0 1 1
47 ORL A,@R1 1 1
48 ORL A,R0 1 1
49 ORL A,R1 1 1
4A ORL A,R2 1 1
4B ORL A,R3 1 1
4C ORL A,R4 1 1
4D ORL A,R5 1 1
4E ORL A,R6 1 1
4F ORL A,R7 1 1
50 JNC reladdr 2 2
51 ACALL addr11 2 2
52 ANL direct,A 2 1
53 ANL direct,#data 3 2
54 ANL A,#data 2 1
55 ANL A,direct 2 1
56 ANL A,@R0 1 1
57 ANL A,@R1 1 1
58 ANL A,R0 1 1
59 ANL A,R1 1 1
5A ANL A,R2 1 1
5B ANL A,R3 1 1
5C ANL A,R4 1 1
5D ANL A,R5 1 1
5E ANL A,R6 1 1
5F ANL A,R7 1 1
60 JZ reladdr 2 2
61 AJMP addr11 2 2
62 XRL direct,A 2 1
63 XRL direct,#data 3 2
64 XRL A,#data 2 1
65 XRL A,direct 2 1
66 XRL A,@R0 1 1
67 XRL A,@R1 1 1
68 XRL A,R0 1 1
69 XRL A,R1 1 1
6A XRL A,R2 1 1
6B XRL A,R3 1 1
6C XRL A,R4 1 1
6D XRL A,R5 1 1
6E XRL A,R6 1 1
6F XRL A,R7 1 1
70 JNZ reladdr 2 2
71 ACALL addr11 2 2
72 ORL C,bitaddr 2 2
73 JMP @A+DPTR 1 2
74 MOV A,#data 2 1
75 MOV direct,#data 3 2
76 MOV @R0,#data 2 1
77 MOV @R1,#data 2 1
78 MOV R0,#data 2 1
79 MOV R1,#data 2 1
7A MOV R2,#data 2 1
7B MOV R3,#data 2 1
7C MOV R4,#data 2 1
7D MOV R5,#data 2 1
7E MOV R6,#data 2 1
7F MOV R7,#data 2 1
80 SJMP reladdr 2 2
81 AJMP addr11 2 2
82 ANL C,bitaddr 2 1
83 MOVC A,@A+PC 1 1
84 DIV AB 1 4
85 MOV direct,direct 3 1
86 MOV direct,@R0 2 2
87 MOV direct,@R1 2 2
88 MOV direct,R0 2 2
89 MOV direct,R1 2 2
8A MOV direct,R2 2 2
8B MOV direct,R3 2 2
8C MOV direct,R4 2 2
8D MOV direct,R5 2 2
8E MOV direct,R6 2 2
8F MOV direct,R7 2 2
90 MOV DPTR,#data16 3 2
91 ACALL addr11 2 2
92 MOV bitaddr,C 2 2
93 MOVC A,@A+DPTR 1 2
94 SUBB A,#data 2 1
95 SUBB A,direct 2 1
96 SUBB A,@R0 1 1
97 SUBB A,@R1 1 1
98 SUBB A,R0 1 1
99 SUBB A,R1 1 1
9A SUBB A,R2 1 1
9B SUBB A,R3 1 1
9C SUBB A,R4 1 1
9D SUBB A,R5 1 1
9E SUBB A,R6 1 1
9F SUBB A,R7 1 1
A0 ORL C,/bitaddr 2 1
A1 AJMP addr11 2 2
A2 MOV C,bitaddr 2 1
A3 INC DPTR 1 2
A4 MUL AB 1 4
A5 INVALID 1 1
A6 MOV @R0,direct 2 2
A7 MOV @R1,direct 2 2
A8 MOV R0,direct 2 2
A9 MOV R1,direct 2 2
AA MOV R2,direct 2 2
AB MOV R3,direct 2 2
AC MOV R4,direct 2 2
AD MOV R5,direct 2 2
AE MOV R6,direct 2 2
AF MOV R7,direct 2 2
B0 ANL C,/bitaddr 2 1
B1 ACALL addr11 2 2
B2 CPL bitaddr 2 1
B3 CPL C 1 1
B4 CJNE A,#data,reladdr 3 2
B5 CJNE A,direct,reladdr 3 2
B6 CJNE @R0,#data,reladdr 3 2
B7 CJNE @R1,#data,reladdr 3 2
B8 CJNE R0,#data,reladdr 3 2
B9 CJNE R1,#data,reladdr 3 2
BA CJNE R2,#data,reladdr 3 2
BB CJNE R3,#data,reladdr 3 2
BC CJNE R4,#data,reladdr 3 2
BD CJNE R5,#data,reladdr 3 2
BE CJNE R6,#data,reladdr 3 2
BF CJNE R7,#data,reladdr 3 2
C0 PUSH direct 2 2
C1 AJMP addr11 2 2
C2 CLR bitaddr 2 1
C3 CLR C 1 1
C4 SWAP A 1 1
C5 XCH A,direct 2 1
C6 XCH A,@R0 1 1
C7 XCH A,@R1 1 1
C8 XCH A,R0 1 1
C9 XCH A,R1 1 1
CA XCH A,R2 1 1
CB XCH A,R3 1 1
CC XCH A,R4 1 1
CD XCH A,R5 1 1
CE XCH A,R6 1 1
CF XCH A,R7 1 1
D0 POP direct 2 2
D1 ACALL addr11 2 2
D2 SETB bitaddr 2 1
D3 SETB C 1 1
D4 DA A 1 1
D5 DJNZ direct,reladdr 3 2
D6 XCHD A,@R0 1 1
D7 XCHD A,@R1 1 1
D8 DJNZ R0,reladdr 2 2
D9 DJNZ R1,reladdr 2 2
DA DJNZ R2,reladdr 2 2
DB DJNZ R3,reladdr 2 2
DC DJNZ R4,reladdr 2 2
DD DJNZ R5,reladdr 2 2
DE DJNZ R6,reladdr 2 2
DF DJNZ R7,reladdr 2 2
E0 MOVX A,@DPTR 1 2
E1 AJMP addr11 2 2
E2 MOVX A,@R0 1 2
E3 MOVX A,@R1 1 2
E4 CLR A 1 1
E5 MOV A,direct 2 1
E6 MOV A,@R0 1 1
E7 MOV A,@R1 1 1
E8 MOV A,R0 1 1
E9 MOV A,R1 1 1
EA MOV A,R2 1 1
EB MOV A,R3 1 1
EC MOV A,R4 1 1
ED MOV A,R5 1 1
EE MOV A,R6 1 1
EF MOV A,R7 1 1
F0 MOVX @DPTR,A 1 2
F1 ACALL addr11 2 2
F2 MOVX @R0,A 1 2
F3 MOVX @R1,A 1 2
F4 CPL A 1 1
F5 MOV direct,A 2 1
F6 MOV @R0,A 1 1
F7 MOV @R1,A 1 1
F8 MOV R0,A 1 1
F9 MOV R1,A 1 1
FA MOV R2,A 1 1
FB MOV R3,A 1 1
FC MOV R4,A 1 1
FD MOV R5,A 1 1
FE MOV R6,A 1 1
FF MOV R7,A 1 1

922
src/common/opcodes2c.pl Executable file
View File

@ -0,0 +1,922 @@
#!/usr/bin/perl
#
# Copyright (C) 1999 Jonathan St-André
# Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
#
# This file is released under the GPLv2
# Arg1: opcodes list filename
# Arg2: output directory
if (($#ARGV + 1) < 2) {
die "Missing arguments.\n";
}
my $opcodes_lst_filename = $ARGV[0];
my $builddir = $ARGV[1];
open OPCODELST, $opcodes_lst_filename or die "Error opening " .
$opcodes_lst_filename . " : $!\n";
my $file;
$file = $builddir . "/instructions_8051.h";
open INST_DEF, ">" . $file or die "Error creating <" . $file . "> : $!\n";
$file = $builddir . "/instructions_8051.c";
open INST_IMP, ">" . $file or die "Error creating <" . $file . "> : $!\n";
$file = $builddir . "/opcodes.h";
open OPCODES_DEF, ">" . $file or die "Error creating <" . $file . "> : $!\n";
$file = $builddir . "/opcodes.c";
open OPCODES_IMP, ">" . $file or die "Error creating <" . $file . "> : $!\n";
# Write GPL license
# Argument 0 is file descriptor
sub write_header
{
my $fd = $_[0];
print $fd " *\n";
print $fd " * Do not modify this file directly, as it was created by opcodes2c.pl\n";
print $fd " * Any modifications made directly to this file will be lost.\n";
print $fd " *\n";
print $fd " * Copyright (C) 1999 Jonathan St-André\n";
print $fd " * Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>\n";
print $fd " *\n";
print $fd " * This file is released under the GPLv2\n";
print $fd " */\n\n";
}
# Write C function source code line to INST_IMP file.
# Prefix each line with a tab (indentation) and add newline character at the end.
sub cfw
{
print INST_IMP "\t",$_[0],"\n";
}
# Header for instructions_8051.c
print INST_IMP "/*\n";
print INST_IMP " * instructions_8051.c\n";
write_header(INST_IMP);
print INST_IMP "/* Define only here, for not having extern scope on local variables. */\n";
print INST_IMP "#define INSTRUCTIONS_8051_M 1\n\n\n";
print INST_IMP "#include \"reg8051.h\"\n";
print INST_IMP "#include \"cpu8051.h\"\n";
print INST_IMP "#include \"memory.h\"\n";
print INST_IMP "#include \"psw.h\"\n";
print INST_IMP "#include \"operations.h\"\n";
print INST_IMP "#include \"instructions_8051.h\"\n\n\n";
# Header for opcodes.h
print OPCODES_DEF "/*\n";
print OPCODES_DEF " * opcodes.h\n";
write_header(OPCODES_DEF);
print OPCODES_DEF "#ifndef OPCODES_H\n";
print OPCODES_DEF "#define OPCODES_H 1\n\n";
print OPCODES_DEF "int\n";
print OPCODES_DEF "opcodes_get_instr_size(uint8_t opcode);\n";
print OPCODES_DEF "char *\n";
print OPCODES_DEF "opcodes_get_instr_type_str(uint8_t opcode);\n";
print OPCODES_DEF "int\n";
print OPCODES_DEF "opcodes_get_instr_arg_type_id(unsigned int offset);\n";
print OPCODES_DEF "char *\n";
print OPCODES_DEF "opcodes_get_instr_arg_type_str(unsigned int offset);\n";
# opcodes.c
print OPCODES_IMP "/*\n";
print OPCODES_IMP " * opcodes.c\n";
write_header(OPCODES_IMP);
print OPCODES_IMP "#include <stdint.h>\n\n";
# Column indexes in opcodes.lst table
use constant COL_OPCODE => 0;
use constant COL_INSTR => 1;
use constant COL_ARGS => 2;
use constant COL_COUNT_NO_ARGS => 4;
$nbinst=0;
$nbaddr=0;
$nbargs=0;
$instnumb=0;
# Read file describing each instruction/opcode
# Discard first two lines, which are comments
$ligne = <OPCODELST>;
$ligne = <OPCODELST>;
while($ligne=<OPCODELST>) {
chop $ligne;
if (length $ligne < 2) {
next;
}
@wordlist = split ' ',$ligne;
$nbword = @wordlist;
$instruction = $wordlist[COL_INSTR];
for ($i = (COL_INSTR + 1); $i < ($nbword - 2); $i++) {
$instruction = "$instruction $wordlist[$i]";
}
$a_instruction[$instnumb] = $instruction;
$a_bytes[$instnumb] = $wordlist[$nbword - 2];
$a_cycles[$instnumb] = $wordlist[$nbword - 1];
$a_opcodehex[$instnumb] = $wordlist[COL_OPCODE];
$instfunction[$instnumb] = "CPU8051::OP_$wordlist[COL_OPCODE]";
$instargs[$instnumb << 2] = $instargs[($instnumb << 2) + 1] =
$instargs[($instnumb << 2) + 2] = $instargs[($instnumb << 2) + 3] = 0;
if ($nbword > COL_COUNT_NO_ARGS) {
@argslist = split /\,/,$wordlist[COL_ARGS];
$argslistsize = @argslist;
$instargs[$instnumb << 2] = $argslistsize;
for ($i = 0; $i < $argslistsize; $i++) {
if (not exists $argstypes{$argslist[$i]}) {
$argstypes[$nbargs] = $argslist[$i];
$argstypes{$argslist[$i]} = $nbargs++;
}
$instargs[($instnumb << 2) + $i + 1] = $argstypes{$argslist[$i]};
}
}
if (not exists $insttext{$wordlist[COL_INSTR]}) {
$insttext[$nbinst] = $wordlist[COL_INSTR];
$insttext{$wordlist[COL_INSTR]} = $nbinst++;
}
$insttype[$instnumb] = $insttext{$wordlist[COL_INSTR]};
if (not exists $addrmode{$wordlist[COL_ARGS]}) {
$addrmode[$nbaddr] = $wordlist[COL_ARGS];
$addrmode{$wordlist[COL_ARGS]} = $nbaddr++;
}
$nbbytes[$instnumb] = $wordlist[$nbword - 2];
$instaddr[$instnumb] = $addrmode{$wordlist[COL_ARGS]};
$instnumb++;
}
# ------------------------------------------------------------------------------
print OPCODES_IMP "/* Size(in bytes) of each instruction (offset in table is instruction opcode) */\n";
$nbelement = @nbbytes;
print OPCODES_IMP "static int instr_size[$nbelement] = {";
for ($i = 0; $i < $nbelement; $i++) {
if ($i % 16 == 0) {
print OPCODES_IMP "\n\t";
} else {
print OPCODES_IMP " ";
}
print OPCODES_IMP "$nbbytes[$i],";
}
print OPCODES_IMP "\n";
print OPCODES_IMP "};\n";
print OPCODES_IMP "\n";
# ------------------------------------------------------------------------------
print OPCODES_IMP "/*\n";
print OPCODES_IMP " * For all 256 opcodes, the value in this table gives the instruction type\n";
print OPCODES_IMP " * ex.: MOV, INC, CLR, CPL,...\n";
print OPCODES_IMP " * To know what is the instruction type, use\n";
print OPCODES_IMP " * the number as an offset in instr_type_str[]\n";
print OPCODES_IMP " */\n";
$nbelement = @insttype;
print OPCODES_IMP "static int instr_type_id[$nbelement] = {";
for ($i = 0; $i < $nbelement; $i++) {
if ($i % 16 == 0) {
print OPCODES_IMP "\n\t";
} else {
print OPCODES_IMP " ";
}
print OPCODES_IMP "$insttype[$i],";
}
print OPCODES_IMP "\n";
print OPCODES_IMP "};\n";
print OPCODES_IMP "\n";
# ------------------------------------------------------------------------------
print OPCODES_IMP "/* List of instructions types referenced by instr_type_id[] */\n";
$nbelement = @insttext;
$elementnb = 0;
print OPCODES_IMP "static char *instr_type_str[$nbelement] = {\n";
foreach $instruc (@insttext) {
print OPCODES_IMP "\t\"$instruc\"";
if ($elementnb++ < ($nbelement - 1)) {
print OPCODES_IMP ",";
}
print OPCODES_IMP "\n";
}
print OPCODES_IMP "};\n";
print OPCODES_IMP "\n";
# ------------------------------------------------------------------------------
print OPCODES_IMP "/*\n";
print OPCODES_IMP " * Table describing all arguments types of an instruction\n";
print OPCODES_IMP " * The table is indexed instr_arg_type_id[ opcode * 4]\n";
print OPCODES_IMP " * instr_arg_type_id[opcode*4 + 1] gives number of instruction arguments\n";
print OPCODES_IMP " * instr_arg_type_id[opcode*4 + i] for i=1,2 and 3 gives type of each argument\n";
print OPCODES_IMP " * for most instructions, the 3rd argument isn't used\n";
print OPCODES_IMP " * the argument type is referenced to instr_arg_type_str[]\n";
print OPCODES_IMP " */\n";
$nbelement = @instargs;
print OPCODES_IMP "static int instr_arg_type_id[$nbelement] = {";
for ($i = 0; $i < $nbelement; $i++) {
if ($i % 16 == 0) {
print OPCODES_IMP "\n\t";
} else {
print OPCODES_IMP " ";
}
print OPCODES_IMP "$instargs[$i],";
}
print OPCODES_IMP "\n";
print OPCODES_IMP "};\n";
print OPCODES_IMP "\n";
# ------------------------------------------------------------------------------
print OPCODES_IMP "/*\n";
print OPCODES_IMP " * List all types of arguments available to instructions\n";
print OPCODES_IMP " * Referenced by instr_arg_type_id[]\n";
print OPCODES_IMP " */\n";
$nbelement = @argstypes;
$elementnb = 0;
print OPCODES_IMP "static char *instr_arg_type_str[$nbelement] = {\n";
foreach $args (@argstypes) {
print OPCODES_IMP "\t\"$args\"";
if ($elementnb++ < $nbelement-1) {
print OPCODES_IMP ",";
}
print OPCODES_IMP "\n";
}
print OPCODES_IMP "};\n";
print OPCODES_IMP "\n";
print OPCODES_IMP "int\n";
print OPCODES_IMP "opcodes_get_instr_size(uint8_t opcode)\n";
print OPCODES_IMP "{\n";
print OPCODES_IMP "\treturn instr_size[opcode];\n";
print OPCODES_IMP "}\n";
print OPCODES_IMP "\n";
print OPCODES_IMP "char *\n";
print OPCODES_IMP "opcodes_get_instr_type_str(uint8_t opcode)\n";
print OPCODES_IMP "{\n";
print OPCODES_IMP "\treturn instr_type_str[instr_type_id[opcode]];\n";
print OPCODES_IMP "}\n";
print OPCODES_IMP "\n";
print OPCODES_IMP "int\n";
print OPCODES_IMP "opcodes_get_instr_arg_type_id(unsigned int offset)\n";
print OPCODES_IMP "{\n";
print OPCODES_IMP "\treturn instr_arg_type_id[offset];\n";
print OPCODES_IMP "}\n";
print OPCODES_IMP "\n";
print OPCODES_IMP "char *\n";
print OPCODES_IMP "opcodes_get_instr_arg_type_str(unsigned int offset)\n";
print OPCODES_IMP "{\n";
print OPCODES_IMP "\treturn instr_arg_type_str[instr_arg_type_id[offset]];\n";
print OPCODES_IMP "}\n";
print OPCODES_IMP "\n";
# ------------------------------------------------------------------------------
for ($i = 0 ; $i < 256; $i++) {
print INST_IMP "/*","*"x76,"\n";
print INST_IMP " * Instruction \"$a_instruction[$i]\" takes $a_cycles[$i] cycle(s) and $a_bytes[$i] byte(s).\n";
print INST_IMP " ","*"x76,"/\n";
print INST_IMP "int\n";
print INST_IMP "cpu8051_OP_$a_opcodehex[$i](void)\n";
print INST_IMP "{\n";
if( $i == 0x85 ) {
# Cas particulier pour MOV direct,direct -> src et dest sont inverses dans la memoire
print INST_IMP " unsigned char srcaddr = mem_read8( PGM_MEM_ID, cpu8051.pc++ );\n";
print INST_IMP " unsigned char source = mem_read_direct( srcaddr );\n";
print INST_IMP " unsigned char destaddr = mem_read8( PGM_MEM_ID, cpu8051.pc++ );\n";
print INST_IMP " unsigned char destination = mem_read_direct( destaddr );\n";
print INST_IMP " destination = source;\n";
print INST_IMP " mem_write_direct( destaddr, destination );\n";
}
else {
if ($instargs[$i*4] > 0) {
$op_destination=$instargs[$i*4+1];
if ($op_destination == 0) { # addr11
cfw("unsigned int addr11 = ( ( mem_read8( PGM_MEM_ID, cpu8051.pc - 1 ) << 3 ) & 0xF00 ) + mem_read8( PGM_MEM_ID, cpu8051.pc );");
cfw("cpu8051.pc++;");
}
if ($op_destination == 1) { # addr16
cfw("uint16_t addr16 = pgm_read_addr16(cpu8051.pc);");
cfw("cpu8051.pc += 2;");
}
if ($op_destination == 2) { # A
cfw("unsigned char destination = mem_read_direct( _ACC_ );");
}
if ($op_destination == 3) { # direct
cfw("unsigned char destaddr = mem_read8( PGM_MEM_ID, cpu8051.pc++ );");
cfw("unsigned char destination = mem_read_direct( destaddr );");
}
if ($op_destination == 4) { # @R0
cfw("unsigned char destination = mem_read_indirect ( mem_read_direct( BANKPSW + _R0_ ) );");
}
if ($op_destination == 5) { # @R1
cfw("unsigned char destination = mem_read_indirect ( mem_read_direct( BANKPSW + _R1_ ) );");
}
if ($op_destination == 6) { # R0
cfw("unsigned char destination = mem_read_direct( BANKPSW + _R0_ );");
}
if ($op_destination == 7) { # R1
cfw("unsigned char destination = mem_read_direct( BANKPSW + _R1_ );");
}
if ($op_destination == 8) { # R2
cfw("unsigned char destination = mem_read_direct( BANKPSW + _R2_ );");
}
if ($op_destination == 9) { # R3
cfw("unsigned char destination = mem_read_direct( BANKPSW + _R3_ );");
}
if ($op_destination == 10) { # R4
cfw("unsigned char destination = mem_read_direct( BANKPSW + _R4_ );");
}
if ($op_destination == 11) { # R5
cfw("unsigned char destination = mem_read_direct( BANKPSW + _R5_ );");
}
if ($op_destination == 12) { # R6
cfw("unsigned char destination = mem_read_direct( BANKPSW + _R6_ );");
}
if ($op_destination == 13) { # R7
cfw("unsigned char destination = mem_read_direct( BANKPSW + _R7_ );");
}
if ($op_destination == 14) { # bitaddr
cfw("unsigned char destination, dstbitaddr = mem_read8( PGM_MEM_ID, cpu8051.pc++ );");
cfw("destination = mem_read_bit( dstbitaddr );");
}
if ($op_destination == 15) { # reladdr
cfw("cpu8051.pc++;");
cfw("unsigned int destination = ((char) mem_read8(PGM_MEM_ID, cpu8051.pc - 1)) + cpu8051.pc;");
}
if ($op_destination == 16) { # #data
cfw("unsigned char destination = mem_read8( PGM_MEM_ID, cpu8051.pc++ );");
}
if ($op_destination == 17) { # C
cfw("unsigned char destination = psw_read_cy();");
}
if ($op_destination == 18) { # @A+DPTR
cfw("unsigned int destination = mem_read_direct( _ACC_ ) + mem_sfr_read_dptr();");
}
if ($op_destination == 20) { # AB
cfw("unsigned char destination = mem_read_direct( _ACC_ );");
cfw("unsigned char source = mem_read_direct( _B_ );");
}
if ($op_destination == 21) { # DPTR
cfw("unsigned int destination = mem_sfr_read_dptr();");
}
if ($op_destination == 23) { # /bitaddr
cfw("unsigned char destination, dstbitaddr = mem_read8( PGM_MEM_ID, (cpu8051.pc)++ );");
cfw("destination = ( mem_read_bit( dstbitaddr ) ^ 1 );");
}
if ($op_destination == 24) { # @DPTR
cfw("unsigned char destination = mem_read_indirect(mem_sfr_read_dptr());");
}
}
if ($instargs[$i*4] > 1) {
$op_source=$instargs[$i*4+2];
if ($op_source == 0) { # addr11
cfw("unsigned int addr11 = ( ( mem_read8( PGM_MEM_ID, cpu8051.pc - 1 ) << 3 ) & 0xF00 ) + mem_read8( PGM_MEM_ID, (cpu8051.pc)++ );");
}
if ($op_source == 1) { # addr16
cfw("uint16_t addr16 = pgm_read_addr16(cpu8051.pc);");
cfw("cpu8051.pc += 2;");
}
if ($op_source == 2) { # A
cfw("unsigned char source = mem_read_direct( _ACC_ );");
}
if ($op_source == 3) { # direct
cfw("unsigned char srcaddr = mem_read8( PGM_MEM_ID, (cpu8051.pc)++ );");
cfw("unsigned char source = mem_read_direct( srcaddr );");
}
if ($op_source == 4) { # @R0
cfw("unsigned char source = mem_read_indirect ( mem_read_direct( BANKPSW + _R0_ ) );");
}
if ($op_source == 5) { # @R1
cfw("unsigned char source = mem_read_indirect ( mem_read_direct( BANKPSW + _R1_ ) );");
}
if ($op_source == 6) { # R0
cfw("unsigned char source = mem_read_direct( BANKPSW + _R0_ );");
}
if ($op_source == 7) { # R1
cfw("unsigned char source = mem_read_direct( BANKPSW + _R1_ );");
}
if ($op_source == 8) { # R2
cfw("unsigned char source = mem_read_direct( BANKPSW + _R2_ );");
}
if ($op_source == 9) { # R3
cfw("unsigned char source = mem_read_direct( BANKPSW + _R3_ );");
}
if ($op_source == 10) { # R4
cfw("unsigned char source = mem_read_direct( BANKPSW + _R4_ );");
}
if ($op_source == 11) { # R5
cfw("unsigned char source = mem_read_direct( BANKPSW + _R5_ );");
}
if ($op_source == 12) { # R6
cfw("unsigned char source = mem_read_direct( BANKPSW + _R6_ );");
}
if ($op_source == 13) { # R7
cfw("unsigned char source = mem_read_direct( BANKPSW + _R7_ );");
}
if ($op_source == 14) { # bitaddr
cfw("unsigned char source, srcbitaddr = mem_read8( PGM_MEM_ID, (cpu8051.pc)++ );");
cfw("source = mem_read_bit( srcbitaddr );");
}
if ($op_source == 15) { # reladdr
cfw("(cpu8051.pc)++;");
cfw("unsigned int source = ((char) mem_read8(PGM_MEM_ID, cpu8051.pc - 1)) + cpu8051.pc;");
}
if ($op_source == 16) { # #data
cfw("unsigned char source = mem_read8( PGM_MEM_ID, (cpu8051.pc)++ );");
}
if ($op_source == 17) { # C
cfw("unsigned char source = psw_read_cy();");
}
if ($op_source == 18) { # @A+DPTR
cfw("unsigned char source = mem_read8( PGM_MEM_ID, mem_read_direct( _ACC_ ) + mem_sfr_read_dptr());");
}
if ($op_source == 19) { # @A+PC
cfw("unsigned char source = mem_read8( PGM_MEM_ID, mem_read_direct( _ACC_ ) + ( ++cpu8051.pc ) );");
}
if ($op_source == 21) { # DPTR
cfw("unsigned int source = mem_sfr_read_dptr();");
}
if ($op_source == 22) { # #data16
cfw("uint16_t source = pgm_read_addr16(cpu8051.pc);");
cfw("cpu8051.pc += 2;");
}
if ($op_source == 23) { # /bitaddr
cfw("unsigned char source, srcbitaddr = mem_read8( PGM_MEM_ID, (cpu8051.pc)++ );");
cfw("source = ( mem_read_bit( srcbitaddr ) ^ 1 );");
}
if ($op_source == 24) { # @DPTR
cfw("unsigned char source = mem_read_indirect(mem_sfr_read_dptr());");
}
}
##############################################################################
$modifysrc=0;
# RR
if ($insttype[$i] == 3) {
cfw("destination = ( destination >> 1 ) | ( destination << 7 );");
}
# INC
if ($insttype[$i] == 4) {
cfw("destination++;");
}
# JBC
if ($insttype[$i] == 5) {
cfw("if ( destination == 1 ) { cpu8051.pc = source; destination = 0; }");
}
# ACALL
if ($insttype[$i] == 6) {
cfw("stack_push16(cpu8051.pc);");
}
# LCALL
if ($insttype[$i] == 7) {
cfw("stack_push16(cpu8051.pc);");
}
# RRC
if ($insttype[$i] == 8) {
cfw("unsigned char new_cy = destination & 0x01;");
cfw("destination = ( destination >> 1 ) | (psw_read_cy() << 7);");
cfw("psw_write_cy(new_cy);");
}
# DEC
if ($insttype[$i] == 9) {
cfw("destination--;");
}
# JB
if ($insttype[$i] == 10) {
cfw("if ( destination == 1 ) { cpu8051.pc = source; }");
}
# RET
if ($insttype[$i] == 11) {
cfw("cpu8051.pc = stack_pop16();");
}
# RL
if ($insttype[$i] == 12) {
cfw("destination = ( destination << 1 ) | ( destination >> 7 );");
}
# ADD
if ($insttype[$i] == 13) {
cfw("destination = addition(destination, source, 0);");
}
# JNB
if ($insttype[$i] == 14) {
cfw("if ( destination == 0 ) { cpu8051.pc = source; }");
}
# RETI
if ($insttype[$i] == 15) {
cfw("cpu8051.active_priority = -1;");
cfw("cpu8051.pc = stack_pop16();");
}
# RLC
if ($insttype[$i] == 16) {
cfw("unsigned char new_cy = destination & 0x80;");
cfw("destination = ( destination << 1 ) | psw_read_cy();");
cfw("psw_write_cy(new_cy);");
}
# ADDC
# ADD and ADDC function identically except that ADDC adds the value of
# operand as well as the value of the Carry flag whereas ADD does not
# add the Carry flag to the result.
if ($insttype[$i] == 17) {
cfw("unsigned char carryflag = psw_read_cy();");
cfw("destination = addition(destination, source, carryflag);");
}
# JC
if ($insttype[$i] == 18) {
cfw("if (psw_read_cy()) { cpu8051.pc = destination; }");
}
# ORL
if ($insttype[$i] == 19) {
cfw("destination |= source;");
}
# JNC
if ($insttype[$i] == 20) {
cfw("if (psw_read_cy() == 0) { cpu8051.pc = destination; }");
}
# ANL
if ($insttype[$i] == 21) {
cfw("destination &= source;");
}
# JZ
if ($insttype[$i] == 22) {
cfw("if ( mem_read_direct( _ACC_ ) == 0 ) { cpu8051.pc = destination; }");
}
# XRL
if ($insttype[$i] == 23) {
cfw("destination ^= source;");
}
# JNZ
if ($insttype[$i] == 24) {
cfw("if ( mem_read_direct( _ACC_ ) != 0 ) { cpu8051.pc = destination; }");
}
# JMP
if ($insttype[$i] == 25) {
cfw("cpu8051.pc = destination;");
}
# MOV
if ($insttype[$i] == 26) {
cfw("destination = source;");
}
# SJMP
if ($insttype[$i] == 27) {
cfw("cpu8051.pc = destination;");
}
# MOVC
if ($insttype[$i] == 28) {
cfw("destination = source;");
}
# DIV
if ($insttype[$i] == 29) {
# A = destination
# B = source
cfw("psw_clr_cy();");
# If B is zero, the OV flag will be set indicating a
# division-by-zero error
cfw("if (source != 0) {");
cfw(" mem_write_direct(_ACC_, destination/source);");
cfw(" mem_write_direct( _B_, destination%source);");
cfw(" psw_clr_ov();");
cfw("} else {");
cfw(" psw_set_ov();");
cfw("}");
}
# SUBB
if ($insttype[$i] == 30) {
cfw("unsigned char carryflag = psw_read_cy();");
cfw("psw_clr_cy();");
cfw("psw_clr_ac();");
cfw("psw_clr_ov();");
cfw("if ( destination < ( source + carryflag ) ) {");
cfw(" psw_set_cy();");
cfw(" if ((destination & 0x7F) > ((source + carryflag) & 0x7F)) psw_set_ov();");
cfw("} else if ((destination & 0x7F) < ((source + carryflag) & 0x7F)) psw_set_ov();");
cfw("if ((destination & 0x0F) < ((source + carryflag) & 0x0F)) psw_set_ac();");
cfw("destination -= source + carryflag;");
}
# MUL
if ($insttype[$i] == 31) {
# A = destination
# B = source
cfw("psw_clr_cy();");
cfw("mem_write_direct(_ACC_, destination * source);");
cfw("mem_write_direct(_B_, (destination * source) / 0x100);");
cfw("if (mem_read_direct(_B_) > 0)");
cfw(" psw_set_ov();");
cfw("else");
cfw(" psw_clr_ov();");
}
# CPL
if ($insttype[$i] == 33) {
if ($instargs[$i*4+1] == 2) { cfw("destination ^= 0xFF;"); }
else { cfw("destination ^= 0x01;"); }
}
# CJNE
if ($insttype[$i] == 34) {
cfw("unsigned int reladdr = ((char) mem_read8(PGM_MEM_ID, cpu8051.pc)) + (cpu8051.pc + 1);");
cfw("psw_clr_cy();");
cfw("if ( destination < source ) psw_set_cy();");
cfw("if ( destination != source ) cpu8051.pc = reladdr; else cpu8051.pc++;");
}
# PUSH
if ($insttype[$i] == 35) {
cfw("stack_push8(destination);");
}
# CLR
if ($insttype[$i] == 36) {
cfw("destination = 0;");
}
# SWAP
if ($insttype[$i] == 37) {
cfw("destination = ( destination << 4 ) + ( destination >> 4 );");
}
# XCH
if ($insttype[$i] == 38) {
cfw("unsigned char tmpval = destination;");
cfw("destination = source; source = tmpval;");
$modifysrc=1;
}
# POP
if ($insttype[$i] == 39) {
cfw("destination = stack_pop8();");
}
# SETB
if ($insttype[$i] == 40) {
cfw("destination = 1;");
}
# DA
if ($insttype[$i] == 41) {
cfw("if (((destination & 0x0F) > 9) || psw_read_ac()) {");
cfw(" if ( ( destination + 6 ) > 0xFF) psw_set_cy();");
cfw(" destination += 6;");
cfw("}");
cfw("if ( psw_read_cy() || ( ( destination & 0xF0 ) > 0x90 ) ) {");
cfw(" if ( ( destination + 0x60 ) > 0xFF ) psw_set_cy();");
cfw(" destination += 0x60;");
cfw("}");
}
# DJNZ
if ($insttype[$i] == 42) {
cfw("destination--;");
cfw("if ( destination != 0 ) cpu8051.pc = source;");
}
# XCHD
if ($insttype[$i] == 43) {
cfw("unsigned char tmpval = ( destination & 0x0F );");
cfw("destination = ( destination & 0xF0 ) + ( source & 0x0F );");
cfw("source = ( source & 0xF0 ) + tmpval;");
$modifysrc=1;
}
# MOVX
if ($insttype[$i] == 44) {
cfw("destination = source;");
}
##############################################################################
if ($instargs[$i*4] > 0) {
$op_destination=$instargs[$i*4+1];
if ($op_destination == 0) { # addr11
cfw("cpu8051.pc = ( cpu8051.pc & 0xF800 ) | addr11;");
}
if ($op_destination == 1) { # addr16
cfw("cpu8051.pc = addr16;");
}
if ($op_destination == 2) { # A
cfw("mem_write_direct( _ACC_, destination );");
}
if ($op_destination == 3) { # direct
cfw("mem_write_direct( destaddr, destination );");
}
if ($op_destination == 4) { # @R0
cfw("mem_write_indirect( mem_read_direct( BANKPSW + _R0_ ), destination );");
}
if ($op_destination == 5) { # @R1
cfw("mem_write_indirect( mem_read_direct( BANKPSW + _R1_ ), destination );");
}
if ($op_destination == 6) { # R0
cfw("mem_write_direct( BANKPSW + _R0_, destination );");
}
if ($op_destination == 7) { # R1
cfw("mem_write_direct( BANKPSW + _R1_, destination );");
}
if ($op_destination == 8) { # R2
cfw("mem_write_direct( BANKPSW + _R2_, destination );");
}
if ($op_destination == 9) { # R3
cfw("mem_write_direct( BANKPSW + _R3_, destination );");
}
if ($op_destination == 10) { # R4
cfw("mem_write_direct( BANKPSW + _R4_, destination );");
}
if ($op_destination == 11) { # R5
cfw("mem_write_direct( BANKPSW + _R5_, destination );");
}
if ($op_destination == 12) { # R6
cfw("mem_write_direct( BANKPSW + _R6_, destination );");
}
if ($op_destination == 13) { # R7
cfw("mem_write_direct( BANKPSW + _R7_, destination );");
}
if ($op_destination == 14) { # bitaddr
cfw("mem_write_bit( dstbitaddr, destination );");
}
if ($op_destination == 17) { # C
cfw("psw_write_cy(destination);");
}
if ($op_destination == 21) { # DPTR
cfw("mem_sfr_write_dptr(destination);");
}
if ($op_destination == 23) { # /bitaddr
cfw("mem_write_bit( dstbitaddr, destination );");
}
if ($op_destination == 24) { # @DPTR
cfw("mem_write_indirect(mem_sfr_read_dptr(), destination);");
}
}
if ($modifysrc == 1) {
if ($instargs[$i*4] > 1) {
$op_source=$instargs[$i*4+2];
if ($op_source == 0) { # addr11
cfw("cpu8051.pc = ( cpu8051.pc & 0xF800 ) | addr11;");
}
if ($op_source == 1) { # addr16
cfw("cpu8051.pc = addr16;");
}
if ($op_source == 2) { # A
cfw("mem_write_direct( _ACC_, source );");
}
if ($op_source == 3) { # direct
cfw("mem_write_direct( srcaddr, source );");
}
if ($op_source == 4) { # @R0
cfw("mem_write_indirect( mem_read_direct( BANKPSW + _R0_ ), source );");
}
if ($op_source == 5) { # @R1
cfw("mem_write_indirect( mem_read_direct( BANKPSW + _R1_ ), source );");
}
if ($op_source == 6) { # R0
cfw("mem_write_direct( BANKPSW + _R0_, source );");
}
if ($op_source == 7) { # R1
cfw("mem_write_direct( BANKPSW + _R1_, source );");
}
if ($op_source == 8) { # R2
cfw("mem_write_direct( BANKPSW + _R2_, source );");
}
if ($op_source == 9) { # R3
cfw("mem_write_direct( BANKPSW + _R3_, source );");
}
if ($op_source == 10) { # R4
cfw("mem_write_direct( BANKPSW + _R4_, source );");
}
if ($op_source == 11) { # R5
cfw("mem_write_direct( BANKPSW + _R5_, source );");
}
if ($op_source == 12) { # R6
cfw("mem_write_direct( BANKPSW + _R6_, source );");
}
if ($op_source == 13) { # R7
cfw("mem_write_direct( BANKPSW + _R7_, source );");
}
if ($op_source == 14) { # bitaddr
cfw("mem_write_bit( srcbitaddr, source );");
}
if ($op_source == 17) { # C
cfw("psw_write_cy(source);");
}
if ($op_source == 21) { # DPTR
cfw("mem_sfr_write_dptr(source);");
}
if ($op_source == 23) { # /bitaddr
cfw("mem_write_bit( srcbitaddr, source );");
}
if ($op_source == 24) { # @DPTR
cfw("mem_write_indirect(mem_sfr_read_dptr(), source);");
}
}
}
}
cfw("return $a_cycles[$i];");
print INST_IMP "}\n";
print INST_IMP "\n";
}
# ------------------------------------------------------------------------------
# Header for instructions_8051.h
print INST_DEF "/*\n";
print INST_DEF " * instructions_8051.h\n";
write_header(INST_DEF);
print INST_DEF "#ifndef INSTRUCTIONS_8051_H\n";
print INST_DEF "#define INSTRUCTIONS_8051_H 1\n\n\n";
print INST_DEF "#define BANKPSW (mem_read_direct(_PSW_) & 0x18)\n\n";
print INST_DEF "typedef int (*OPCODE_FP)(void);\n\n\n";
for( $i=0; $i<256; $i++ ) {
print INST_DEF "int\n";
print INST_DEF "cpu8051_OP_$a_opcodehex[$i](void);\n\n";
}
print INST_DEF "\n";
print INST_DEF "/* Exported variables. */\n";
print INST_DEF "#ifdef INSTRUCTIONS_8051_M\n";
print INST_DEF "OPCODE_FP opcode_table[256] = {\n";
for ($i = 0; $i < 256; $i++) {
$ifunc = substr($instfunction[$i], 9);
print INST_DEF "\tcpu8051_$ifunc,\n";
}
print INST_DEF "};\n";
print INST_DEF "#else\n";
print INST_DEF "OPCODE_FP opcode_table[256];\n";
print INST_DEF "#endif\n\n\n";
print INST_DEF "#endif /* INSTRUCTIONS_8051_H */\n";
print OPCODES_DEF "#endif /* OPCODES_IMP */\n";
close OPCODES_DEF;
close OPCODES_IMP;
close OPCODELST;
close INST_DEF;
close INST_IMP;

56
src/common/operations.c Normal file
View File

@ -0,0 +1,56 @@
/*
* operations.c
*
* Copyright (C) 2014 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include "common.h"
#include "reg8051.h"
#include "cpu8051.h"
#include "sfr.h"
#include "psw.h"
#include "memory.h"
#include "operations.h"
/*
* ADD and ADDC function identically except that ADDC adds the value of operand
* as well as the value of the Carry flag whereas ADD does not add the Carry
* flag to the result.
*/
int
addition(int dst, int src, int carry)
{
psw_clr_cy();
psw_clr_ac();
psw_clr_ov();
/*
* The Overflow (OV) bit is set if there is a carry-out of bit 6 or
* out of bit 7, but not both. In other words, if the addition of the
* Accumulator, operand and (in the case of ADDC) the Carry flag
* treated as signed values results in a value that is out of the
* range of a signed byte (-128 through +127) the Overflow flag is
* set. Otherwise, the Overflow flag is cleared.
*/
if (dst + src + carry > 0xFF) {
/* Carry from bit 7. */
psw_set_cy();
if (((dst & 0x7F) + (src & 0x7F) + carry) < 0x80)
psw_set_ov(); /* If no carry from bit 6, set OV. */
} else if (((dst & 0x7F) + (src & 0x7F) + carry) > 0x7F) {
/* If no carry from bit 7, but carry from bit 6, set OV. */
psw_set_ov();
}
if (((dst & 0x0F) + (src & 0x0F) + carry) > 0x0F)
psw_set_ac();
return dst + src + carry;
}

15
src/common/operations.h Normal file
View File

@ -0,0 +1,15 @@
/*
* operations.h
*
* Copyright (C) 2014 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef OPERATIONS_H
#define OPERATIONS_H 1
int
addition(int dest, int src, int carry);
#endif /* OPERATIONS_H */

184
src/common/options.c Normal file
View File

@ -0,0 +1,184 @@
/*
* options.c -- functions for processing command-line options and arguments
*
* Copyright (C) 2011 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <argp.h>
#if STDC_HEADERS
# include <string.h>
#elif HAVE_STRINGS_H
# include <strings.h>
#endif
#include "common.h"
#include "options.h"
#include "memory.h"
const char *argp_program_version = PACKAGE_VERSION;
const char *argp_program_bug_address = PACKAGE_BUGREPORT;
/*
* Program documentation.
* Adjacent string constants are concatenated as one string constant.
*/
static const char str_doc[] = PACKAGE_NAME " -- " PACKAGE_DESCRIPTION;
/* How many non-option arguments we accept. */
#define ARGS_COUNT 1
/* A description of the non-option arguments we accept. */
static const char args_doc[] = "[FILENAME]";
/* The options we understand. */
static struct argp_option argp_options[] = {
{"debug", 'd', "level", 0, "Produce debugging output", 0},
{"geometry", 'g', "pos", 0, "Set geometry", 0},
{"pram", 'p', "size", 0, "Set program memory size", 0},
{"xram", 'x', "size", 0,
"Set external ram size (default is 1024)", 0},
{"stop", 's', "addr", 0,
"Automatically run program and stop at address", 0},
{NULL, 0, NULL, 0, NULL, 0}
};
struct options_t options;
static void
decode_debug_option(char *arg, struct argp_state *state)
{
char *endptr;
int log_level;
log_level = (int) strtol(arg, &endptr, 0);
if (*endptr != '\0') {
log_err("Invalid log level");
argp_usage(state);
}
if (log_level > LOG_LEVEL_DEBUG) {
log_err("Invalid log level (0 to 3)");
argp_usage(state);
}
options.log = log_level;
}
static void
decode_memory_size(char *arg, struct argp_state *state, int memid)
{
char *endptr;
int *dest;
if (memid == PGM_MEM_ID)
dest = &options.pram_size;
else if (memid == INT_MEM_ID)
dest = &options.iram_size;
else if (memid == EXT_MEM_ID)
dest = &options.xram_size;
else
exit(EXIT_FAILURE); /* Programming error. */
/*
* Sizes versus max memory sizes will be checked when calling
* memory_init().
*/
*dest = (int) strtol(arg, &endptr, 0);
if (*endptr != '\0') {
log_err("Invalid memory size");
argp_usage(state);
}
}
static void
decode_address(char *arg, struct argp_state *state, uint16_t *dest)
{
char *endptr;
*dest = (uint16_t) strtol(arg, &endptr, 0);
if (*endptr != '\0') {
log_err("Invalid address");
argp_usage(state);
}
}
/* Parse a single option. */
static error_t
parse_opt(int key, char *arg, struct argp_state *state)
{
switch (key) {
case 'd':
decode_debug_option(arg, state);
break;
case 'g':
options.g = arg;
break;
case 'i':
decode_memory_size(arg, state, INT_MEM_ID);
break;
case 'p':
decode_memory_size(arg, state, PGM_MEM_ID);
break;
case 's':
decode_address(arg, state, &options.stop_address);
break;
case 'x':
decode_memory_size(arg, state, EXT_MEM_ID);
break;
case ARGP_KEY_ARG:
if (state->arg_num >= ARGS_COUNT) {
/* Too many arguments. */
argp_usage(state);
}
options.filename = arg;
break;
case ARGP_KEY_END:
if (state->arg_num < ARGS_COUNT) {
/* Not enough arguments, but the filename is optional.
So no error. */
}
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
/* Our argp parser. */
static struct argp argp = {argp_options, parse_opt, args_doc, str_doc,
NULL, NULL, NULL};
/* Initializes the different options passed as arguments on the command line. */
void
parse_command_line_options(int argc, char *argv[])
{
error_t rc;
/* Setting default values. */
options.filename = NULL;
options.g = NULL;
options.pram_size = PGM_MEM_DEFAULT_SIZE;
options.iram_size = INT_MEM_MAX_SIZE;
options.xram_size = EXT_MEM_DEFAULT_SIZE;
options.log = LOG_LEVEL_ERR;
options.stop_address = 0; /* 0 means stop address is disabled. */
/* Parse our arguments. */
rc = argp_parse(&argp, argc, argv, 0, 0, NULL);
if (rc != 0)
log_fail("Failure to parse command line arguments");
}

29
src/common/options.h Normal file
View File

@ -0,0 +1,29 @@
/*
* options.h
*
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef OPTIONS_H
#define OPTIONS_H 1
#define PACKAGE_COPYRIGHT "(c) Hugo Villeneuve"
#define PACKAGE_DESCRIPTION "Emulator for 8051 family microcontrollers"
struct options_t {
char *g;
int pram_size; /* Maximum program memory size. */
int iram_size; /* Maximum internal ram size. */
int xram_size; /* Maximum external ram size. */
char *filename;
int log;
uint16_t stop_address; /* Run program up to that adress and exit. */
} options_t;
void
parse_command_line_options(int argc, char *argv[]);
#endif /* OPTIONS_H */

125
src/common/psw.c Normal file
View File

@ -0,0 +1,125 @@
/*
* psw.c
*
* Copyright (C) 2013 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#include "common.h"
#include "reg8051.h"
#include "memory.h"
/* Returns 0 or 1 */
int
psw_read_bit(unsigned int bit)
{
return (mem_read8(INT_MEM_ID, _PSW_) >> bit) & 0x01;
}
void
psw_write_bit(unsigned int bit, int val)
{
uint8_t psw = mem_read8(INT_MEM_ID, _PSW_);
if (val)
psw |= (1 << bit); /* Set */
else
psw &= ~(1 << bit); /* Clear */
mem_write8(INT_MEM_ID, _PSW_, psw); /* Save updated value */
}
/* Returns 0 or 1 */
int
psw_read_cy(void)
{
return psw_read_bit(PSW_BIT_CY);
}
void
psw_write_cy(int cy)
{
psw_write_bit(PSW_BIT_CY, cy);
}
void
psw_set_cy(void)
{
psw_write_bit(PSW_BIT_CY, 1);
}
void
psw_clr_cy(void)
{
psw_write_bit(PSW_BIT_CY, 0);
}
/* Returns 0 or 1 */
int
psw_read_ac(void)
{
return psw_read_bit(PSW_BIT_AC);
}
void
psw_write_ac(int ac)
{
psw_write_bit(PSW_BIT_AC, ac);
}
void
psw_set_ac(void)
{
psw_write_bit(PSW_BIT_AC, 1);
}
void
psw_clr_ac(void)
{
psw_write_bit(PSW_BIT_AC, 0);
}
/* Returns 0 or 1 */
int
psw_read_ov(void)
{
return psw_read_bit(PSW_BIT_OV);
}
void
psw_write_ov(int ov)
{
psw_write_bit(PSW_BIT_OV, ov);
}
void
psw_set_ov(void)
{
psw_write_bit(PSW_BIT_OV, 1);
}
void
psw_clr_ov(void)
{
psw_write_bit(PSW_BIT_OV, 0);
}
/*
* Compute parity of bits in accumulator:
* parity = 0: even number of ones in accumulator
* parity = 1: odd number of ones in accumulator
*/
void
psw_compute_parity_bit(void)
{
int parity = 0;
uint8_t acc = mem_read8(INT_MEM_ID, _ACC_);
while (acc) {
parity = !parity;
acc = acc & (acc - 1);
}
psw_write_bit(PSW_BIT_P, parity);
}

57
src/common/psw.h Normal file
View File

@ -0,0 +1,57 @@
/*
* psw.h
*
* Copyright (C) 2013 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef PSW_H
#define PSW_H 1
int
psw_read_bit(unsigned int bit);
void
psw_write_bit(unsigned int bit, int val);
int
psw_read_cy(void);
void
psw_write_cy(int cy);
void
psw_clr_cy(void);
void
psw_set_cy(void);
int
psw_read_ac(void);
void
psw_write_ac(int ac);
void
psw_clr_ac(void);
void
psw_set_ac(void);
int
psw_read_ov(void);
void
psw_write_ov(int ov);
void
psw_clr_ov(void);
void
psw_set_ov(void);
void
psw_compute_parity_bit(void);
#endif /* PSW_H */

63
src/common/reg8051.h Normal file
View File

@ -0,0 +1,63 @@
/*
* reg8051.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef REG8051_H
#define REG8051_H 1
/* SFR Registers ( $80 - $FF ) */
#define _ACC_ 0xE0
#define _B_ 0xF0
#define _PSW_ 0xD0
#define _SP_ 0x81
#define _DPTRLOW_ _DPL_
#define _DPTRHIGH_ _DPH_
#define _DPL_ 0x82
#define _DPH_ 0x83
#define _P0_ 0x80
#define _P1_ 0x90
#define _P2_ 0xA0
#define _P3_ 0xB0
#define _IP_ 0xB8
#define _IE_ 0xA8
#define _TMOD_ 0x89
#define _TCON_ 0x88
#define _TH0_ 0x8C
#define _TL0_ 0x8A
#define _TH1_ 0x8D
#define _TL1_ 0x8B
#define _SCON_ 0x98
#define _SBUF_ 0x99
#define _PCON_ 0x87
#define _T2CON_ 0xC8
#define _R0_ 0x00
#define _R1_ 0x01
#define _R2_ 0x02
#define _R3_ 0x03
#define _R4_ 0x04
#define _R5_ 0x05
#define _R6_ 0x06
#define _R7_ 0x07
#define _BANK0_ 0x00
#define _BANK1_ 0x08
#define _BANK2_ 0x10
#define _BANK3_ 0x18
#define PSW_BIT_CY 7
#define PSW_BIT_AC 6
#define PSW_BIT_OV 2
#define PSW_BIT_P 0
#define PSW_FLAG_CY (1 << PSW_BIT_CY)
#define PSW_FLAG_AC (1 << PSW_BIT_AC)
#define PSW_FLAG_OV (1 << PSW_BIT_OV)
#define PSW_FLAG_P (1 << PSW_BIT_P)
#endif /* REG8051_H */

357
src/common/sfr.c Normal file
View File

@ -0,0 +1,357 @@
/*
* sfr.c
*
* Copyright (C) 2013 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include "common.h"
#include "reg8051.h"
#include "cpu8051.h"
#include "sfr.h"
#include "memory.h"
#include "instructions_8051.h"
#define HEX_DIGITS_2 2
#define HEX_DIGITS_4 4
/* Specific read/write functions for special registers. */
static unsigned int
regwin_read_pc(int dummy)
{
(void) dummy; /* Remove compiler warning about unused variable. */
return cpu8051.pc;
}
static void
regwin_write_pc(int param, int val)
{
(void) param; /* Remove compiler warning about unused variable. */
cpu8051.pc = (uint16_t) val;
}
static unsigned int
regwin_read_timer(int timer_low_addr)
{
return (mem_sfr_read8(timer_low_addr + 2) << 8) |
mem_sfr_read8(timer_low_addr);
}
static void
regwin_write_timer(int timer_low_addr, int val)
{
mem_sfr_write8(timer_low_addr + 2,
(uint8_t) ((val & 0x0000FFFF) >> 8));
mem_sfr_write8(timer_low_addr, (uint8_t) val);
}
static uint8_t
regwin_read_bank_offset(void)
{
return mem_sfr_read8(_PSW_) & 0x18;
}
static unsigned int
regwin_read_bank(int dummy)
{
(void) dummy; /* Remove compiler warning about unused variable. */
return regwin_read_bank_offset() >> 3;
}
static void
regwin_write_bank(int param, int bank_number)
{
uint8_t psw = mem_sfr_read8(_PSW_);
(void) param; /* Remove compiler warning about unused variable. */
if ((bank_number < 0) || (bank_number > 3)) {
log_info("Error: invalid bank number: %d", bank_number);
bank_number = 0;
}
mem_sfr_write8(_PSW_, (psw & ~0x18) | (bank_number << 3));
}
/* Indirect read of R0 - R7 in current bank from internal memory. */
static unsigned int
regwin_read_rx(int offset)
{
return mem_read8(INT_MEM_ID, regwin_read_bank_offset() + offset);
}
/* Indirect write to R0 - R7 in current bank to internal memory. */
static void
regwin_write_rx(int offset, int val)
{
mem_write8(INT_MEM_ID, regwin_read_bank_offset() + offset,
(uint8_t) val);
}
/* This array defines how to read value for each register. */
static struct regwin_infos_t regwin_infos[SFR_REGS] = {
{
"PC",
HEX_DIGITS_4,
regwin_read_pc, regwin_write_pc,
0, /* Dummy */
},
{
"SP",
HEX_DIGITS_2,
NULL, NULL,
_SP_,
},
{
"PSW",
HEX_DIGITS_2,
NULL, NULL,
_PSW_,
},
{
"A",
HEX_DIGITS_2,
NULL, NULL,
_ACC_,
},
{
"B",
HEX_DIGITS_2,
NULL, NULL,
_B_,
},
{
"DPTR",
HEX_DIGITS_4,
NULL, NULL,
_DPL_,
},
{
"P0",
HEX_DIGITS_2,
NULL, NULL,
_P0_,
},
{
"P1",
HEX_DIGITS_2,
NULL, NULL,
_P1_,
},
{
"P2",
HEX_DIGITS_2,
NULL, NULL,
_P2_,
},
{
"P3",
HEX_DIGITS_2,
NULL, NULL,
_P3_,
},
{
"TCON",
HEX_DIGITS_2,
NULL, NULL,
_TCON_,
},
{
"TMOD",
HEX_DIGITS_2,
NULL, NULL,
_TMOD_,
},
{
"TIMER0",
HEX_DIGITS_4,
regwin_read_timer, regwin_write_timer,
_TL0_,
},
{
"TIMER1",
HEX_DIGITS_4,
regwin_read_timer, regwin_write_timer,
_TL1_,
},
{
"SCON",
HEX_DIGITS_2,
NULL, NULL,
_SCON_,
},
{
"IE",
HEX_DIGITS_2,
NULL, NULL,
_IE_,
},
{
"IP",
HEX_DIGITS_2,
NULL, NULL,
_IP_,
},
{
"BANK",
HEX_DIGITS_2,
regwin_read_bank, regwin_write_bank,
0, /* Dummy */
},
/* R0-R7 Registers in current Bank */
{
"R0",
HEX_DIGITS_2,
regwin_read_rx, regwin_write_rx,
_R0_,
},
{
"R1",
HEX_DIGITS_2,
regwin_read_rx, regwin_write_rx,
_R1_,
},
{
"R2",
HEX_DIGITS_2,
regwin_read_rx, regwin_write_rx,
_R2_,
},
{
"R3",
HEX_DIGITS_2,
regwin_read_rx, regwin_write_rx,
_R3_,
},
{
"R4",
HEX_DIGITS_2,
regwin_read_rx, regwin_write_rx,
_R4_,
},
{
"R5",
HEX_DIGITS_2,
regwin_read_rx, regwin_write_rx,
_R5_,
},
{
"R6",
HEX_DIGITS_2,
regwin_read_rx, regwin_write_rx,
_R6_,
},
{
"R7",
HEX_DIGITS_2,
regwin_read_rx, regwin_write_rx,
_R7_,
},
};
/* Generic read/write functions */
static unsigned int
regwin_read_generic(int addr, int width)
{
if (width == 2) {
return mem_sfr_read8(addr);
} else if (width == 4) {
/* Address is low address. */
return (mem_sfr_read8(addr + 1) << 8) |
mem_sfr_read8(addr);
} else {
return 0xFFFFFFFF;
}
}
static void
regwin_write_generic(int addr, int val, int width)
{
if (width == 2) {
mem_sfr_write8(addr, (uint8_t) val);
} else if (width == 4) {
/* Address is low address. */
mem_sfr_write8(addr + 1, (uint8_t) ((val & 0x0000FFFF) >> 8));
mem_sfr_write8(addr, (uint8_t) val);
}
}
int
regwin_read(int row)
{
int val;
if (regwin_infos[row].read_func == NULL) {
/*
* Read register value using generic 8 or 16 bits read
* function, depending on width.
*/
val = regwin_read_generic(regwin_infos[row].param,
regwin_infos[row].w);
} else {
/* Read register value using custom function pointer. */
val = regwin_infos[row].read_func(
regwin_infos[row].param);
}
return val;
}
int
regwin_write(struct regwin_infos_t *p, int new)
{
int max_value;
max_value = (1 << (4 * p->w)) - 1; /* 16^w - 1 */
/* Check that the new value is not too large for the register type. */
if (new > max_value) {
/* Display message for CLI version */
printf("Value out of range\n");
return -1;
}
if (p->write_func == NULL) {
/*
* Write register value using generic 8 or 16 bits write
* function, depending on width.
*/
regwin_write_generic(p->param, new, p->w);
} else {
/* Write register value using custom function pointer. */
p->write_func(p->param, new);
}
return 0;
}
struct regwin_infos_t *
sfr_get_infos(const char *regname)
{
int row;
for (row = 0; row < SFR_REGS; row++) {
if (strcmp(regwin_infos[row].name, regname) == 0)
return &regwin_infos[row];
}
return NULL; /* Register not found. */
}
struct regwin_infos_t *
sfr_get_infos_from_row(int row)
{
return &regwin_infos[row];
}

34
src/common/sfr.h Normal file
View File

@ -0,0 +1,34 @@
/*
* sfr.h
*
* Copyright (C) 2013 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef SFR_H
#define SFR_H 1
#define SFR_REGS 26
struct regwin_infos_t {
char *name; /* Register name */
int w; /* Number of hex digits to display */
unsigned int (*read_func)(int addr); /* Function to read value */
void (*write_func)(int param, int val); /* Function to write value */
int param; /* Optional parameter to pass to read function. */
};
int
regwin_read(int row);
int
regwin_write(struct regwin_infos_t *p, int new);
struct regwin_infos_t *
sfr_get_infos(const char *regname);
struct regwin_infos_t *
sfr_get_infos_from_row(int row);
#endif /* SFR_H */

166
src/common/timers.c Normal file
View File

@ -0,0 +1,166 @@
/*
* timers.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include "config.h"
#include "common.h"
#include "reg8051.h"
#include "cpu8051.h"
#include "memory.h"
#include "psw.h"
#include "options.h"
#include "instructions_8051.h"
#include "timers.h"
static int gp_timer_value[GP_TIMERS_COUNT];
extern struct options_t options;
void
gp_timer_reset(int id)
{
log_debug("gp timer %d reset", id);
gp_timer_value[id] = 0;
}
void
gp_timers_increment(int count)
{
int id;
log_debug("gp timers increment");
for (id = 0; id < GP_TIMERS_COUNT; id++)
gp_timer_value[id] += count;
}
int
gp_timer_read(int id)
{
return gp_timer_value[id];
}
static void
timer_increment_check_overflow(uint8_t counter_address, uint8_t tf_mask)
{
unsigned int tmp;
tmp = mem_read_direct(counter_address);
tmp++;
tmp &= 0xFF;
if (tmp == 0) {
/* If overflow set TFx */
mem_write_direct(_TCON_,
mem_read_direct(_TCON_) | tf_mask);
}
mem_write_direct(counter_address, tmp); /* Save new value. */
}
static void
timer_with_prescaler(uint8_t tl, uint8_t th, uint8_t tf_mask,
int prescaler_width)
{
unsigned int prescaler;
prescaler = mem_read_direct(tl);
prescaler++;
prescaler &= (1 << prescaler_width) - 1; /* Keep only required bits */
mem_write_direct(tl, prescaler);
if (prescaler == 0)
timer_increment_check_overflow(th, tf_mask);
}
static void
process_timer(uint8_t tl, uint8_t th, uint8_t tf_mask, uint8_t TR, uint8_t mode,
uint8_t gate, uint32_t timer_counter)
{
unsigned int tmp;
switch (mode) {
case 0:
/* Mode 0, 8-bit timer "TH" with "TL" as 5-bit prescaler. */
timer_with_prescaler(tl, th, tf_mask, 5);
break;
case 1:
/* Mode 1, 16-bits counter */
timer_with_prescaler(tl, th, tf_mask, 8);
break;
case 2:
/* Mode 2, 8-bits counter with Auto-Reload */
tmp = mem_read_direct(tl);
tmp++;
tmp &= 0xFF;
if (tmp == 0) {
/* If overflow -> reload and set TF0 */
mem_write_direct(
_TCON_,
mem_read_direct(_TCON_) | tf_mask);
mem_write_direct(tl, mem_read_direct(th));
} else {
mem_write_direct(tl, tmp);
}
break;
case 3:
/*
* Mode 3:
* inactive mode for timer 1
* 2 independents 8-bits timers for timer 0.
*/
if (tl == _TL1_)
break;
if (TR && !gate && !timer_counter)
timer_increment_check_overflow(tl, tf_mask);
/* TH0 uses TR1 et TF1. */
TR = mem_read_direct(_TCON_) & 0x40;
if (TR)
timer_increment_check_overflow(th, 0x80);
break;
}
}
/* Run 8051 timers */
void
timers_check(void)
{
unsigned int tr;
unsigned int mode;
unsigned int gate;
unsigned int timer_counter;
/* Timer 0 */
tr = mem_read_direct(_TCON_) & 0x10;
mode = mem_read_direct(_TMOD_) & 0x03;
gate = mem_read_direct(_TMOD_) & 0x08;
timer_counter = mem_read_direct(_TMOD_) & 0x04;
if ((tr && !gate && !timer_counter) || (mode == 3))
process_timer(_TL0_, _TH0_, 0x20, tr, mode, gate,
timer_counter);
/* Timer 1 */
tr = mem_read_direct(_TCON_) & 0x40;
mode = (mem_read_direct(_TMOD_) & 0x30) >> 4;
gate = mem_read_direct(_TMOD_) & 0x80;
timer_counter = mem_read_direct(_TMOD_) & 0x40;
if (tr && !gate && !timer_counter)
process_timer(_TL1_, _TH1_, 0x80, tr, mode, gate,
timer_counter);
}

29
src/common/timers.h Normal file
View File

@ -0,0 +1,29 @@
/*
* timers.h
*
* Copyright (C) 2013 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef TIMERS_H
#define TIMERS_H 1
#include <stdint.h>
/* Maximum of 4 for CLI version */
#define GP_TIMERS_COUNT 2
void
gp_timer_reset(int id);
void
gp_timers_increment(int count);
int
gp_timer_read(int id);
void
timers_check(void);
#endif /* TIMERS_H */

View File

@ -1,211 +0,0 @@
#ifndef __DISASM_HPP_
#define __DISASM_HPP_
// Do not modify this file directly, it was created by Opcode2cpp.pl
// Any modification made directly on this file will be lost
// For all 256 opcodes, the value in this table gives the instruction type
// ex.: MOV, INC, CLR, CPL,...
// To know what is the instruction type, use the number as an offset in the InstTextTbl[]
static int InstTypesTbl[] = {
0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
10, 1, 11, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
14, 6, 15, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
18, 1, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
20, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
22, 1, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
24, 6, 19, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
27, 1, 21, 28, 29, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 6, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
19, 1, 26, 4, 31, 32, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
21, 6, 33, 33, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
35, 1, 36, 36, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
39, 6, 40, 40, 41, 42, 43, 43, 42, 42, 42, 42, 42, 42, 42, 42,
44, 1, 44, 44, 36, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
44, 6, 44, 44, 33, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26
};
// Size(in bytes) of each instruction (offset in table is instruction opcode)
static int InstSizesTbl[] = {
1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 1, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 1, 1, 3, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
// List of instructions types referenced by InstTypesTbl[]
#define InstTextTblLength 45
static char *InstTextTbl[] = {
"NOP",
"AJMP",
"LJMP",
"RR",
"INC",
"JBC",
"ACALL",
"LCALL",
"RRC",
"DEC",
"JB",
"RET",
"RL",
"ADD",
"JNB",
"RETI",
"RLC",
"ADDC",
"JC",
"ORL",
"JNC",
"ANL",
"JZ",
"XRL",
"JNZ",
"JMP",
"MOV",
"SJMP",
"MOVC",
"DIV",
"SUBB",
"MUL",
"INVALID",
"CPL",
"CJNE",
"PUSH",
"CLR",
"SWAP",
"XCH",
"POP",
"SETB",
"DA",
"DJNZ",
"XCHD",
"MOVX"
};
// Table describing all arguments types of an instruction
// The table is indexed InstArgTbl[ opcode * 4]
// InstArgTbl[opcode*4 + 1] gives the number of arguments the instruction has
// InstArgTbl[opcode*4 + i] for i=1,2 and 3 give the type of each argument
// for most instructions, the 3rd argument isn't used
// the argument type is referecing to ArgsTextTbl[]
#define InstArgTblLength 256
static int InstArgTbl[] = {
0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 2, 0, 0,
1, 2, 0, 0, 1, 3, 0, 0, 1, 4, 0, 0, 1, 5, 0, 0,
1, 6, 0, 0, 1, 7, 0, 0, 1, 8, 0, 0, 1, 9, 0, 0,
1, 10, 0, 0, 1, 11, 0, 0, 1, 12, 0, 0, 1, 13, 0, 0,
2, 14, 15, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 2, 0, 0,
1, 2, 0, 0, 1, 3, 0, 0, 1, 4, 0, 0, 1, 5, 0, 0,
1, 6, 0, 0, 1, 7, 0, 0, 1, 8, 0, 0, 1, 9, 0, 0,
1, 10, 0, 0, 1, 11, 0, 0, 1, 12, 0, 0, 1, 13, 0, 0,
2, 14, 15, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0,
2, 2, 16, 0, 2, 2, 3, 0, 2, 2, 4, 0, 2, 2, 5, 0,
2, 2, 6, 0, 2, 2, 7, 0, 2, 2, 8, 0, 2, 2, 9, 0,
2, 2, 10, 0, 2, 2, 11, 0, 2, 2, 12, 0, 2, 2, 13, 0,
2, 14, 15, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0,
2, 2, 16, 0, 2, 2, 3, 0, 2, 2, 4, 0, 2, 2, 5, 0,
2, 2, 6, 0, 2, 2, 7, 0, 2, 2, 8, 0, 2, 2, 9, 0,
2, 2, 10, 0, 2, 2, 11, 0, 2, 2, 12, 0, 2, 2, 13, 0,
1, 15, 0, 0, 1, 0, 0, 0, 2, 3, 2, 0, 2, 3, 16, 0,
2, 2, 16, 0, 2, 2, 3, 0, 2, 2, 4, 0, 2, 2, 5, 0,
2, 2, 6, 0, 2, 2, 7, 0, 2, 2, 8, 0, 2, 2, 9, 0,
2, 2, 10, 0, 2, 2, 11, 0, 2, 2, 12, 0, 2, 2, 13, 0,
1, 15, 0, 0, 1, 0, 0, 0, 2, 3, 2, 0, 2, 3, 16, 0,
2, 2, 16, 0, 2, 2, 3, 0, 2, 2, 4, 0, 2, 2, 5, 0,
2, 2, 6, 0, 2, 2, 7, 0, 2, 2, 8, 0, 2, 2, 9, 0,
2, 2, 10, 0, 2, 2, 11, 0, 2, 2, 12, 0, 2, 2, 13, 0,
1, 15, 0, 0, 1, 0, 0, 0, 2, 3, 2, 0, 2, 3, 16, 0,
2, 2, 16, 0, 2, 2, 3, 0, 2, 2, 4, 0, 2, 2, 5, 0,
2, 2, 6, 0, 2, 2, 7, 0, 2, 2, 8, 0, 2, 2, 9, 0,
2, 2, 10, 0, 2, 2, 11, 0, 2, 2, 12, 0, 2, 2, 13, 0,
1, 15, 0, 0, 1, 0, 0, 0, 2, 17, 14, 0, 1, 18, 0, 0,
2, 2, 16, 0, 2, 3, 16, 0, 2, 4, 16, 0, 2, 5, 16, 0,
2, 6, 16, 0, 2, 7, 16, 0, 2, 8, 16, 0, 2, 9, 16, 0,
2, 10, 16, 0, 2, 11, 16, 0, 2, 12, 16, 0, 2, 13, 16, 0,
1, 15, 0, 0, 1, 0, 0, 0, 2, 17, 14, 0, 2, 2, 19, 0,
1, 20, 0, 0, 2, 3, 3, 0, 2, 3, 4, 0, 2, 3, 5, 0,
2, 3, 6, 0, 2, 3, 7, 0, 2, 3, 8, 0, 2, 3, 9, 0,
2, 3, 10, 0, 2, 3, 11, 0, 2, 3, 12, 0, 2, 3, 13, 0,
2, 21, 22, 0, 1, 0, 0, 0, 2, 14, 17, 0, 2, 2, 18, 0,
2, 2, 16, 0, 2, 2, 3, 0, 2, 2, 4, 0, 2, 2, 5, 0,
2, 2, 6, 0, 2, 2, 7, 0, 2, 2, 8, 0, 2, 2, 9, 0,
2, 2, 10, 0, 2, 2, 11, 0, 2, 2, 12, 0, 2, 2, 13, 0,
2, 17, 23, 0, 1, 0, 0, 0, 2, 17, 14, 0, 1, 21, 0, 0,
1, 20, 0, 0, 0, 0, 0, 0, 2, 4, 3, 0, 2, 5, 3, 0,
2, 6, 3, 0, 2, 7, 3, 0, 2, 8, 3, 0, 2, 9, 3, 0,
2, 10, 3, 0, 2, 11, 3, 0, 2, 12, 3, 0, 2, 13, 3, 0,
2, 17, 23, 0, 1, 0, 0, 0, 1, 14, 0, 0, 1, 17, 0, 0,
3, 2, 16, 15, 3, 2, 3, 15, 3, 4, 16, 15, 3, 5, 16, 15,
3, 6, 16, 15, 3, 7, 16, 15, 3, 8, 16, 15, 3, 9, 16, 15,
3, 10, 16, 15, 3, 11, 16, 15, 3, 12, 16, 15, 3, 13, 16, 15,
1, 3, 0, 0, 1, 0, 0, 0, 1, 14, 0, 0, 1, 17, 0, 0,
1, 2, 0, 0, 2, 2, 3, 0, 2, 2, 4, 0, 2, 2, 5, 0,
2, 2, 6, 0, 2, 2, 7, 0, 2, 2, 8, 0, 2, 2, 9, 0,
2, 2, 10, 0, 2, 2, 11, 0, 2, 2, 12, 0, 2, 2, 13, 0,
1, 3, 0, 0, 1, 0, 0, 0, 1, 14, 0, 0, 1, 17, 0, 0,
1, 2, 0, 0, 2, 3, 15, 0, 2, 2, 4, 0, 2, 2, 5, 0,
2, 6, 15, 0, 2, 7, 15, 0, 2, 8, 15, 0, 2, 9, 15, 0,
2, 10, 15, 0, 2, 11, 15, 0, 2, 12, 15, 0, 2, 13, 15, 0,
2, 2, 24, 0, 1, 0, 0, 0, 2, 2, 4, 0, 2, 2, 5, 0,
1, 2, 0, 0, 2, 2, 3, 0, 2, 2, 4, 0, 2, 2, 5, 0,
2, 2, 6, 0, 2, 2, 7, 0, 2, 2, 8, 0, 2, 2, 9, 0,
2, 2, 10, 0, 2, 2, 11, 0, 2, 2, 12, 0, 2, 2, 13, 0,
2, 24, 2, 0, 1, 0, 0, 0, 2, 4, 2, 0, 2, 5, 2, 0,
1, 2, 0, 0, 2, 3, 2, 0, 2, 4, 2, 0, 2, 5, 2, 0,
2, 6, 2, 0, 2, 7, 2, 0, 2, 8, 2, 0, 2, 9, 2, 0,
2, 10, 2, 0, 2, 11, 2, 0, 2, 12, 2, 0, 2, 13, 2, 0
};
// List all types of arguments available to instructions
// Referenced by InstArgsTbl[]
#define ArgsTextTblLength 25
static char *ArgsTextTbl[] = {
"addr11",
"addr16",
"A",
"direct",
"@R0",
"@R1",
"R0",
"R1",
"R2",
"R3",
"R4",
"R5",
"R6",
"R7",
"bitaddr",
"reladdr",
"#data",
"C",
"@A+DPTR",
"@A+PC",
"AB",
"DPTR",
"#data16",
"/bitaddr",
"@DPTR"
};
#endif

View File

@ -1,19 +0,0 @@
// Exceptions.hpp
// Gestion des erreurs pour le programme d'emulation du 8051.
#ifndef _EXCEPTION_HPP_
#define _EXCEPTION_HPP_
class ShowOptions { /* ... */ };
class FinishedLoading { /* ... */ };
class ErrorOpeningFile { /* ... */ };
class ErrorHexFileFormat { /* ... */ };
class SyntaxError { /* ... */ };
class InvalidAddress { /* ... */ };
class MissingParameter { /* ... */ };
class InvalidParameter { /* ... */ };
class InvalidRegister { /* ... */ };
class TooMuchParameters { /* ... */ };
class ResetRequest { /* ... */ };
#endif

38
src/gtk/Makefile.am Normal file
View File

@ -0,0 +1,38 @@
# This file is processed by GNU automake to generate Makefile.in
AM_CPPFLAGS = \
$(WARNINGCFLAGS) \
-I$(top_srcdir)/pixmaps \
-I$(top_srcdir)/src/common \
-I$(top_builddir)/src/common \
@GTK_CFLAGS@ \
@GLIB_CFLAGS@ \
-DDATADIR=\"$(datadir)\" \
-DGDK_PIXBUF_DISABLE_DEPRECATED \
-DGDK_DISABLE_DEPRECATED \
-DGTK_DISABLE_DEPRECATED
LDADD = \
$(top_builddir)/src/common/libemu8051.a \
@GTK_LIBS@ \
@ZLIB_LIBS@ \
@GLIB_LIBS@
bin_PROGRAMS = emu8051-gtk
emu8051_gtk_SOURCES = \
main.c main.h \
app-config.c app-config.h \
memwin.c memwin.h \
pgmwin.c pgmwin.h \
regwin.c regwin.h \
pswwin.c pswwin.h \
timerwin.c timerwin.h \
filemenu.c filemenu.h \
viewmenu.c viewmenu.h \
helpmenu.c helpmenu.h \
messagebox.c messagebox.h
CLEANFILES = *~
MAINTAINERCLEANFILES = Makefile.in

207
src/gtk/app-config.c Normal file
View File

@ -0,0 +1,207 @@
/*
* Handle loading and saving of application configuration settings
*
* Copyright (C) 2013 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#if STDC_HEADERS
# include <string.h>
#elif HAVE_STRINGS_H
# include <strings.h>
#endif
#include <glib.h>
#include "common.h"
#include "app-config.h"
static const char profile_name[] = "default";
static struct app_config_t app_config;
struct app_config_t *cfg = &app_config;
static void
app_config_init(void)
{
/* Emulation options */
cfg->clear_ram_on_file_load = false;
/* UI settings */
cfg->win_width = 640;
cfg->win_height = 480;
cfg->win_pos_x = 10;
cfg->win_pos_y = 10;
cfg->hpane_pos = 100;
cfg->vpane_pos = 200;
cfg->main_pane_pos = 200;
/* View menu options */
cfg->layout = UI_LAYOUT1;
cfg->view_int_memory = 1;
cfg->view_ext_memory = 1;
cfg->bytes_per_row = 16; /* 8 or 16 */
}
static int
app_config_key_file_get_int(GKeyFile *kf, const char *grp, const char *key,
int *value)
{
char *str = g_key_file_get_value(kf, grp, key, NULL);
log_debug("key: %s", key);
if (G_LIKELY(str)) {
*value = atoi(str);
log_debug(" value = %d", *value);
g_free(str);
}
return str != NULL;
}
static void
app_config_load_from_key_file(GKeyFile *kf)
{
/* Emulation options */
app_config_key_file_get_int(kf, "emulation", "clear_ram_on_file_load",
&cfg->clear_ram_on_file_load);
/* ui */
app_config_key_file_get_int(kf, "ui", "win_width", &cfg->win_width);
app_config_key_file_get_int(kf, "ui", "win_height", &cfg->win_height);
app_config_key_file_get_int(kf, "ui", "win_pos_x", &cfg->win_pos_x);
app_config_key_file_get_int(kf, "ui", "win_pos_y", &cfg->win_pos_y);
app_config_key_file_get_int(kf, "ui", "hpane_pos", &cfg->hpane_pos);
app_config_key_file_get_int(kf, "ui", "vpane_pos", &cfg->vpane_pos);
app_config_key_file_get_int(kf, "ui", "main_pane_pos",
&cfg->main_pane_pos);
/* View */
app_config_key_file_get_int(kf, "view", "layout", &cfg->layout);
if ((cfg->layout != UI_LAYOUT1) && (cfg->layout != UI_LAYOUT2)) {
log_err("Invalid layout, defaulting to layout 1");
cfg->layout = UI_LAYOUT1;
}
app_config_key_file_get_int(kf, "view", "int_memory",
&cfg->view_int_memory);
app_config_key_file_get_int(kf, "view", "ext_memory",
&cfg->view_ext_memory);
app_config_key_file_get_int(kf, "view", "bytes_per_row",
&cfg->bytes_per_row);
}
static char *
app_config_get_dir_path(void)
{
char *dir_path;
dir_path = g_build_filename(g_get_user_config_dir(), PACKAGE_NAME,
profile_name, NULL);
return dir_path;
}
static char *
app_config_get_file_path(void)
{
char *file_path;
char *dir_path;
char file[MAX_FILENAME_LENGTH];
sprintf(file, "%s.conf", PACKAGE_NAME);
dir_path = app_config_get_dir_path();
file_path = g_build_filename(dir_path, file, NULL);
log_info("app. config file = %s", file_path);
g_free(dir_path);
return file_path;
}
int
app_config_load(void)
{
char *file_path;
GKeyFile *kf;
/* Load default values before config file */
app_config_init();
kf = g_key_file_new();
file_path = app_config_get_file_path();
if (g_key_file_load_from_file(kf, file_path, 0, NULL))
app_config_load_from_key_file(kf);
g_free(file_path);
g_key_file_free(kf);
/* ??? */
return 0;
}
int
app_config_save(void)
{
char *dir_path;
dir_path = app_config_get_dir_path();
if (g_mkdir_with_parents(dir_path, 0700) != -1) {
char *file_path;
GString *buf = g_string_sized_new(1024);
g_string_append(buf, "\n[emulation]\n");
g_string_append_printf(buf, "clear_ram_on_file_load=%d\n",
cfg->clear_ram_on_file_load);
g_string_append(buf, "\n[ui]\n");
g_string_append_printf(buf, "win_width=%d\n", cfg->win_width);
g_string_append_printf(buf, "win_height=%d\n", cfg->win_height);
g_string_append_printf(buf, "win_pos_x=%d\n", cfg->win_pos_x);
g_string_append_printf(buf, "win_pos_y=%d\n", cfg->win_pos_y);
g_string_append_printf(buf, "hpane_pos=%d\n", cfg->hpane_pos);
g_string_append_printf(buf, "vpane_pos=%d\n", cfg->vpane_pos);
g_string_append_printf(buf, "main_pane_pos=%d\n",
cfg->main_pane_pos);
g_string_append(buf, "\n[view]\n");
g_string_append_printf(buf, "layout=%d\n", cfg->layout);
g_string_append_printf(buf, "int_memory=%d\n",
cfg->view_int_memory);
g_string_append_printf(buf, "ext_memory=%d\n",
cfg->view_ext_memory);
g_string_append_printf(buf, "bytes_per_row=%d\n",
cfg->bytes_per_row);
file_path = app_config_get_file_path();
g_file_set_contents(file_path, buf->str, buf->len, NULL);
g_string_free(buf, TRUE);
g_free(file_path);
}
g_free(dir_path);
/* ??? */
return 0;
}

52
src/gtk/app-config.h Normal file
View File

@ -0,0 +1,52 @@
/*
* app_config.h
*
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef APP_CONFIG_H
#define APP_CONFIG_H 1
/*
* Layout1: Layout2:
*
* REGS | PROGRAM | | IRAM
* -------------- REGS | PROGRAM | ----
* IRAM | | XRAM
* --------------
* XRAM
*/
enum layout_t {
UI_LAYOUT1 = 1,
UI_LAYOUT2,
};
struct app_config_t {
/* Emulation options */
int clear_ram_on_file_load;
/* UI settings */
int win_width;
int win_height;
int win_pos_x;
int win_pos_y;
int hpane_pos; /* For registers and program windows. */
int vpane_pos; /* For internal and external memory windows. */
int main_pane_pos; /* Between hpane and vpane. */
/* View menu options */
int layout; /* UI Layout 1 or 2 */
int view_int_memory;
int view_ext_memory;
int bytes_per_row; /* 8 or 16 */
};
int
app_config_load(void);
int
app_config_save(void);
#endif /* APP_CONFIG_H */

134
src/gtk/filemenu.c Normal file
View File

@ -0,0 +1,134 @@
/*
* filemenu.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <unistd.h> /* UNIX standard function definitions */
#include <pwd.h>
#include <gtk/gtk.h>
#include "common.h"
#include "main.h"
#include "messagebox.h"
#include "filemenu.h"
#define FILENAME_DESCRIPTION "Open Intel Hex file"
static char previous_folder[MAX_FILENAME_LENGTH + 1];
static void
remember_current_folder(GtkFileChooser *chooser)
{
char *folder;
folder = gtk_file_chooser_get_current_folder(chooser);
if (folder != NULL) {
if (strlen(folder) >= MAX_FILENAME_LENGTH) {
/* Non-critical error */
log_warn("current folder name too long for buffer");
} else {
log_info("current folder = %s", folder);
strncpy(previous_folder, folder, MAX_FILENAME_LENGTH);
}
g_free(folder);
}
}
static void
file_open_event(GtkObject *object, gpointer data)
{
GtkWidget *file_dialog;
char *dir;
char *cwd = NULL;
/* Remove compiler warning about unused variables. */
(void) object;
(void) data;
log_info("file_open_event()");
/* Create a new file selection widget. */
file_dialog = gtk_file_chooser_dialog_new(
FILENAME_DESCRIPTION, NULL, GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
if (strlen(previous_folder) == 0) {
/* Opening file chooser to current working directory. */
cwd = g_get_current_dir();
dir = cwd;
} else {
/* Opening file chooser to previous opened directory. */
dir = previous_folder;
}
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_dialog), dir);
if (cwd)
g_free(cwd);
if (gtk_dialog_run(GTK_DIALOG(file_dialog)) == GTK_RESPONSE_ACCEPT) {
char *selected_file;
selected_file = gtk_file_chooser_get_filename(
GTK_FILE_CHOOSER(file_dialog));
if (selected_file != NULL) {
log_info("emugtk_File = %s", selected_file);
remember_current_folder(GTK_FILE_CHOOSER(file_dialog));
emugtk_new_file(selected_file);
g_free(selected_file);
}
}
gtk_widget_destroy(file_dialog);
}
static void
file_quit_event(gchar *string)
{
/* Remove compiler warning about unused variables. */
(void) string;
emugtk_quit_gui();
}
void
file_add_menu(GtkWidget *menu_bar)
{
GtkWidget *item;
GtkWidget *menu;
menu = gtk_menu_new();
/* Create the 'open' item. */
item = gtk_menu_item_new_with_label(FILENAME_DESCRIPTION);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
/* Attach the callback functions to the activate signal. */
g_signal_connect(item, "activate", G_CALLBACK(file_open_event), NULL);
add_menu_separator(menu);
item = gtk_menu_item_new_with_label("Exit");
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
/* We can attach the Quit menu item to our exit function */
g_signal_connect(item, "activate", G_CALLBACK(file_quit_event),
(gpointer) "file.quit");
/* Adding submenu title. */
item = gtk_menu_item_new_with_label("File");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
gtk_menu_shell_append((GtkMenuShell *) menu_bar, item);
}

18
src/gtk/filemenu.h Normal file
View File

@ -0,0 +1,18 @@
/*
* filemenu.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef FILEMENU_H
#define FILEMENU_H 1
#include <gtk/gtk.h>
void
file_add_menu(GtkWidget *menu_bar);
#endif /* FILEMENU_H */

94
src/gtk/helpmenu.c Normal file
View File

@ -0,0 +1,94 @@
/*
* helpmenu.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdbool.h>
#if STDC_HEADERS
# include <string.h>
#elif HAVE_STRINGS_H
# include <strings.h>
#endif
#include <gtk/gtk.h>
#include "common.h"
#include "options.h"
#include "main.h"
#include "messagebox.h"
#include "helpmenu.h"
static void
help_about_event(GtkWidget *widget, gpointer data)
{
/* Remove compiler warning about unused variables. */
(void) widget;
(void) data;
const char *authors[] = {
"Hugo Villeneuve <hugo@hugovil.com>",
"Jonathan St-André",
"Pascal Fecteau",
"Jimmy Ringuette",
NULL,
};
const char *license =
"This program is free software; you can redistribute it"
" and/or"
" modify it under the terms of the GNU General Public License"
" as published by the Free Software Foundation; either"
" version 2 of the License, or (at your option) any later"
" version.\n\n"
"This program is distributed in the hope that it will be"
" useful, but WITHOUT ANY WARRANTY; without even the implied"
" warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR"
" PURPOSE. See the GNU General Public License for more"
" details.\n\n"
"You should have received a copy of the GNU General Public"
" License along with this program. If not, see\n"
" <http://www.gnu.org/licenses/>";
gtk_show_about_dialog(
NULL,
"name", PACKAGE_NAME,
"title", "About Dialog",
"version", PACKAGE_VERSION,
"logo-icon-name", PACKAGE_TARNAME,
"comments", PACKAGE_DESCRIPTION,
"authors", authors,
"website", PACKAGE_URL,
"copyright", PACKAGE_COPYRIGHT,
"license", license,
"wrap-license", true,
NULL);
}
void
help_add_menu(GtkWidget *menu_bar)
{
GtkWidget *item;
GtkWidget *menu;
menu = gtk_menu_new();
/* Create the 'Help About' item. */
item = gtk_menu_item_new_with_label("About " PACKAGE_NAME);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
/* Attach the callback functions to the activate signal. */
g_signal_connect(item, "activate", G_CALLBACK(help_about_event), NULL);
/* Adding submenu title. */
item = gtk_menu_item_new_with_label("Help");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
gtk_menu_shell_append((GtkMenuShell *) menu_bar, item);
}

18
src/gtk/helpmenu.h Normal file
View File

@ -0,0 +1,18 @@
/*
* helpmenu.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef HELPMENU_H
#define HELPMENU_H 1
#include <gtk/gtk.h>
void
help_add_menu(GtkWidget *menu_bar);
#endif /* HELPMENU_H */

666
src/gtk/main.c Normal file
View File

@ -0,0 +1,666 @@
/*
* main.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#include <stdio.h>
#include "config.h"
#include <stdint.h>
#include <stdbool.h>
#include <gtk/gtk.h>
#include "common.h"
#include "cpu8051.h"
#include "memory.h"
#include "options.h"
#include "hexfile.h"
#include "timers.h"
#include "main.h"
#include "reset.xpm"
#include "run.xpm"
#include "stop.xpm"
#include "step.xpm"
#include "filemenu.h"
#include "viewmenu.h"
#include "helpmenu.h"
#include "messagebox.h"
#include "regwin.h"
#include "pgmwin.h"
#include "memwin.h"
#include "pswwin.h"
#include "timerwin.h"
#include "app-config.h"
#define BUTTONS_BORDER 2
static int running;
static int running_function_tag;
static int emugtk_window_init_complete;
static GtkWidget *vpaned1;
static GtkWidget *scrollwin_int;
static GtkWidget *scrollwin_ext;
GtkWidget *mainwin;
extern struct app_config_t *cfg;
extern struct options_t options;
void
emugtk_update_display(void)
{
log_debug("update display");
regwin_refresh();
pgmwin_refresh();
pswwin_refresh();
timerwin_update();
if (cfg->view_int_memory && scrollwin_int)
memwin_refresh(INT_MEM_ID);
if (cfg->view_ext_memory && scrollwin_ext)
memwin_refresh(EXT_MEM_ID);
}
/* Step out of running state */
static void
emugtk_stop_running()
{
if (running) {
log_info("stop running");
g_source_remove(running_function_tag);
running = 0;
emugtk_update_display();
}
}
/* Running function called when idle from gtk_main */
static gboolean
emugtk_running(gpointer data)
{
int breakpoint_hit;
(void) data; /* Remove compiler warning about unused variable. */
breakpoint_hit = cpu8051_run(1, NULL);
if (breakpoint_hit)
emugtk_stop_running();
return TRUE;
}
/* Get in the running state */
static void
emugtk_start_running(void)
{
if (!running) {
log_info("start running");
running_function_tag = g_idle_add(emugtk_running, 0);
running = 1;
}
}
/* Taken from the Gxine source code. */
static GtkWidget *
button_add_pix(GtkWidget *box, char **xpm)
{
GtkWidget *button, *icon;
button = gtk_button_new();
gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NORMAL);
icon = gtk_image_new_from_pixbuf(
gdk_pixbuf_new_from_xpm_data((const char **) xpm));
gtk_container_add(GTK_CONTAINER(button), icon);
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, BUTTONS_BORDER);
return button;
}
/* CPU reset and Gtk UI update */
static void
emugtk_reset(void)
{
cpu8051_reset();
emugtk_update_display();
}
/* Signal ResetEvent (ResetButton) */
static void
emugtk_reset_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
/* Remove compiler warning about unused variables. */
(void) widget;
(void) event;
(void) data;
log_info("ResetEvent()");
emugtk_stop_running();
emugtk_reset();
}
/* CPU Step and Gtk UI update */
static void
emugtk_step(void)
{
cpu8051_exec();
emugtk_update_display();
}
/* Signal RunEvent (RunButton) */
static void
emugtk_run_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
/* Remove compiler warning about unused variables. */
(void) widget;
(void) event;
(void) data;
log_info("RunEvent()");
if (running)
emugtk_stop_running();
else
emugtk_start_running();
}
/* Signal StopEvent (StopButton) */
static void
emugtk_stop_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
/* Remove compiler warning about unused variables. */
(void) widget;
(void) event;
(void) data;
log_info("StopEvent()");
emugtk_stop_running();
}
/* Signal StepEvent (StepButton) */
static void
emugtk_step_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
/* Remove compiler warning about unused variables. */
(void) widget;
(void) event;
(void) data;
log_info("StepEvent()");
emugtk_stop_running();
emugtk_step();
}
/* Creates the Reset, Run, Stop and Step buttons. */
static GtkWidget *
add_buttons(void)
{
GtkWidget *button_hbox;
GtkWidget *button;
/* The buttons of the hbox are NOT given equal space in the box. */
button_hbox = gtk_hbox_new(FALSE, 0);
/* Creating the RESET button. */
button = button_add_pix(button_hbox, reset_xpm);
g_signal_connect(button, "clicked",
G_CALLBACK(emugtk_reset_event),
NULL);
/* Creating the RUN button. */
button = button_add_pix(button_hbox, run_xpm);
g_signal_connect(button, "clicked",
G_CALLBACK(emugtk_run_event),
NULL);
/* Creating STOP button. */
button = button_add_pix(button_hbox, stop_xpm);
g_signal_connect(GTK_OBJECT(button), "clicked",
G_CALLBACK(emugtk_stop_event),
NULL);
/* Creating STEP button. */
button = button_add_pix(button_hbox, step_xpm);
g_signal_connect(GTK_OBJECT(button), "clicked",
G_CALLBACK(emugtk_step_event),
NULL);
return button_hbox;
}
static GtkWidget *
add_menu(void)
{
GtkWidget *menu_bar;
/* Creating menu item. */
menu_bar = gtk_menu_bar_new();
/* Adding the 'File' submenu */
file_add_menu(menu_bar);
/* Adding the 'View' submenu */
view_add_menu(menu_bar);
/* Adding the 'Help' submenu */
help_add_menu(menu_bar);
return menu_bar;
}
static int
mainwin_configure_event(GtkWindow *window, GdkEvent *event, gpointer data)
{
/* Remove compiler warning about unused variables. */
(void) window;
(void) data;
cfg->win_width = event->configure.width;
cfg->win_height = event->configure.height;
cfg->win_pos_x = event->configure.x;
cfg->win_pos_y = event->configure.y;
/*
* Important:
* Returning false allows event to propagate to children. If not, they
* will not be resized when we resize the main window.
*/
return FALSE;
}
static void
hpaned_notify_event(GtkWindow *window, GdkEvent *event, gpointer data)
{
GtkWidget *paned = data;
/* Remove compiler warning about unused variables. */
(void) window;
(void) event;
cfg->hpane_pos = gtk_paned_get_position(GTK_PANED(paned));
}
static void
vpaned_notify_event(GtkWindow *window, GdkEvent *event, gpointer data)
{
GtkWidget *paned = data;
/* Remove compiler warning about unused variables. */
(void) window;
(void) event;
cfg->vpane_pos = gtk_paned_get_position(GTK_PANED(paned));
}
static void
main_paned_notify_event(GtkWindow *window, GdkEvent *event, gpointer data)
{
GtkWidget *paned = data;
/* Remove compiler warning about unused variables. */
(void) window;
(void) event;
cfg->main_pane_pos = gtk_paned_get_position(GTK_PANED(paned));
}
void
emugtk_quit_gui(void)
{
gtk_main_quit();
}
static void
emugtk_show_memory_paned(void)
{
gtk_widget_show_all(mainwin);
emugtk_update_display();
}
void
emugtk_create_int_memory_paned(void)
{
scrollwin_int = memwin_init("Internal memory (IRAM)",
INT_MEM_ID);
gtk_paned_pack1(GTK_PANED(vpaned1), scrollwin_int,
FALSE, FALSE);
if (emugtk_window_init_complete)
emugtk_show_memory_paned();
}
void
emugtk_destroy_int_memory_paned(void)
{
if (scrollwin_int == NULL)
return;
gtk_widget_destroy(scrollwin_int);
scrollwin_int = NULL;
}
void
emugtk_create_ext_memory_paned(void)
{
scrollwin_ext = memwin_init("External memory (XRAM)",
EXT_MEM_ID);
gtk_paned_pack2(GTK_PANED(vpaned1), scrollwin_ext,
TRUE, FALSE);
if (emugtk_window_init_complete)
emugtk_show_memory_paned();
}
void
emugtk_destroy_ext_memory_paned(void)
{
if (scrollwin_ext == NULL)
return;
gtk_widget_destroy(scrollwin_ext);
scrollwin_ext = NULL;
}
void
emugtk_recreate_memory_paned(void)
{
if (cfg->view_int_memory) {
emugtk_destroy_int_memory_paned();
emugtk_create_int_memory_paned();
}
if (cfg->view_ext_memory) {
emugtk_destroy_ext_memory_paned();
emugtk_create_ext_memory_paned();
}
if (emugtk_window_init_complete)
emugtk_show_memory_paned();
}
static GtkWidget *
emugtk_create_memory_paned(void)
{
/* Create vpaned (memory windows) only if necessary. */
if (cfg->view_int_memory || cfg->view_ext_memory) {
vpaned1 = gtk_vpaned_new();
gtk_paned_set_position(GTK_PANED(vpaned1), cfg->vpane_pos);
g_signal_connect(G_OBJECT(vpaned1), "notify::position",
G_CALLBACK(vpaned_notify_event), vpaned1);
emugtk_recreate_memory_paned();
return vpaned1;
} else {
return NULL;
}
}
static void
emugtk_set_geometry_hints(GtkWidget *window)
{
GdkGeometry hints;
hints.min_width = 100;
hints.min_height = 100;
/* Set reference point to top left corner */
hints.win_gravity = GDK_GRAVITY_NORTH_WEST;
gtk_window_set_geometry_hints(GTK_WINDOW(window), window, &hints,
GDK_HINT_MIN_SIZE);
}
/*
* mainwin
* +---------------------------------------------------------------------+
* | |
* | vbox |
* | +---------------------------------------------------------------+ |
* | | | |
* | | menu_bar | |
* | | +----------------------+ | |
* | | | File View Help | | |
* | | +----------------------+ | |
* | | | |
* | |---------------------------------------------------------------| |
* | | | |
* | | buttons_bar | |
* | | +-----------------------+ | |
* | | | RST RUN STOP STEP | | |
* | | +-----------------------+ | |
* | | | |
* | |---------------------------------------------------------------| |
* | | | |
* | | main_paned | |
* | | +---------------------------------------------------------+ | |
* | | | | | |
* | | | hpaned | | |
* | | | +---------------------------------------------------+ | | |
* | | | | | | | | |
* | | | | scrollwin | scrollwin | | | |
* | | | | +------------------+ * +--------------------+ | | | |
* | | | | | REGISTERS window | * | Disassembly window | | | | |
* | | | | +------------------+ | +--------------------+ | | | |
* | | | | | | | | |
* | | | +---------------------------------------------------+ | | |
* | | | | | |
* | | |--------------------------***----------------------------- | |
* | | | | | |
* | | | vpaned | | |
* | | | +---------------------------------------------------+ | | |
* | | | | | | | |
* | | | | scrollwin | | | |
* | | | | +---------------------------------------------+ | | | |
* | | | | | Internal memory window | | | | |
* | | | | +---------------------------------------------+ | | | |
* | | | | | | | |
* | | | +-----------------------***-------------------------| | | |
* | | | | | | | |
* | | | | scrollwin | | | |
* | | | | +---------------------------------------------+ | | | |
* | | | | | External memory window | | | | |
* | | | | +---------------------------------------------+ | | | |
* | | | | | | | |
* | | | +---------------------------------------------------+ | | |
* | | | | | |
* | | +---------------------------------------------------------+ | |
* | | | |
* | | | |
* | +---------------------------------------------------------------+ |
* | |
* | |
* +---------------------------------------------------------------------+
*/
static void
emugtk_window_init(void)
{
int geometry_ok = false;
int id;
GtkWidget *vbox;
GtkWidget *menu_bar;
GtkWidget *buttons_bar;
GtkWidget *scrollwin;
GtkWidget *hpaned;
GtkWidget *vpaned;
GtkWidget *main_paned;
emugtk_window_init_complete = false;
mainwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(mainwin), PACKAGE_NAME);
gtk_container_set_border_width(GTK_CONTAINER(mainwin), 0);
/* Window DESTROY event. */
g_signal_connect(mainwin, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(mainwin), "configure-event",
G_CALLBACK(mainwin_configure_event), NULL);
/* Creating the menu bar. */
menu_bar = add_menu();
/* Creating the buttons bar. */
buttons_bar = add_buttons();
scrollwin = pswwin_init();
gtk_box_pack_start(GTK_BOX(buttons_bar), scrollwin, FALSE, FALSE, 50);
for (id = 0; id < GP_TIMERS_COUNT; id++) {
scrollwin = timerwin_init(id);
gtk_box_pack_start(GTK_BOX(buttons_bar), scrollwin,
FALSE, FALSE, 15);
}
/* hpaned will contain registers and disassembly windows. */
hpaned = gtk_hpaned_new();
gtk_paned_set_position(GTK_PANED(hpaned), cfg->hpane_pos);
g_signal_connect(G_OBJECT(hpaned), "notify::position",
G_CALLBACK(hpaned_notify_event), hpaned);
/* 8051 registers frame. */
scrollwin = regwin_init();
gtk_paned_pack1(GTK_PANED(hpaned), scrollwin, FALSE, FALSE);
/* Program disassembly frame. */
scrollwin = pgmwin_init();
gtk_paned_pack2(GTK_PANED(hpaned), scrollwin, TRUE, FALSE);
/*
* main_paned will contain two groups:
* group1: registers and disassembly windows.
* group2: memory windows
*/
if (cfg->layout == UI_LAYOUT1)
main_paned = gtk_vpaned_new();
else
main_paned = gtk_hpaned_new();
gtk_paned_set_position(GTK_PANED(main_paned), cfg->main_pane_pos);
g_signal_connect(G_OBJECT(main_paned), "notify::position",
G_CALLBACK(main_paned_notify_event), main_paned);
gtk_paned_pack1(GTK_PANED(main_paned), hpaned, FALSE, FALSE);
vpaned = emugtk_create_memory_paned();
if (vpaned != NULL)
gtk_paned_pack2(GTK_PANED(main_paned), vpaned,
TRUE, FALSE);
/*
* vbox contains the menu bar and body_vbox (for all remaining
* items).
*/
vbox = gtk_vbox_new(FALSE, 1);
gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 1);
gtk_box_pack_start(GTK_BOX(vbox), buttons_bar, FALSE, FALSE, 1);
gtk_box_pack_start(GTK_BOX(vbox), main_paned, true, true, 1);
/* Adding the vbox to the main window. */
gtk_container_add(GTK_CONTAINER(mainwin), vbox);
g_signal_connect(mainwin, "destroy", G_CALLBACK(emugtk_quit_gui), NULL);
emugtk_set_geometry_hints(mainwin);
/*
* If either a size or a position can be extracted from the geometry
* string, gtk_window_parse_geometry() returns TRUE and calls
* gtk_window_set_default_size() and/or gtk_window_move() to resize/move
* the window.
*/
if (options.g != NULL) {
geometry_ok = gtk_window_parse_geometry(GTK_WINDOW(mainwin),
options.g);
if (!geometry_ok)
log_err("Failed to parse geometry argument: %s",
options.g);
}
/*
* If geometry was not specified, or was improperly parsed, use
* saved window size.
*/
if (geometry_ok == false) {
log_err("Use saved window size");
gtk_window_set_default_size(GTK_WINDOW(mainwin),
cfg->win_width, cfg->win_height);
gtk_window_move(GTK_WINDOW(mainwin),
cfg->win_pos_x, cfg->win_pos_y);
}
gtk_widget_show_all(mainwin);
emugtk_window_init_complete = true;
}
void
add_menu_separator(GtkWidget *menu)
{
GtkWidget *item;
item = gtk_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
}
void
emugtk_new_file(char *file)
{
int rc;
emugtk_stop_running();
rc = hexfile_load(file);
if (!rc) {
message_show_error("Error parsing hex file");
} else {
if (cfg->clear_ram_on_file_load)
emugtk_reset();
emugtk_update_display();
}
}
int
main(int argc, char **argv)
{
int rc_load_hexfile = true;
parse_command_line_options(argc, argv);
app_config_load();
cpu8051_init();
running = 0;
gtk_init(&argc, &argv);
if (options.filename != NULL)
rc_load_hexfile = hexfile_load(options.filename);
cpu8051_reset();
log_info("Init GUI");
emugtk_window_init();
emugtk_update_display();
if (!rc_load_hexfile)
message_show_error("Error parsing hex file");
gtk_main();
log_info("Terminate");
app_config_save();
return EXIT_SUCCESS;
}

42
src/gtk/main.h Normal file
View File

@ -0,0 +1,42 @@
/*
* main.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef MAIN_H
#define MAIN_H 1
#include <gtk/gtk.h>
void
add_menu_separator(GtkWidget *menu);
void
emugtk_new_file(char *file);
void
emugtk_update_display(void);
void
emugtk_quit_gui(void);
void
emugtk_create_int_memory_paned(void);
void
emugtk_destroy_int_memory_paned(void);
void
emugtk_create_ext_memory_paned(void);
void
emugtk_destroy_ext_memory_paned(void);
void
emugtk_recreate_memory_paned(void);
#endif /* MAIN_H */

384
src/gtk/memwin.c Normal file
View File

@ -0,0 +1,384 @@
/*
* memwin.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <ctype.h> /* For isprint */
#include <zlib.h> /* For crc32 routine */
#include "common.h"
#include "memory.h"
#include "hexfile.h"
#include "cpu8051.h"
#include "regwin.h"
#include "memwin.h"
#include "main.h"
#include "options.h"
#include "log.h"
#include "app-config.h"
extern struct app_config_t *cfg;
extern struct options_t options;
static int COL_ASCII;
static int N_COLUMNS;
enum {
COL_ADDRESS = 0,
COL_DATA0,
};
/* Contains informations for the two different memory window types. */
struct memwin_infos_t {
GtkWidget *memlist;
int data_rows;
uint32_t *crc;
int crc_init;
};
static struct memwin_infos_t memwin_infos_internal;
static struct memwin_infos_t memwin_infos_external;
static struct memwin_infos_t *memwin_infos;
/* Creating a model */
static GtkListStore *
memwin_init_store(int data_rows)
{
GtkTreeIter iter;
int row;
int col;
GtkListStore *store;
GType col_types[N_COLUMNS];
/* No need for static array, all our columns are of the same type. */
for (col = 0; col < N_COLUMNS; col++)
col_types[col] = G_TYPE_STRING;
store = gtk_list_store_newv(N_COLUMNS, col_types);
/* Add rows. */
for (row = 0; row < data_rows; row++)
gtk_list_store_append(store, &iter);
return store;
}
static void
memwin_cell_edited(GtkCellRendererText *cell, gchar *path_string,
gchar *new_str, gpointer model)
{
guint column;
enum mem_id_t memory_id;
gpointer columnptr;
gpointer memory_id_ptr;
GtkTreeIter iter;
int address;
uint8_t old;
int new;
char *str;
if (!model)
log_err("Unable to get model from cell renderer");
/* Column number is passed as renderer object data */
columnptr = g_object_get_data(G_OBJECT(cell), "column");
column = GPOINTER_TO_UINT(columnptr);
/* Memory ID is passed as renderer object data */
memory_id_ptr = g_object_get_data(G_OBJECT(cell), "memory_id");
memory_id = GPOINTER_TO_UINT(memory_id_ptr);
/* Get the iterator */
gtk_tree_model_get_iter_from_string(model, &iter, path_string);
/* Get base address. */
gtk_tree_model_get(model, &iter, COL_ADDRESS, &str, -1);
/* No need to check error, has already been validated. */
address = asciihex2int(str);
/* Convert column number (1, 2, 3...) to index (0, 1, 2...) */
address += (column - COL_DATA0);
old = mem_read8(memory_id, address);
log_info("Address: $%02X", address);
log_info(" old value: $%02X", old);
/* Convert new value (asciihex) to integer. */
new = asciihex2int(new_str);
if (asciihex2int_get_error()) {
log_warn(" new value: invalid");
return;
} else if ((new < 0) || (new > 255)) {
log_warn(" new value: out of range");
return;
} else {
log_info(" new value: $%02X", new);
}
/* Store new value in emulator memory. */
mem_write8(memory_id, address, new);
/* Convert to text. */
int2asciihex(new, str, 2);
/* Store new value in gtk model. */
gtk_list_store_set(GTK_LIST_STORE(model), &iter, column, str, -1);
/*
* Make sure to update all registers and memory.
* For example, BANKed registers depends on internal memory.
*/
emugtk_update_display();
};
static void
memwin_init_columns(GtkWidget *listview, enum mem_id_t memory_id)
{
int i;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
/* Columns and cell renderers */
renderer = gtk_cell_renderer_text_new();
/* Add address column */
column = gtk_tree_view_column_new_with_attributes(
"Address", renderer, "text", COL_ADDRESS, NULL);
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
for (i = COL_DATA0; i < (COL_DATA0 + cfg->bytes_per_row); i++) {
char col_name[8];
/* Create new renderer for each editable cell. */
renderer = gtk_cell_renderer_text_new();
/* Allow edition, align to left side. */
g_object_set(renderer, "editable", TRUE, "xalign", 0, NULL);
g_signal_connect(renderer, "edited",
G_CALLBACK(memwin_cell_edited),
gtk_tree_view_get_model(
GTK_TREE_VIEW(listview)));
/* Add column index and memory_id, used when editing the cell */
g_object_set_data(G_OBJECT(renderer), "column",
GUINT_TO_POINTER(i));
g_object_set_data(G_OBJECT(renderer), "memory_id",
GUINT_TO_POINTER(memory_id));
/* Use two digits only if DATA_ROWS > 10 */
if (cfg->bytes_per_row < 10)
sprintf(col_name, "B%1d", i - COL_DATA0);
else
sprintf(col_name, "B%02d", i - COL_DATA0);
column = gtk_tree_view_column_new_with_attributes(
col_name, renderer, "text", i, NULL);
gtk_tree_view_column_set_sizing(column,
GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
}
/* Add ASCII column, using fixed-font. */
renderer = gtk_cell_renderer_text_new();
g_object_set(renderer, "family", "Monospace", NULL);
column = gtk_tree_view_column_new_with_attributes(
"ASCII", renderer, "text", COL_ASCII, NULL);
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
}
static void
memwin_infos_select(enum mem_id_t memory_id)
{
if (memory_id == INT_MEM_ID) {
log_debug("memory ID = INTERNAL");
memwin_infos = &memwin_infos_internal;
} else if (memory_id == EXT_MEM_ID) {
log_debug("memory ID = EXTERNAL");
memwin_infos = &memwin_infos_external;
} else {
log_fail("Invalid memory type");
exit(1);
}
}
static void
compute_data_rows(int memory_id)
{
if (memory_id == INT_MEM_ID)
memwin_infos->data_rows = options.iram_size /
cfg->bytes_per_row;
else if (memory_id == EXT_MEM_ID)
memwin_infos->data_rows = options.xram_size /
cfg->bytes_per_row;
if (memwin_infos->crc)
free(memwin_infos->crc);
memwin_infos->crc = malloc(memwin_infos->data_rows * sizeof(uint32_t));
memwin_infos->crc_init = false;
}
GtkWidget *
memwin_init(char *title, enum mem_id_t memory_id)
{
GtkWidget *frame;
GtkWidget *scrollwin;
GtkListStore *store;
log_debug("memwin_init");
COL_ASCII = cfg->bytes_per_row + 1;
N_COLUMNS = COL_ASCII + 1;
frame = gtk_frame_new(title);
scrollwin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
GTK_SHADOW_ETCHED_OUT);
/* Automatically add scrollbars when necessary. */
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(frame), scrollwin);
memwin_infos_select(memory_id);
compute_data_rows(memory_id);
/* Creating a model */
store = memwin_init_store(memwin_infos->data_rows);
/* Creating the view component */
memwin_infos->memlist = gtk_tree_view_new_with_model(
GTK_TREE_MODEL(store));
gtk_tree_view_set_headers_visible(
GTK_TREE_VIEW(memwin_infos->memlist), TRUE);
gtk_container_add(GTK_CONTAINER(scrollwin), memwin_infos->memlist);
memwin_init_columns(memwin_infos->memlist, memory_id);
/*
* The tree view has acquired its own reference to the model, so we can
* drop ours. That way the model will be freed automatically when the
* tree view is destroyed.
*/
g_object_unref(store);
return frame;
}
/*
* Use CRC to detect which rows have changed. This is only to
* improve performance when using stepping mode, as we then only update
* rows which have been modified.
*/
static int
memwin_row_changed(enum mem_id_t memory_id, int row, unsigned int address)
{
int row_changed;
uint32_t crc_new = 0;
uint8_t *buf8;
buf8 = mem_getbuf(memory_id, address);
crc_new = crc32(0L, Z_NULL, 0);
crc_new = crc32(crc_new, buf8, cfg->bytes_per_row);
if ((memwin_infos->crc_init) &&
(crc_new == memwin_infos->crc[row])) {
row_changed = false;
} else {
memwin_infos->crc[row] = crc_new;
log_debug(" Row %02d value(s) change", row);
row_changed = true;
}
return row_changed;
}
/* Dump internal or external memory. */
void
memwin_refresh(enum mem_id_t memory_id)
{
int row;
unsigned int address = 0;
GtkListStore *store;
log_debug("memwin_refresh");
memwin_infos_select(memory_id);
store = GTK_LIST_STORE(gtk_tree_view_get_model(
GTK_TREE_VIEW(memwin_infos->memlist)));
for (row = 0; row < memwin_infos->data_rows;
row++, address += cfg->bytes_per_row) {
int valid;
GtkTreeIter iter;
char str[4+1]; /* Max. str len for address column (4 digits) */
char ascii_str[16+1]; /* Maximum 16 data columns. */
int col;
if (row == 0) {
/* Get first row in list store */
valid = gtk_tree_model_get_iter_first(
GTK_TREE_MODEL(store), &iter);
} else {
/* Get next row in list store */
valid = gtk_tree_model_iter_next(
GTK_TREE_MODEL(store), &iter);
}
if (!valid) {
log_err("Tree model: invalid iter");
return;
}
/* Only update row if it has been modified. */
if (memwin_row_changed(memory_id, row, address)) {
/* Display base address. */
int2asciihex(address, str, 4);
gtk_list_store_set(store, &iter, COL_ADDRESS, str, -1);
for (col = 0; col < cfg->bytes_per_row; col++) {
uint8_t data;
data = mem_read8(memory_id, address + col);
/* Display hex data */
int2asciihex(data, str, 2);
gtk_list_store_set(store, &iter, col + 1, str,
-1);
/* Append to ASCII string (if applicable). */
if (!isprint(data))
data = '.';
sprintf(&ascii_str[col], "%c", data);
}
/* Display ASCII characters. */
gtk_list_store_set(store, &iter, COL_ASCII, ascii_str,
-1);
}
}
/* At this point we know all rows crc have been initialized. */
memwin_infos->crc_init = true;
}

21
src/gtk/memwin.h Normal file
View File

@ -0,0 +1,21 @@
/*
* memwin.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef MEMWIN_H
#define MEMWIN_H 1
#include <gtk/gtk.h>
GtkWidget *
memwin_init(char *title, enum mem_id_t memory_id);
void
memwin_refresh(enum mem_id_t memory_id);
#endif /* MEMWIN_H */

47
src/gtk/messagebox.c Normal file
View File

@ -0,0 +1,47 @@
/*
* messagebox.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <gtk/gtk.h>
#include "common.h"
#include "messagebox.h"
extern GtkWidget *mainwin;
void
message_show_error(char *message)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new(GTK_WINDOW(mainwin),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
message, NULL);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
void
message_show_information(char *message)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new(GTK_WINDOW(mainwin),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
message, NULL);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}

21
src/gtk/messagebox.h Normal file
View File

@ -0,0 +1,21 @@
/*
* messagebox.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef MESSAGEBOX_H
#define MESSAGEBOX_H 1
#include <gtk/gtk.h>
void
message_show_error(char *message);
void
message_show_information(char *message);
#endif /* MESSAGEBOX_H */

293
src/gtk/pgmwin.c Normal file
View File

@ -0,0 +1,293 @@
/*
* pgmwin.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include "common.h"
#include "memory.h"
#include "cpu8051.h"
#include "opcodes.h"
#include "pgmwin.h"
#include "hexfile.h"
static GtkWidget *pgmlist;
#define LIST_VIEW_NAME "Program"
#define DATA_ROWS 100
enum {
COL_BREAKPT = 0,
COL_ADDR,
COL_B0,
COL_B1,
COL_B2,
COL_INST,
COL_ARGS,
COL_COLOR,
N_COLUMNS,
};
static char *col_names[N_COLUMNS] = {
"BPT",
"Address",
"B0",
"B1",
"B2",
"Mnemonic",
"Arguments",
"COLOR", /* Not displayed, used to set foreground color of cell. */
};
/* Creating a model */
static GtkListStore *
pgmwin_init_store(void)
{
GtkTreeIter iter;
int row;
int col;
GtkListStore *store;
GType col_types[N_COLUMNS];
/* No need for static array, all our columns are of the same type. */
for (col = 0; col < N_COLUMNS; col++)
col_types[col] = G_TYPE_STRING;
store = gtk_list_store_newv(N_COLUMNS, col_types);
/* Add rows. */
for (row = 0; row < DATA_ROWS; row++) {
gtk_list_store_append(store, &iter);
/* Color first row in red (current instruction). */
if (row == 0)
gtk_list_store_set(store, &iter, COL_COLOR, "red", -1);
else
gtk_list_store_set(store, &iter, COL_COLOR, "black",
-1);
}
return store;
}
static void
pgmwin_init_columns(void)
{
int k;
GtkCellRenderer *renderer;
/* Create renderer */
renderer = gtk_cell_renderer_text_new();
/* Add columns, except for last one (COL_COLOR). */
for (k = 0; k < COL_COLOR; k++) {
GtkTreeViewColumn *col;
/* Create tree view column */
col = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(col, col_names[k]);
gtk_tree_view_column_set_sizing(col,
GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(GTK_TREE_VIEW(pgmlist), col);
/* Pack cell renderer into column */
gtk_tree_view_column_pack_start(col, renderer, TRUE);
/* Establish connection between cell renderer and data store. */
gtk_tree_view_column_set_attributes(col, renderer, "text", k,
"foreground", COL_COLOR,
NULL);
}
}
/* Mouse button pressed in the window. */
static gint
pgmwin_sel_changed_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
/* Remove compiler warning about unused variables. */
(void) widget;
(void) event;
(void) data;
log_debug("pgmwin_sel_changed_event()");
/* This will only work in single or browse selection mode! */
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pgmlist));
if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
char *str_addr;
int val;
gtk_tree_model_get(model, &iter, COL_ADDR, &str_addr, -1);
/* Convert hex address in ASCII to integer. */
/* No need to check error, has already been validated. */
val = asciihex2int(str_addr);
log_debug(" row address is: $%04X", val);
breakpoint_toggle(val);
pgmwin_refresh();
g_free(str_addr);
} else {
log_debug(" no row selected");
}
return FALSE;
}
GtkWidget *
pgmwin_init(void)
{
GtkWidget *frame;
GtkWidget *scrollwin;
GtkListStore *store;
GtkTreeSelection *selection;
frame = gtk_frame_new(LIST_VIEW_NAME);
scrollwin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
GTK_SHADOW_ETCHED_OUT);
/* Automatically add scrollbars when necessary. */
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(frame), scrollwin);
/* Creating a model */
store = pgmwin_init_store();
/* Creating the view component */
pgmlist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pgmlist), TRUE);
gtk_container_add(GTK_CONTAINER(scrollwin), pgmlist);
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pgmlist));
/* Only one row can be selected at a time. */
gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
g_signal_connect(selection, "changed",
G_CALLBACK(pgmwin_sel_changed_event), NULL);
pgmwin_init_columns();
/*
* The tree view has acquired its own reference to the model, so we can
* drop ours. That way the model will be freed automatically when the
* tree view is destroyed.
*/
g_object_unref(store);
return frame;
}
/* Show disassembled program. */
void
pgmwin_refresh(void)
{
int row;
GtkListStore *store;
unsigned int address;
address = cpu8051.pc;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(pgmlist)));
for (row = 0; row < DATA_ROWS; row++) {
int valid;
GtkTreeIter iter;
char str[128];
int k;
int col_id;
int inst_size;
unsigned char opcode;
if (row == 0) {
/* Get first row in list store */
valid = gtk_tree_model_get_iter_first(
GTK_TREE_MODEL(store), &iter);
} else {
/* Get next row in list store */
valid = gtk_tree_model_iter_next(
GTK_TREE_MODEL(store), &iter);
}
if (!valid) {
log_err("Tree model: invalid iter");
return;
}
if (address > 0xFFFF) {
/*
* Not the most elegant solution, but it works to not
* display instructions past last address, 0xFFFF.
*/
gtk_list_store_set(store, &iter,
COL_BREAKPT, NULL,
COL_ADDR, NULL,
COL_B0, NULL,
COL_B1, NULL,
COL_B2, NULL,
COL_INST, NULL,
COL_ARGS, NULL,
COL_COLOR, NULL,
-1);
} else {
/* Display breakpoints. */
if (breakpoint_is_defined(address))
sprintf(str, "*");
else
str[0] = '\0';
gtk_list_store_set(store, &iter, COL_BREAKPT, str, -1);
/* Display base address. */
int2asciihex(address, str, 4);
gtk_list_store_set(store, &iter, COL_ADDR, str, -1);
opcode = mem_read8(PGM_MEM_ID, address);
inst_size = opcodes_get_instr_size(opcode);
/* Display instruction hex bytes. */
for (k = 0, col_id = COL_B0; k < 3; k++, col_id++) {
if (k < inst_size)
int2asciihex(mem_read8(PGM_MEM_ID,
address + k),
str, 2);
else
str[0] = '\0';
gtk_list_store_set(store, &iter, col_id, str,
-1);
}
/* Display instruction menmonic. */
(void) cpu8051_disasm_mnemonic(opcode, str);
gtk_list_store_set(store, &iter, COL_INST, str, -1);
/* Display instruction arguments (if applicable). */
cpu8051_disasm_args(address, str);
gtk_list_store_set(store, &iter, COL_ARGS, str, -1);
address += inst_size;
}
}
}

21
src/gtk/pgmwin.h Normal file
View File

@ -0,0 +1,21 @@
/*
* pgmwin.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef PGMWIN_H
#define PGMWIN_H 1
#include <gtk/gtk.h>
GtkWidget *
pgmwin_init(void);
void
pgmwin_refresh(void);
#endif /* PGMWIN_H */

241
src/gtk/pswwin.c Normal file
View File

@ -0,0 +1,241 @@
/*
* pswwin.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdint.h>
#include "common.h"
#include "reg8051.h"
#include "cpu8051.h"
#include "memory.h"
#include "pswwin.h"
#include "memwin.h"
#include "pgmwin.h"
#include "psw.h"
#include "instructions_8051.h"
#include "hexfile.h"
#include "main.h"
static GtkWidget *pswlist;
#define DATA_ROWS 1
#define LIST_VIEW_NAME "PSW"
enum {
COL_CY = 0,
COL_AC,
COL_F0,
COL_RS1,
COL_RS0,
COL_OV,
COL_RESERVED,
COL_P,
N_COLUMNS,
};
static char *col_names[N_COLUMNS] = {
"CY",
"AC",
"F0",
"RS1",
"RS0",
"OV",
"-",
"P",
};
/* Creating a model */
static GtkListStore *
pswwin_init_store(void)
{
GtkTreeIter iter;
int row;
int col;
GtkListStore *store;
GType col_types[N_COLUMNS];
/* No need for static array, all our columns are of the same type. */
for (col = 0; col < N_COLUMNS; col++)
col_types[col] = G_TYPE_STRING;
store = gtk_list_store_newv(N_COLUMNS, col_types);
/* Add rows. */
for (row = 0; row < DATA_ROWS; row++)
gtk_list_store_append(store, &iter);
return store;
}
static void
pswwin_cell_edited(GtkCellRendererText *cell, gchar *path_string,
gchar *new_str, gpointer model)
{
guint column;
gpointer columnptr;
GtkTreeIter iter;
uint8_t old;
int new;
char str[10];
int bit_index;
if (!model)
log_err("Unable to get model from cell renderer");
/* Column number is passed as renderer object data */
columnptr = g_object_get_data(G_OBJECT(cell), "column");
column = GPOINTER_TO_UINT(columnptr);
log_info("column = $%02X", column);
/* Get the iterator */
gtk_tree_model_get_iter_from_string(model, &iter, path_string);
bit_index = 7 - column;
old = psw_read_bit(bit_index);
log_info(" old value: %d", old);
/* Convert new value (asciihex) to integer. */
new = asciihex2int(new_str);
if (asciihex2int_get_error()) {
log_warn(" new value: invalid");
return;
} else if ((new != 0) && (new != 1)) {
log_warn(" new value: out of range");
return;
} else {
log_info(" new value: %d", new);
}
/* Store new value in emulator memory. */
psw_write_bit(bit_index, new);
/* Convert to text. */
int2asciihex(new, str, 1);
/* Store new value in gtk model. */
gtk_list_store_set(GTK_LIST_STORE(model), &iter, column, str, -1);
/*
* Make sure to update all registers and memory.
* For example, BANKed registers depends on internal memory.
*/
emugtk_update_display();
};
static void
pswwin_init_columns(void)
{
int k;
/* Add column for each bit in PSW. */
for (k = 0; k < N_COLUMNS; k++) {
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
/* Create new renderer for value column (editable). */
renderer = gtk_cell_renderer_text_new();
/* Allow edition, align to center. */
g_object_set(renderer, "editable", TRUE, "xalign", 0.5, NULL);
g_signal_connect(renderer, "edited",
G_CALLBACK(pswwin_cell_edited),
gtk_tree_view_get_model(
GTK_TREE_VIEW(pswlist)));
/* Add column index, used when editing the cell. */
g_object_set_data(G_OBJECT(renderer), "column",
GUINT_TO_POINTER(k));
column = gtk_tree_view_column_new_with_attributes(
col_names[k], renderer, "text", k, NULL);
/* Center column name */
g_object_set(column, "alignment", 0.5, NULL);
/* Hardcoded width... */
gtk_tree_view_column_set_sizing(column,
GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_fixed_width(column, 35);
gtk_tree_view_append_column(GTK_TREE_VIEW(pswlist), column);
}
}
GtkWidget *
pswwin_init(void)
{
GtkWidget *frame;
GtkListStore *store;
frame = gtk_frame_new(LIST_VIEW_NAME);
/* Creating a model */
store = pswwin_init_store();
/* Creating the view component */
pswlist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
gtk_tree_view_set_grid_lines(GTK_TREE_VIEW(pswlist),
GTK_TREE_VIEW_GRID_LINES_BOTH);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pswlist), TRUE);
gtk_container_add(GTK_CONTAINER(frame), pswlist);
pswwin_init_columns();
/*
* The tree view has acquired its own reference to the model, so we can
* drop ours. That way the model will be freed automatically when the
* tree view is destroyed.
*/
g_object_unref(store);
return frame;
}
/* Show registers. */
void
pswwin_refresh(void)
{
GtkListStore *store;
int valid;
GtkTreeIter iter;
int k;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(pswlist)));
/* Get first row in list store */
valid = gtk_tree_model_get_iter_first(
GTK_TREE_MODEL(store), &iter);
if (!valid) {
log_err("Tree model: invalid iter");
return;
}
/* Display bit values. */
for (k = 0; k < N_COLUMNS; k++) {
char str[4];
int bit_index;
bit_index = 7 - k;
int2asciihex(psw_read_bit(bit_index), str, 1);
gtk_list_store_set(store, &iter, k, str, -1);
}
}

21
src/gtk/pswwin.h Normal file
View File

@ -0,0 +1,21 @@
/*
* pswwin.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef PSWWIN_H
#define PSWWIN_H 1
#include <gtk/gtk.h>
GtkWidget *
pswwin_init(void);
void
pswwin_refresh(void);
#endif /* PSWWIN_H */

235
src/gtk/regwin.c Normal file
View File

@ -0,0 +1,235 @@
/*
* regwin.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include "common.h"
#include "reg8051.h"
#include "cpu8051.h"
#include "sfr.h"
#include "memory.h"
#include "regwin.h"
#include "memwin.h"
#include "pgmwin.h"
#include "instructions_8051.h"
#include "hexfile.h"
#include "main.h"
static GtkWidget *reglist;
#define LIST_VIEW_NAME "Registers"
#define DATA_ROWS SFR_REGS
enum {
COL_NAME = 0,
COL_VAL,
N_COLUMNS,
};
/* Creating a model */
static GtkListStore *
regwin_init_store(void)
{
GtkTreeIter iter;
int row;
int col;
GtkListStore *store;
GType col_types[N_COLUMNS];
/* No need for static array, all our columns are of the same type. */
for (col = 0; col < N_COLUMNS; col++)
col_types[col] = G_TYPE_STRING;
store = gtk_list_store_newv(N_COLUMNS, col_types);
/* Add rows. */
for (row = 0; row < DATA_ROWS; row++)
gtk_list_store_append(store, &iter);
return store;
}
static void
regwin_cell_edited(GtkCellRendererText *cell, gchar *path_string,
gchar *new_str, gpointer model)
{
GtkTreeIter iter;
int old;
int new;
char *str;
int rc;
struct regwin_infos_t *regwin_infos;
(void) cell; /* Remove compiler warning about unused variables. */
if (!model)
log_err("Unable to get model from cell renderer");
/* Get the iterator */
gtk_tree_model_get_iter_from_string(model, &iter, path_string);
/* Get register name. */
gtk_tree_model_get(model, &iter, COL_NAME, &str, -1);
log_info("Register: %s", str);
regwin_infos = sfr_get_infos(str);
log_info(" width: %d bits", 4 * regwin_infos->w);
/* Read current (old) value. */
gtk_tree_model_get(model, &iter, COL_VAL, &str, -1);
/* No need to check error, has already been validated. */
old = asciihex2int(str);
log_info(" old value: $%04X", old);
new = asciihex2int(new_str);
if (asciihex2int_get_error()) {
log_warn(" new value: invalid");
return;
}
log_info(" new value: $%04X", new);
/* Store new value in emulator register (if in range). */
rc = regwin_write(regwin_infos, new);
if (rc == 0) {
/* Store new value in gtk model. */
int2asciihex(new, str, regwin_infos->w);
gtk_list_store_set(GTK_LIST_STORE(model), &iter, COL_VAL, str,
-1);
/*
* Make sure to update all windows.
* For example, R0-R7 values depends on internal memory values.
*/
emugtk_update_display();
}
};
static void
regwin_init_columns(void)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
/* Columns and cell renderers */
renderer = gtk_cell_renderer_text_new();
/* Add Register column */
column = gtk_tree_view_column_new_with_attributes(
"Name", renderer, "text", COL_NAME, NULL);
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(GTK_TREE_VIEW(reglist), column);
/* Add Value column */
/* Create new renderer for value column (editable). */
renderer = gtk_cell_renderer_text_new();
/* Allow edition, align to right side. */
g_object_set(renderer, "editable", TRUE, "xalign", 1.0, NULL);
g_signal_connect(renderer, "edited",
G_CALLBACK(regwin_cell_edited),
gtk_tree_view_get_model(GTK_TREE_VIEW(reglist)));
column = gtk_tree_view_column_new_with_attributes(
"Value", renderer, "text", COL_VAL, NULL);
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_append_column(GTK_TREE_VIEW(reglist), column);
}
GtkWidget *
regwin_init(void)
{
GtkWidget *frame;
GtkWidget *scrollwin;
GtkListStore *store;
frame = gtk_frame_new(LIST_VIEW_NAME);
scrollwin = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
GTK_SHADOW_ETCHED_OUT);
/* Automatically add scrollbars when necessary. */
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(frame), scrollwin);
/* Creating a model */
store = regwin_init_store();
/* Creating the view component */
reglist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(reglist), TRUE);
gtk_container_add(GTK_CONTAINER(scrollwin), reglist);
regwin_init_columns();
/*
* The tree view has acquired its own reference to the model, so we can
* drop ours. That way the model will be freed automatically when the
* tree view is destroyed.
*/
g_object_unref(store);
return frame;
}
/* Show registers. */
void
regwin_refresh(void)
{
int row;
GtkListStore *store;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(reglist)));
for (row = 0; row < DATA_ROWS; row++) {
int valid;
GtkTreeIter iter;
int val;
char str[8];
struct regwin_infos_t *regwin_infos;
if (row == 0) {
/* Get first row in list store */
valid = gtk_tree_model_get_iter_first(
GTK_TREE_MODEL(store), &iter);
} else {
/* Get next row in list store */
valid = gtk_tree_model_iter_next(
GTK_TREE_MODEL(store), &iter);
}
if (!valid) {
log_err("Tree model: invalid iter");
return;
}
regwin_infos = sfr_get_infos_from_row(row);
val = regwin_read(row);
/* Convert to specified number of hex digits. */
int2asciihex(val, str, regwin_infos->w);
gtk_list_store_set(store, &iter,
COL_NAME, regwin_infos->name,
COL_VAL, str,
-1);
}
}

21
src/gtk/regwin.h Normal file
View File

@ -0,0 +1,21 @@
/*
* regwin.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef REGWIN_H
#define REGWIN_H 1
#include <gtk/gtk.h>
GtkWidget *
regwin_init(void);
void
regwin_refresh(void);
#endif /* REGWIN_H */

112
src/gtk/timerwin.c Normal file
View File

@ -0,0 +1,112 @@
/*
* timerwin.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include "common.h"
#include "timers.h"
#include "main.h"
static GtkWidget *label[GP_TIMERS_COUNT];
static GtkWidget *
button_add_stock(GtkWidget *box, gchar *stock_id, int display_label)
{
GtkWidget *button;
/* Create the button. */
if (display_label) {
/* By default, a label is appended to stock buttons. */
button = gtk_button_new_from_stock(stock_id);
} else {
GtkWidget *icon;
button = gtk_button_new();
gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NORMAL);
icon = gtk_image_new_from_stock(stock_id,
GTK_ICON_SIZE_SMALL_TOOLBAR);
gtk_container_add(GTK_CONTAINER(button), icon);
}
gtk_box_pack_start(GTK_BOX(box), button, false, false, 2);
return button;
}
void
timerwin_update(void)
{
int id;
char buf[128];
for (id = 0; id < GP_TIMERS_COUNT; id++) {
/* Display textin bold, with big font size. */
sprintf(buf , "<b><big>%08d</big></b> cycles",
gp_timer_read(id));
gtk_label_set_markup(GTK_LABEL(label[id]), buf);
}
}
static void
timer_reset_callback(GtkWidget *widget, gpointer data)
{
int id = GPOINTER_TO_INT(data);
/* Remove compiler warning about unused variables. */
(void) widget;
log_info("timer_reset_callback ID = %d", id);
gp_timer_reset(id);
timerwin_update();
}
GtkWidget *
timerwin_init(int id)
{
GtkWidget *frame;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *timer_reset_button;
char title[100];
log_debug("timer window init");
sprintf(title, "Emulator timer %c", 'A' + id);
frame = gtk_frame_new(title);
/* The items of the hbox are NOT given equal space in the box. */
hbox = gtk_hbox_new(false, 0);
/*
* If the button was added directly to the hbox, it would be as high
* as the frame widget (ugly). Adding it first to a vbox makes it have
* a box shape.
*/
vbox = gtk_vbox_new(true, 0);
timer_reset_button = button_add_stock(vbox, GTK_STOCK_REFRESH, false);
g_signal_connect(G_OBJECT(timer_reset_button), "clicked",
G_CALLBACK(timer_reset_callback), GINT_TO_POINTER(id));
gtk_box_pack_start(GTK_BOX(hbox), vbox, false, false, 3);
label[id] = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label[id]), "<small>Small text</small>");
gtk_box_pack_start(GTK_BOX(hbox), label[id], false, false, 10);
gtk_container_add(GTK_CONTAINER(frame), hbox);
return frame;
}

21
src/gtk/timerwin.h Normal file
View File

@ -0,0 +1,21 @@
/*
* timerwin.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef TIMERWIN_H
#define TIMERWIN_H 1
#include <gtk/gtk.h>
GtkWidget *
timerwin_init(int id);
void
timerwin_update(void);
#endif /* TIMERWIN_H */

189
src/gtk/viewmenu.c Normal file
View File

@ -0,0 +1,189 @@
/*
* viewmenu.c
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <gtk/gtk.h>
#include "common.h"
#include "main.h" /* For AddMenuSeparator() function. */
#include "messagebox.h"
#include "viewmenu.h"
#include "app-config.h"
extern struct app_config_t *cfg;
void toggle_layout(GtkWidget *widget, gpointer data)
{
int id;
id = GPOINTER_TO_UINT(data);
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
log_info(" Switching to layout %d", id);
cfg->layout = id;
message_show_information(
"You must restart for the changes to take effect");
}
}
void toggle_bytes_per_row(GtkWidget *widget, gpointer data)
{
int bytes_per_row;
bytes_per_row = GPOINTER_TO_UINT(data);
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
log_info(" Bytes per row = %d", bytes_per_row);
cfg->bytes_per_row = bytes_per_row;
emugtk_destroy_int_memory_paned();
emugtk_destroy_ext_memory_paned();
emugtk_recreate_memory_paned();
}
}
void toggle_int_memory(GtkWidget *widget, gpointer data)
{
(void) data; /* Remove compiler warning about unused variables. */
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
log_info(" View internal memory");
cfg->view_int_memory = 1;
emugtk_create_int_memory_paned();
} else {
cfg->view_int_memory = 0;
emugtk_destroy_int_memory_paned();
}
}
void toggle_ext_memory(GtkWidget *widget, gpointer data)
{
(void) data; /* Remove compiler warning about unused variables. */
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
log_info(" View external memory");
cfg->view_ext_memory = 1;
emugtk_create_ext_memory_paned();
} else {
cfg->view_ext_memory = 0;
emugtk_destroy_ext_memory_paned();
}
}
void
view_add_layout_submenu(GtkWidget *parent)
{
GtkWidget *submenu;
GtkWidget *layout;
GtkWidget *layout1;
GtkWidget *layout2;
GSList *group = NULL;
submenu = gtk_menu_new();
layout = gtk_menu_item_new_with_label("Layout");
layout1 = gtk_radio_menu_item_new_with_label(group, "Layout1");
group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(layout1));
layout2 = gtk_radio_menu_item_new_with_label(group, "Layout2");
if (cfg->layout == UI_LAYOUT1)
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(layout1),
TRUE);
else
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(layout2),
TRUE);
g_signal_connect(G_OBJECT(layout1), "activate",
G_CALLBACK(toggle_layout), (gpointer) UI_LAYOUT1);
g_signal_connect(G_OBJECT(layout2), "activate",
G_CALLBACK(toggle_layout), (gpointer) UI_LAYOUT2);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(layout), submenu);
gtk_menu_shell_append(GTK_MENU_SHELL(submenu), layout1);
gtk_menu_shell_append(GTK_MENU_SHELL(submenu), layout2);
gtk_menu_shell_append(GTK_MENU_SHELL(parent), layout);
}
void
view_add_bytes_per_row_submenu(GtkWidget *parent)
{
GtkWidget *submenu;
GtkWidget *item;
GtkWidget *item1;
GtkWidget *item2;
GSList *group = NULL;
submenu = gtk_menu_new();
item = gtk_menu_item_new_with_label("Bytes per row");
item1 = gtk_radio_menu_item_new_with_label(group, "8");
group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item1));
item2 = gtk_radio_menu_item_new_with_label(group, "16");
if (cfg->bytes_per_row == 8)
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item1),
TRUE);
else
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item2),
TRUE);
g_signal_connect(G_OBJECT(item1), "activate",
G_CALLBACK(toggle_bytes_per_row), (gpointer) 8);
g_signal_connect(G_OBJECT(item2), "activate",
G_CALLBACK(toggle_bytes_per_row), (gpointer) 16);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item1);
gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item2);
gtk_menu_shell_append(GTK_MENU_SHELL(parent), item);
}
void
view_add_menu(GtkWidget *menu_bar)
{
GtkWidget *item;
GtkWidget *menu;
GtkWidget *view;
menu = gtk_menu_new();
view = gtk_menu_item_new_with_label("View");
item = gtk_check_menu_item_new_with_label("Internal Memory");
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item),
cfg->view_int_memory);
g_signal_connect(G_OBJECT(item), "activate",
G_CALLBACK(toggle_int_memory), NULL);
item = gtk_check_menu_item_new_with_label("External Memory");
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item),
cfg->view_ext_memory);
g_signal_connect(G_OBJECT(item), "activate",
G_CALLBACK(toggle_ext_memory), NULL);
add_menu_separator(menu);
/* Add layout submenu */
view_add_layout_submenu(menu);
add_menu_separator(menu);
/* Add bytes per row submenu */
view_add_bytes_per_row_submenu(menu);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), view);
}

18
src/gtk/viewmenu.h Normal file
View File

@ -0,0 +1,18 @@
/*
* viewmenu.h
*
* Copyright (C) 1999 Jonathan St-André
* Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
*
* This file is released under the GPLv2
*/
#ifndef VIEWMENU_H
#define VIEWMENU_H 1
#include <gtk/gtk.h>
void
view_add_menu(GtkWidget *menu_bar);
#endif /* VIEWMENU_H */

View File

@ -1,258 +0,0 @@
Opcode(bin) Opcode Instruction Bytes Cycles
--------------------------------------------------------------
00000000 00 NOP 1 1
00000001 01 AJMP addr11 2 2
00000010 02 LJMP addr16 3 2
00000011 03 RR A 1 1
00000100 04 INC A 1 1
00000101 05 INC direct 2 1
00000110 06 INC @R0 1 1
00000111 07 INC @R1 1 1
00001000 08 INC R0 1 1
00001001 09 INC R1 1 1
00001010 0A INC R2 1 1
00001011 0B INC R3 1 1
00001100 0C INC R4 1 1
00001101 0D INC R5 1 1
00001110 0E INC R6 1 1
00001111 0F INC R7 1 1
00010000 10 JBC bitaddr,reladdr 3 2
00010001 11 ACALL addr11 2 2
00010010 12 LCALL addr16 3 2
00010011 13 RRC A 1 1
00010100 14 DEC A 1 1
00010101 15 DEC direct 2 1
00010110 16 DEC @R0 1 1
00010111 17 DEC @R1 1 1
00011000 18 DEC R0 1 1
00011001 19 DEC R1 1 1
00011010 1A DEC R2 1 1
00011011 1B DEC R3 1 1
00011100 1C DEC R4 1 1
00011101 1D DEC R5 1 1
00011110 1E DEC R6 1 1
00011111 1F DEC R7 1 1
00100000 20 JB bitaddr,reladdr 3 2
00100001 21 AJMP addr11 2 2
00100010 22 RET 1 2
00100011 23 RL A 1 1
00100100 24 ADD A,#data 2 1
00100101 25 ADD A,direct 2 1
00100110 26 ADD A,@R0 1 1
00100111 27 ADD A,@R1 1 1
00101000 28 ADD A,R0 1 1
00101001 29 ADD A,R1 1 1
00101010 2A ADD A,R2 1 1
00101011 2B ADD A,R3 1 1
00101100 2C ADD A,R4 1 1
00101101 2D ADD A,R5 1 1
00101110 2E ADD A,R6 1 1
00101111 2F ADD A,R7 1 1
00110000 30 JNB bitaddr,reladdr 3 2
00110001 31 ACALL addr11 2 2
00110010 32 RETI 1 2
00110011 33 RLC A 1 1
00110100 34 ADDC A,#data 2 1
00110101 35 ADDC A,direct 2 1
00110110 36 ADDC A,@R0 1 1
00110111 37 ADDC A,@R1 1 1
00111000 38 ADDC A,R0 1 1
00111001 39 ADDC A,R1 1 1
00111010 3A ADDC A,R2 1 1
00111011 3B ADDC A,R3 1 1
00111100 3C ADDC A,R4 1 1
00111101 3D ADDC A,R5 1 1
00111110 3E ADDC A,R6 1 1
00111111 3F ADDC A,R7 1 1
01000000 40 JC reladdr 2 2
01000001 41 AJMP addr11 2 2
01000010 42 ORL direct,A 2 1
01000011 43 ORL direct,#data 3 2
01000100 44 ORL A,#data 2 1
01000101 45 ORL A,direct 2 1
01000110 46 ORL A,@R0 1 1
01000111 47 ORL A,@R1 1 1
01001000 48 ORL A,R0 1 1
01001001 49 ORL A,R1 1 1
01001010 4A ORL A,R2 1 1
01001011 4B ORL A,R3 1 1
01001100 4C ORL A,R4 1 1
01001101 4D ORL A,R5 1 1
01001110 4E ORL A,R6 1 1
01001111 4F ORL A,R7 1 1
01010000 50 JNC reladdr 2 2
01010001 51 ACALL addr11 2 2
01010010 52 ANL direct,A 2 1
01010011 53 ANL direct,#data 3 2
01010100 54 ANL A,#data 2 1
01010101 55 ANL A,direct 2 1
01010110 56 ANL A,@R0 1 1
01010111 57 ANL A,@R1 1 1
01011000 58 ANL A,R0 1 1
01011001 59 ANL A,R1 1 1
01011010 5A ANL A,R2 1 1
01011011 5B ANL A,R3 1 1
01011100 5C ANL A,R4 1 1
01011101 5D ANL A,R5 1 1
01011110 5E ANL A,R6 1 1
01011111 5F ANL A,R7 1 1
01100000 60 JZ reladdr 2 2
01100001 61 AJMP addr11 2 2
01100010 62 XRL direct,A 2 1
01100011 63 XRL direct,#data 3 2
01100100 64 XRL A,#data 2 1
01100101 65 XRL A,direct 2 1
01100110 66 XRL A,@R0 1 1
01100111 67 XRL A,@R1 1 1
01101000 68 XRL A,R0 1 1
01101001 69 XRL A,R1 1 1
01101010 6A XRL A,R2 1 1
01101011 6B XRL A,R3 1 1
01101100 6C XRL A,R4 1 1
01101101 6D XRL A,R5 1 1
01101110 6E XRL A,R6 1 1
01101111 6F XRL A,R7 1 1
01110000 70 JNZ reladdr 2 2
01110001 71 ACALL addr11 2 2
01110010 72 ORL C,bitaddr 2 2
01110011 73 JMP @A+DPTR 1 2
01110100 74 MOV A,#data 2 1
01110101 75 MOV direct,#data 3 2
01110110 76 MOV @R0,#data 2 1
01110111 77 MOV @R1,#data 2 1
01111000 78 MOV R0,#data 2 1
01111001 79 MOV R1,#data 2 1
01111010 7A MOV R2,#data 2 1
01111011 7B MOV R3,#data 2 1
01111100 7C MOV R4,#data 2 1
01111101 7D MOV R5,#data 2 1
01111110 7E MOV R6,#data 2 1
01111111 7F MOV R7,#data 2 1
10000000 80 SJMP reladdr 2 2
10000001 81 AJMP addr11 2 2
10000010 82 ANL C,bitaddr 2 1
10000011 83 MOVC A,@A+PC 1 1
10000100 84 DIV AB 1 4
10000101 85 MOV direct,direct 3 1
10000110 86 MOV direct,@R0 2 2
10000111 87 MOV direct,@R1 2 2
10001000 88 MOV direct,R0 2 2
10001001 89 MOV direct,R1 2 2
10001010 8A MOV direct,R2 2 2
10001011 8B MOV direct,R3 2 2
10001100 8C MOV direct,R4 2 2
10001101 8D MOV direct,R5 2 2
10001110 8E MOV direct,R6 2 2
10001111 8F MOV direct,R7 2 2
10010000 90 MOV DPTR,#data16 3 2
10010001 91 ACALL addr11 2 2
10010010 92 MOV bitaddr,C 2 2
10010011 93 MOVC A,@A+DPTR 1 2
10010100 94 SUBB A,#data 2 1
10010101 95 SUBB A,direct 2 1
10010110 96 SUBB A,@R0 1 1
10010111 97 SUBB A,@R1 1 1
10011000 98 SUBB A,R0 1 1
10011001 99 SUBB A,R1 1 1
10011010 9A SUBB A,R2 1 1
10011011 9B SUBB A,R3 1 1
10011100 9C SUBB A,R4 1 1
10011101 9D SUBB A,R5 1 1
10011110 9E SUBB A,R6 1 1
10011111 9F SUBB A,R7 1 1
10100000 A0 ORL C,/bitaddr 2 1
10100001 A1 AJMP addr11 2 2
10100010 A2 MOV C,bitaddr 2 1
10100011 A3 INC DPTR 1 2
10100100 A4 MUL AB 1 4
10100101 A5 INVALID 1 1
10100110 A6 MOV @R0,direct 2 2
10100111 A7 MOV @R1,direct 2 2
10101000 A8 MOV R0,direct 2 2
10101001 A9 MOV R1,direct 2 2
10101010 AA MOV R2,direct 2 2
10101011 AB MOV R3,direct 2 2
10101100 AC MOV R4,direct 2 2
10101101 AD MOV R5,direct 2 2
10101110 AE MOV R6,direct 2 2
10101111 AF MOV R7,direct 2 2
10110000 B0 ANL C,/bitaddr 2 1
10110001 B1 ACALL addr11 2 2
10110010 B2 CPL bitaddr 2 1
10110011 B3 CPL C 1 1
10110100 B4 CJNE A,#data,reladdr 3 2
10110101 B5 CJNE A,direct,reladdr 3 2
10110110 B6 CJNE @R0,#data,reladdr 3 2
10110111 B7 CJNE @R1,#data,reladdr 3 2
10111000 B8 CJNE R0,#data,reladdr 3 2
10111001 B9 CJNE R1,#data,reladdr 3 2
10111010 BA CJNE R2,#data,reladdr 3 2
10111011 BB CJNE R3,#data,reladdr 3 2
10111100 BC CJNE R4,#data,reladdr 3 2
10111101 BD CJNE R5,#data,reladdr 3 2
10111110 BE CJNE R6,#data,reladdr 3 2
10111111 BF CJNE R7,#data,reladdr 3 2
11000000 C0 PUSH direct 2 2
11000001 C1 AJMP addr11 2 2
11000010 C2 CLR bitaddr 2 1
11000011 C3 CLR C 1 1
11000100 C4 SWAP A 1 1
11000101 C5 XCH A,direct 2 1
11000110 C6 XCH A,@R0 1 1
11000111 C7 XCH A,@R1 1 1
11001000 C8 XCH A,R0 1 1
11001001 C9 XCH A,R1 1 1
11001010 CA XCH A,R2 1 1
11001011 CB XCH A,R3 1 1
11001100 CC XCH A,R4 1 1
11001101 CD XCH A,R5 1 1
11001110 CE XCH A,R6 1 1
11001111 CF XCH A,R7 1 1
11010000 D0 POP direct 2 2
11010001 D1 ACALL addr11 2 2
11010010 D2 SETB bitaddr 2 1
11010011 D3 SETB C 1 1
11010100 D4 DA A 1 1
11010101 D5 DJNZ direct,reladdr 3 2
11010110 D6 XCHD A,@R0 1 1
11010111 D7 XCHD A,@R1 1 1
11011000 D8 DJNZ R0,reladdr 2 2
11011001 D9 DJNZ R1,reladdr 2 2
11011010 DA DJNZ R2,reladdr 2 2
11011011 DB DJNZ R3,reladdr 2 2
11011100 DC DJNZ R4,reladdr 2 2
11011101 DD DJNZ R5,reladdr 2 2
11011110 DE DJNZ R6,reladdr 2 2
11011111 DF DJNZ R7,reladdr 2 2
11100000 E0 MOVX A,@DPTR 1 2
11100001 E1 AJMP addr11 2 2
11100010 E2 MOVX A,@R0 1 2
11100011 E3 MOVX A,@R1 1 2
11100100 E4 CLR A 1 1
11100101 E5 MOV A,direct 2 1
11100110 E6 MOV A,@R0 1 1
11100111 E7 MOV A,@R1 1 1
11101000 E8 MOV A,R0 1 1
11101001 E9 MOV A,R1 1 1
11101010 EA MOV A,R2 1 1
11101011 EB MOV A,R3 1 1
11101100 EC MOV A,R4 1 1
11101101 ED MOV A,R5 1 1
11101110 EE MOV A,R6 1 1
11101111 EF MOV A,R7 1 1
11110000 F0 MOVX @DPTR,A 1 2
11110001 F1 ACALL addr11 2 2
11110010 F2 MOVX @R0,A 1 2
11110011 F3 MOVX @R1,A 1 2
11110100 F4 CPL A 1 1
11110101 F5 MOV direct,A 2 1
11110110 F6 MOV @R0,A 1 1
11110111 F7 MOV @R1,A 1 1
11111000 F8 MOV R0,A 1 1
11111001 F9 MOV R1,A 1 1
11111010 FA MOV R2,A 1 1
11111011 FB MOV R3,A 1 1
11111100 FC MOV R4,A 1 1
11111101 FD MOV R5,A 1 1
11111110 FE MOV R6,A 1 1
11111111 FF MOV R7,A 1 1

View File

@ -1,115 +0,0 @@
:0600000002003302003390
:03000B00020033BD
:03001300020033B5
:03001B00020033AD
:03002300020033A5
:03002B000200339D
:100033007581801202D312024375540075550085F1
:100043004356854457755BC61204C8120493740360
:100053002557F543855A56855B57755B0A1204C8C5
:10006300120493E5574430F55E75F000E543120240
:10007300DC85514F85525085535175522E855E5301
:1000830074501203067404120306E54F120306E5C7
:1000930050120306E551120306E552120306E55317
:1000A300120306745A12030675300075315D7532FA
:1000B300C01204E78534F0E5351202DC74501203F4
:1000C300067401120306E54F120306E550120306F8
:1000D300E551120306E552120306E55312030674B3
:1000E3005A12030675F000E5361202DC745012034F
:1000F300067405120306E551120306E552120306C0
:10010300E553120306745A12030675F000E537121D
:1001130002DC74501203067406120306E55112033F
:1001230006E552120306E553120306745A12030638
:10013300E53875F00584C5F0C3334430F55FC5F089
:1001430075F0001202DC85525085535175522E858D
:100153005F5374501203067408120306E55012032A
:1001630006E551120306E552120306E55312030690
:10017300745A12030675540075550085415685421D
:1001830057755B641204C87554001204938556F0C6
:10019300E5571202DC74501203067402120306E5DB
:1001A30051120306E552120306E553120306745A6D
:1001B300120306755400755500853B56853C5775EB
:1001C3005B0F1204C812049385575C855A56855BEE
:1001D30057755B641204C81204938556F0E55712F1
:1001E30002DC85525D85535E75F000E55C1202DC2E
:1001F30085524F85535075512E855D52855E5374DC
:10020300501203067407120306E54F120306E55066
:10021300120306E551120306E552120306E55312D3
:100223000306745A12030674201203060139756219
:1002330016740075F000D5F0FDD5E0F7D562F22213
:10024300783B7900E9120255A64E08A64D0809B974
:1002530008F2D2B3C2B1C2B300D2B3C2B6C2B300C2
:10026300D2B3F580C2B300D2B3D2B6C2B300D2B315
:10027300D2B1C2B31202CA7580FFD2B3C2B1C2B344
:1002830000D2B3C2B7C2B30085804DD2B3D2B7C2D6
:10029300B300D2B3D2B1C2B300D2B3D2B2C2B300AD
:1002A300D2B3C2B1C2B300D2B3C2B7C2B300858066
:1002B3004E00D2B3D2B7C2B300D2B3D2B1C2B300ED
:1002C300D2B3C2B2C2B322D2B300C2B330B0F822A7
:1002D30075D54475B0F3513122C00078537554007D
:1002E30075550085F056F557755800755900755AC0
:1002F30000755B0A120314E55B4430F618B84EE848
:10030300D00022F586B290E5AA53E08060F9E58635
:1003130022C004C003C002C001C0007504207503DD
:100323000075020075010075000012038F1203A50A
:100333004022C3E5039558403A7019C3E502955925
:1003430040317010C3E501955A40287007C3E5009A
:10035300955B401FC3E500955BF500E501955AF5F4
:1003630001E5029559F502E5039558F503E557D2E2
:10037300E0F557DCB585035885025985015A850098
:100383005BD000D001D002D003D00422C3E55733A1
:10039300F557E55633F556E55533F555E55433F53D
:1003A3005422E50033F500E50133F501E50233F5A9
:1003B30002E50333F50322C002C001C00075021B2E
:1003C30075010075000012040312041D4010C3E5FB
:1003D30001955A401C7007C3E500955B4013C3E5C4
:1003E30000955BF500E501955AF501E557D2E0F577
:1003F30057DAD385015A85005BD000D001D00222A1
:10040300C3E55733F557E55633F556E55533F555FB
:10041300E5543392E35407F55422E50033F500E540
:100423000133F50122C002C001C000750216750137
:10043300007500001204711204844010C3E5019595
:100443005A401C7007C3E500955B4013C3E5009554
:100453005BF500E501955AF501E557D2E0F557DA6A
:10046300D385015A85005BD000D001D00222C3E5B9
:100473005733F557E55633F556E55533F55592E6BB
:1004830022E50033F500E5013392E6543FF50122FE
:1004930085575B85565A535A0F1204B81204B81283
:1004A30004B81204B853540F8556578555568554CE
:1004B3005575540022E55413F554E55513F555E5E8
:1004C3005613F55622E556855BF0A4F55685F0558F
:1004D300E557855BF0A4F557C5F02556F556E43589
:1004E30055F555221205751205981205B5E53654D2
:1004F300F0C4C5F0E53754F025F0F5F01205DAF84D
:10050300E5F0240130D605E8F90205131205DAF9FE
:10051300E5F024105007E8FAE9FB020536F5F0127E
:1005230005DAFAE5F0240130D605EAFB02053612B6
:1005330005DAFB88F0E9AC36120553F88AF0EBAC28
:1005430036120553FA88F0EAAC37120553F5382210
:10055300C0F0C223C395F05005F42401D223F5F073
:10056300EC540FA454F0C4302303F42401D0F02539
:10057300F02275540775552775560E755700E530EB
:10058300B4000B85315A85325B71BA0205918556E9
:100593003485573522C3E5359490F556E5349401F7
:1005A300F555755700C3755A25755B809128855796
:1005B3003622755400755500C3E54394285001E471
:1005C300F556755700755800755900755A00755BD7
:1005D300A071148557372224E8F58274053400F599
:1005E3008374009322111123465F5F666666666615
:1005F3006666585858111123465F5F6666666666DD
:100603006666585858111123465F5F6666666666CC
:100613006666585858111123465F5F6666666666BC
:100623006666585858111123465F5F6666666666AC
:100633006666585858111123465F5F66666666669C
:100643006666585858111123465F5F66666666668C
:100653006666585858111123465B5B626262626298
:1006630062625454541111234651515858585858E2
:100673005858585858111123464A4A51515151510B
:10068300515151515111111C3846464A4A4A4A4A5E
:100693004A4A4A4A4A11111C343F3F4343434343A6
:1006A300434343434311111C3438383C3C3C3C3CEA
:1006B3003C3C3C3C3C11111C2A2D2D313131313154
:1006C300313131313111111C3438383C3C3C3C3C24
:1006D3003C3C3C3C3C11111C2A2D2D313131313134
:0506E30031313131311D
:00000001FF

View File

@ -1,13 +0,0 @@
:03000000020033C8
:1000330075818075D54475A000C290E4F500E50094
:1000430012007DF586D29005A07400D5E0FDC29024
:10005300E5AA53E08060F9E5861200690500C3E56F
:1000630000945040D92222752005740075F000D504
:10007300F0FDD5E0F7D520F20022248BF582740041
:100083003400F5837400932252504D3A31303234A8
:1000930035204D41503A313033204D41543A3131BE
:1000A30030204241543A31322E3420202020202067
:1000B3000D0A0A45474F3A31342E36202054505307
:1000C3003A31303020414E473A33302020434C54AC
:0B00D3003A313038202020202020206F
:00000001FF

View File

@ -1,179 +0,0 @@
;*******************************************************************************
;* Système d'Injection et d'Allumage Électronique *
;* Version : 01 *
;* Auteur : Hugo Villeneuve *
;* *
;* 10 mars 1999 *
;*******************************************************************************
$MOD52 ; Micro-contrôleur Atmel AT89S8252
;*******************************************************************************
;* Définition des constantes *
;*******************************************************************************
TOS EQU 60h ; Adresse du dessus de la pile.
CR EQU 0Dh ; Code ASCII pour un retour de chariot.
LF EQU 0Ah ; Code ASCII pour un changement de ligne
;*******************************************************************************
;* Définition des variables *
;*******************************************************************************
BSEG
ORG 20h
C_FLAG: DBIT 1
Z_FLAG: DBIT 2
N_FLAG: DBIT 3 ; Utilisé par la sous-routine MULT8_16
SIGNE: DBIT 4 ; Utilisé pour l'interpolation.
DSEG
ORG 30h
PERIODE2: DS 1 ; Période pour une rotation du vilebrequin, sur 24 bits.
PERIODE1: DS 1
PERIODE0: DS 1
POSITION_VILB: DS 1 ; Renseignement sur la position actuelle du vilebrequin (zones 0,1 ou 2).
VITESSE_RPM: DS 2 ; Vitesse de rotation du moteur en RPM.
INDEX_RPM: DS 1 ; Index de 8 bits pour l'adressage des colonnes de la table d'allumage.
INDEX_MAP: DS 1 ; Index de 8 bits pour l'adressage des lignes de la table d'allumage.
ANGLE: DS 1 ; Angle d'allumage calculé à partir de la table.
BAT: DS 2 ; Voltage de la batterie.
MAT: DS 2 ; Manifold Air Temperature.
CLT: DS 2 ; Coolant Temperature.
TPS: DS 2 ; Throttle Position Sensor.
MAP: DS 2 ; Manifold Absolute Pressure.
EGO: DS 2 ; Exhaust Gas-Oxygen Sensor.
CAN6: DS 2 ; Canal #6 du convertisseur AN.
CAN7: DS 2 ; Canal #7 du convertisseur AN.
GAMMA: DS 2 ; Rapport Air/Carburant.
LSB_CAN: DS 1 ; Octet de poids faible de la conversion Analogique-Numérique.
MSB_CAN: DS 1 ; Octet de poids fort de la conversion Analogique-Numérique.
NOMBRE4: DS 1 ; Stockage des codes ASCII pour les conversions.
NOMBRE3: DS 1
NOMBRE2: DS 1
NOMBRE1: DS 1
NOMBRE0: DS 1
C3: DS 1 ; Accumulateur C de 32 bits pour les calculs mathématiques.
C2: DS 1
C1: DS 1
C0: DS 1
D3: DS 1 ; Accumulateur D de 32 bits pour les calculs mathématiques.
D2: DS 1
D1: DS 1
D0: DS 1
TMP6: DS 1 ; Variables temporaires utilisées pour les calculs mathématiques.
TMP5: DS 1 ; FAIRE LE MÉNAGE VARIABLES NON UTILISEES!!!
TMP4: DS 1
TMP3: DS 1
TMP2: DS 1
TMP1: DS 1
TMP0: DS 1
VAR0: DS 1
VAR1: DS 1
VAR2: DS 1
;*******************************************************************************
;* Définition des régistres spécifiques au AT89S8252 *
;*******************************************************************************
SPCR DATA 0D5h ; SPCR - SPI Control Register
SPSR DATA 0AAh ; SPSR - SPI Status Register
SPIF EQU 10000000b ; Masque pour le drapeau SPI.
WCOL EQU 01000000b ; Masque pour le drapeau Write Collision.
SPDR DATA 086h ; SPDR - SPI Data Register
;*******************************************************************************
;* Vecteurs d'interruptions *
;*******************************************************************************
CSEG
ORG 0000h ; Vecteur d'interruption du RESET.
JMP DEBUT
ORG 0003h ; Vecteur pour l'interruption EXTERNE 0.
JMP VILEBREQUIN
ORG 000Bh ; Vecteur pour l'interruption du TIMER 0.
JMP DEBUT
ORG 0013h ; Vecteur pour l'interruption EXTERNE 1.
JMP DEBUT
ORG 001Bh ; Vecteur pour l'interruption du TIMER 1.
JMP DEBUT
ORG 0023h ; Vecteur pour l'interruption du Port série.
JMP DEBUT
ORG 002Bh ; Vecteur pour l'interruption du TIMER 2.
JMP DEBUT
;*******************************************************************************
;* Début du programme principal *
;*******************************************************************************
ORG 0033h
DEBUT:
MOV SP,#TOS ; Initialisation de la pile.
CALL INITIALISATION
; il ne faut pas modifier la valeur de P1.0!!!
ICI:
NOP
NOP
NOP
NOP
JMP ICI
;*******************************************************************************
;* Délai *
;*******************************************************************************
DELAI: MOV TMP0,#016h ; Délai de 1/2 seconde.
B3: MOV A,#0
B2: MOV B,#0
B1: DJNZ B,B1
DJNZ ACC,B2
DJNZ TMP0,B3
RET
;*******************************************************************************
;* INTERRUPTION *
;*******************************************************************************
VILEBREQUIN:
RETI
;*******************************************************************************
;* Initialisation *
;*******************************************************************************
INITIALISATION: MOV SPCR,#01000100b ; Interruption SPI désactivée;
; Activation du port SPI;
; Ordre des transferts : MSB en premier;
; Opération en mode escalve (SLAVE);
; Polarité de l'horloge : niveau bas si inactif.
; Phase de l'horloge : transfert sur front montant.
MOV TH0,#2
MOV TL0,#55h
SETB TCON.4 ; Timer 0 ON.
SETB TCON.6 ; Timer 1 ON.
MOV TMOD,#00010001B ; Initialisation des timers 0 et 1 en timers de
; 16 bits, incrémentés par l'horloge interne
; Chaque timer est incrémenté tant que le bit correspondant de
; TCON est à 1 (TCON.4 et TCON.6).
RET
END

Some files were not shown because too many files have changed in this diff Show More