mirror of
http://git.hugovil.com/git/emu8051.git
synced 2025-05-09 17:01:03 +08:00
Compare commits
265 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
73774e5974 | ||
![]() |
c7eae29d2f | ||
![]() |
b1c46135a4 | ||
![]() |
9cd867c94a | ||
![]() |
121bcb38f2 | ||
![]() |
7d0bd87bf6 | ||
![]() |
9241cbf30e | ||
![]() |
3e3b891049 | ||
![]() |
486bd979e3 | ||
![]() |
2f8c619857 | ||
![]() |
3ca737ea38 | ||
![]() |
972da42d11 | ||
![]() |
d1392836d0 | ||
![]() |
acff1c38b1 | ||
![]() |
f7e3f1d8d0 | ||
![]() |
b89d7661e7 | ||
![]() |
b5d52c94a7 | ||
![]() |
e45e088e0d | ||
![]() |
3edaa24acc | ||
![]() |
401c1d7060 | ||
![]() |
ab28e54867 | ||
![]() |
4c4ca66c31 | ||
![]() |
fbbb71d6d8 | ||
![]() |
7abd6d07ea | ||
![]() |
c91e69d435 | ||
![]() |
e417485aaf | ||
![]() |
87daca654d | ||
![]() |
c69c15d65b | ||
![]() |
00deadc94f | ||
![]() |
8bfc53036a | ||
![]() |
ba0e6b3b86 | ||
![]() |
4c9cf2f222 | ||
![]() |
1d394c78b9 | ||
![]() |
dc0e2b9353 | ||
![]() |
5419d1bd9d | ||
![]() |
3c838204cd | ||
![]() |
75172f0ea5 | ||
![]() |
93c2708bee | ||
![]() |
888cea8f85 | ||
![]() |
8e5b455c12 | ||
![]() |
f2fba46bfe | ||
![]() |
1466890269 | ||
![]() |
f2f9b967b4 | ||
![]() |
7c267c5882 | ||
![]() |
a43a2e343e | ||
![]() |
c7d14532b0 | ||
![]() |
fd418e0f87 | ||
![]() |
ce650967bd | ||
![]() |
d755f96382 | ||
![]() |
1f9c51e5df | ||
![]() |
fc904031c8 | ||
![]() |
c2ac9fc48f | ||
![]() |
cc6633f78b | ||
![]() |
310d829f65 | ||
![]() |
e8c456321e | ||
![]() |
b470088f1c | ||
![]() |
d74a41311f | ||
![]() |
a6ccc722bd | ||
![]() |
656993ee5e | ||
![]() |
ff643bede1 | ||
![]() |
d230e5df59 | ||
![]() |
30f7307f61 | ||
![]() |
5e7b849e7d | ||
![]() |
8f1773713c | ||
![]() |
cc7dd9b04f | ||
![]() |
9417a6bc0b | ||
![]() |
cec5fe02c3 | ||
![]() |
6281db4c82 | ||
![]() |
34513fc19f | ||
![]() |
71c48441ed | ||
![]() |
877e908e7b | ||
![]() |
84a325ac72 | ||
![]() |
b58acccaf0 | ||
![]() |
0027047772 | ||
![]() |
7f72e34564 | ||
![]() |
290e4eb58e | ||
![]() |
3a89081827 | ||
![]() |
dd7540145e | ||
![]() |
30d141860a | ||
![]() |
4055176e86 | ||
![]() |
670bbd59fa | ||
![]() |
57f6d79aa0 | ||
![]() |
702da8f531 | ||
![]() |
fa97a074e5 | ||
![]() |
1590b0711f | ||
![]() |
bd7be8da77 | ||
![]() |
5194d331cd | ||
![]() |
955a5eaa95 | ||
![]() |
1eb382f725 | ||
![]() |
b8e00ae8a1 | ||
![]() |
429bc0270f | ||
![]() |
2407d4a9a8 | ||
![]() |
b95c4f897b | ||
![]() |
cca33e1d25 | ||
![]() |
187e9a2c6c | ||
![]() |
96a44157eb | ||
![]() |
091899a37a | ||
![]() |
7977d9426b | ||
![]() |
fb189bd5ce | ||
![]() |
5088955838 | ||
![]() |
a46ab59d50 | ||
![]() |
356fc4e3a3 | ||
![]() |
bdc8dc1d31 | ||
![]() |
ce24c216aa | ||
![]() |
6a014db0cd | ||
![]() |
ef76945139 | ||
![]() |
5d04244ebc | ||
![]() |
e93543c1a1 | ||
![]() |
1a20c858a9 | ||
![]() |
28f33d3ca4 | ||
![]() |
0315df6597 | ||
![]() |
d27ffb9c24 | ||
![]() |
7521627a72 | ||
![]() |
7a22c370ea | ||
![]() |
594b0ac005 | ||
![]() |
97e8525955 | ||
![]() |
ab08aba210 | ||
![]() |
3e23ac6c01 | ||
![]() |
5f0e9d167d | ||
![]() |
359b0be02b | ||
![]() |
8b2f6f3ebb | ||
![]() |
3e3d02a2f2 | ||
![]() |
444731db04 | ||
![]() |
72e3350162 | ||
![]() |
3fed93eb25 | ||
![]() |
b6dd8fec84 | ||
![]() |
a1c2d96861 | ||
![]() |
381b6d7dd0 | ||
![]() |
e75510dd87 | ||
![]() |
dd92f3969f | ||
![]() |
18b62c73db | ||
![]() |
ccb7a5d184 | ||
![]() |
8c2d345bc7 | ||
![]() |
8d9b71ab38 | ||
![]() |
6bf8b77a5e | ||
![]() |
495c40d54e | ||
![]() |
484f0d39a0 | ||
![]() |
b7b1c62985 | ||
![]() |
f49cd33240 | ||
![]() |
6743535949 | ||
![]() |
98b757f83d | ||
![]() |
ad5ac01289 | ||
![]() |
61ae08f73d | ||
![]() |
47852aee98 | ||
![]() |
f9394f5df4 | ||
![]() |
e6f062fc43 | ||
![]() |
5905b40585 | ||
![]() |
82819ebb72 | ||
![]() |
eff770859b | ||
![]() |
d1c1972f26 | ||
![]() |
84075f7a17 | ||
![]() |
47f57bc580 | ||
![]() |
21fb2cf2a3 | ||
![]() |
3615ed71ec | ||
![]() |
70b6c9964c | ||
![]() |
b7f56a8019 | ||
![]() |
bbd37b7501 | ||
![]() |
00fd5e1abb | ||
![]() |
e2ad770d00 | ||
![]() |
c4f4ebc5ab | ||
![]() |
ae50fa4fee | ||
![]() |
5e54765874 | ||
![]() |
b72c9b3c1b | ||
![]() |
68a328d198 | ||
![]() |
c2ef73ab94 | ||
![]() |
add152ddb8 | ||
![]() |
593009d28f | ||
![]() |
dd2261ab6c | ||
![]() |
276025c248 | ||
![]() |
ae3a0ccd89 | ||
![]() |
83d7d5ddbe | ||
![]() |
fb0a9a8db4 | ||
![]() |
0f98327ed3 | ||
![]() |
4c86604f94 | ||
![]() |
3edb6517f8 | ||
![]() |
ca2a000a22 | ||
![]() |
bd0627548f | ||
![]() |
02656a7a70 | ||
![]() |
42f213fff5 | ||
![]() |
45be0d0218 | ||
![]() |
7657e4d7db | ||
![]() |
1aa4da2dd7 | ||
![]() |
d367f394a9 | ||
![]() |
fcc8caad9c | ||
![]() |
7e70fab3bd | ||
![]() |
b3a099e3ee | ||
![]() |
aae7cef399 | ||
![]() |
7f00cb821f | ||
![]() |
bb59ed1964 | ||
![]() |
4093ad22ec | ||
![]() |
3002753538 | ||
![]() |
3e67c30ca5 | ||
![]() |
f3f6f52c0e | ||
![]() |
1e334b447f | ||
![]() |
e224fa1ef2 | ||
![]() |
8dc9dd02e6 | ||
![]() |
7b400e8dd6 | ||
![]() |
a38ca01fb6 | ||
![]() |
04200c3465 | ||
![]() |
746f97a65c | ||
![]() |
ac54ee974b | ||
![]() |
6c53f8ff02 | ||
![]() |
311abd4cfc | ||
![]() |
9e76ea5f95 | ||
![]() |
9983810898 | ||
![]() |
327fe8f226 | ||
![]() |
c862545432 | ||
![]() |
4f35cb1366 | ||
![]() |
2dcf6a1a19 | ||
![]() |
51b8355b29 | ||
![]() |
0ddadb203a | ||
![]() |
0d3230092d | ||
![]() |
c9f73afe56 | ||
![]() |
00871e77de | ||
![]() |
ba7ff1a7a7 | ||
![]() |
696410ca8d | ||
![]() |
36ea763e1d | ||
![]() |
536beb0f1e | ||
![]() |
9cddfd237c | ||
![]() |
de33eb581d | ||
![]() |
4760af53ee | ||
![]() |
5143afcd54 | ||
![]() |
5d3fdb383d | ||
![]() |
bd7fa9a1fb | ||
![]() |
c361bcde92 | ||
![]() |
c233aa6715 | ||
![]() |
aef9693dac | ||
![]() |
d75d156ebc | ||
![]() |
43cc485237 | ||
![]() |
cece320b97 | ||
![]() |
4d60f6b8f7 | ||
![]() |
be12d598fd | ||
![]() |
5dc03cd1b8 | ||
![]() |
f2fdef17a2 | ||
![]() |
9a47639756 | ||
![]() |
a689c76798 | ||
![]() |
e57f14d42e | ||
![]() |
61c76cca39 | ||
![]() |
fd6fa7c56a | ||
![]() |
581d60d73a | ||
![]() |
47a60dcfbf | ||
![]() |
67a0a710e0 | ||
![]() |
7121e7929d | ||
![]() |
761e720501 | ||
![]() |
60f3340a9f | ||
![]() |
dfa6052123 | ||
![]() |
9b40aee50b | ||
![]() |
da17471fcb | ||
![]() |
fc3c2b3dbd | ||
![]() |
97bcc837a4 | ||
![]() |
31155ac867 | ||
![]() |
3c5ab93d18 | ||
![]() |
b235414950 | ||
![]() |
fb3b352957 | ||
![]() |
a78a174393 | ||
![]() |
fc4dd8fa3a | ||
![]() |
6a65dca9d5 | ||
![]() |
82756d9818 | ||
![]() |
2519aa8162 | ||
![]() |
b1fbb635cd | ||
![]() |
4c305c73f8 | ||
![]() |
ec415e2315 | ||
![]() |
69b536c338 | ||
![]() |
87d58c2f12 | ||
![]() |
223164c042 |
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal 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
23
AUTHORS
@ -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
492
ChangeLog
@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
60
Makefile.am
60
Makefile.am
@ -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
107
NEWS
@ -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
54
README
@ -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"
|
29
TODO
29
TODO
@ -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
|
||||
|
31
autogen.sh
31
autogen.sh
@ -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
9
build-aux/.gitignore
vendored
Normal 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
432
build-aux/gitlog-to-changelog
Executable 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:
|
@ -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 )
|
||||
])
|
||||
|
@ -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
137
configure.ac
Normal 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)
|
89
configure.in
89
configure.in
@ -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
11
data/Makefile.am
Normal 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
9
data/emu8051.conf
Normal 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
|
112
doc/emu8051.man
112
doc/emu8051.man
@ -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
0
m4/.gitignore
vendored
Normal file
644
src/CPU8051.cpp
644
src/CPU8051.cpp
@ -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"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
735
src/EmuGtk.cpp
735
src/EmuGtk.cpp
@ -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 );
|
||||
}
|
||||
}
|
111
src/EmuGtk.hpp
111
src/EmuGtk.hpp
@ -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
|
@ -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
|
266
src/Inst_Def.hpp
266
src/Inst_Def.hpp
@ -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
|
4208
src/Inst_Imp.cpp
4208
src/Inst_Imp.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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 $<
|
128
src/MemWin.cpp
128
src/MemWin.cpp
@ -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 ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
|
||||
|
186
src/PgmWin.cpp
186
src/PgmWin.cpp
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
@ -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
|
131
src/RegWin.cpp
131
src/RegWin.cpp
@ -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 ) );
|
||||
}
|
@ -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
36
src/cli/Makefile.am
Normal 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
72
src/cli/keyboard.c
Normal 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
25
src/cli/keyboard.h
Normal 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
50
src/cli/main.c
Normal 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
287
src/cli/menu.c
Normal 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
40
src/cli/menu.h
Normal 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
262
src/cli/parser.y
Normal 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
68
src/cli/scanner.l
Normal 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
48
src/common/Makefile.am
Normal 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
48
src/common/common.h
Normal 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
559
src/common/cpu8051.c
Normal 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
86
src/common/cpu8051.h
Normal 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
205
src/common/hexfile.c
Normal 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
25
src/common/hexfile.h
Normal 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
127
src/common/log.c
Normal 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
43
src/common/log.h
Normal 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
340
src/common/memory.c
Normal 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
107
src/common/memory.h
Normal 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
258
src/common/opcodes.lst
Normal 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
922
src/common/opcodes2c.pl
Executable 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
56
src/common/operations.c
Normal 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
15
src/common/operations.h
Normal 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
184
src/common/options.c
Normal 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
29
src/common/options.h
Normal 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
125
src/common/psw.c
Normal 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
57
src/common/psw.h
Normal 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
63
src/common/reg8051.h
Normal 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
357
src/common/sfr.c
Normal 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 ®win_infos[row];
|
||||
}
|
||||
|
||||
return NULL; /* Register not found. */
|
||||
}
|
||||
|
||||
struct regwin_infos_t *
|
||||
sfr_get_infos_from_row(int row)
|
||||
{
|
||||
return ®win_infos[row];
|
||||
}
|
||||
|
34
src/common/sfr.h
Normal file
34
src/common/sfr.h
Normal 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
166
src/common/timers.c
Normal 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
29
src/common/timers.h
Normal 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 */
|
211
src/disasm.hpp
211
src/disasm.hpp
@ -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
|
@ -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
38
src/gtk/Makefile.am
Normal 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
207
src/gtk/app-config.c
Normal 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
52
src/gtk/app-config.h
Normal 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
134
src/gtk/filemenu.c
Normal 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
18
src/gtk/filemenu.h
Normal 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
94
src/gtk/helpmenu.c
Normal 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
18
src/gtk/helpmenu.h
Normal 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
666
src/gtk/main.c
Normal 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
42
src/gtk/main.h
Normal 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
384
src/gtk/memwin.c
Normal 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
21
src/gtk/memwin.h
Normal 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
47
src/gtk/messagebox.c
Normal 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
21
src/gtk/messagebox.h
Normal 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
293
src/gtk/pgmwin.c
Normal 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
21
src/gtk/pgmwin.h
Normal 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
241
src/gtk/pswwin.c
Normal 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
21
src/gtk/pswwin.h
Normal 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
235
src/gtk/regwin.c
Normal 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
21
src/gtk/regwin.h
Normal 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
112
src/gtk/timerwin.c
Normal 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
21
src/gtk/timerwin.h
Normal 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
189
src/gtk/viewmenu.c
Normal 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
18
src/gtk/viewmenu.h
Normal 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 */
|
258
src/opcodes.lst
258
src/opcodes.lst
@ -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
|
@ -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
|
@ -1,13 +0,0 @@
|
||||
:03000000020033C8
|
||||
:1000330075818075D54475A000C290E4F500E50094
|
||||
:1000430012007DF586D29005A07400D5E0FDC29024
|
||||
:10005300E5AA53E08060F9E5861200690500C3E56F
|
||||
:1000630000945040D92222752005740075F000D504
|
||||
:10007300F0FDD5E0F7D520F20022248BF582740041
|
||||
:100083003400F5837400932252504D3A31303234A8
|
||||
:1000930035204D41503A313033204D41543A3131BE
|
||||
:1000A30030204241543A31322E3420202020202067
|
||||
:1000B3000D0A0A45474F3A31342E36202054505307
|
||||
:1000C3003A31303020414E473A33302020434C54AC
|
||||
:0B00D3003A313038202020202020206F
|
||||
:00000001FF
|
@ -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
Loading…
x
Reference in New Issue
Block a user