Permalink
Browse files

This is the first revision at svn.berlios.de for Salent

git-svn-id: http://svn.berlios.de/svnroot/repos/salent@1 61cb175c-0704-0410-9cb5-98685d7901e0
  • Loading branch information...
0 parents commit b13d3b3136c60716d9ce40e9e087f350fb82f6fd agent committed Oct 28, 2005
Showing with 228,302 additions and 0 deletions.
  1. +187 −0 Config.ast
  2. +67 −0 Config.ast.tt
  3. +32 −0 alu/Changes
  4. +14 −0 alu/Makefile.PL
  5. +161 −0 alu/Makefile.tt
  6. +126 −0 alu/alu.c.tt
  7. +142 −0 alu/alu.do.tt
  8. +163 −0 alu/alu.t.tt
  9. +136 −0 alu/alu.v.tt
  10. +63 −0 alu/ast++.pl
  11. +39 −0 alu/opc.tt
  12. +58 −0 alu/talu1.op.tt
  13. +67 −0 alu/talu2.op.tt
  14. +67 −0 alu/talu3.op.tt
  15. +61 −0 alu/talu4.op.tt
  16. +63 −0 alu/talu5.op.tt
  17. +58 −0 alu/talu6.pl
  18. +3 −0 alu/work/_info
  19. +5 −0 build.bat
  20. +20 −0 clean.bat
  21. +14 −0 exclude
  22. +4 −0 idu/.smoker.yml
  23. +130 −0 idu/C/Idu.pm
  24. +686 −0 idu/C/idu.c.tt
  25. +18 −0 idu/C/idu.def
  26. +66 −0 idu/C/idu.h
  27. +95 −0 idu/C/idui.c
  28. +471 −0 idu/Changes
  29. +467 −0 idu/Makefile
  30. +14 −0 idu/_Inline/config
  31. 0 idu/_Inline/lib/auto/Idu_012a/Idu_012a.bs
  32. BIN idu/_Inline/lib/auto/Idu_012a/Idu_012a.dll
  33. BIN idu/_Inline/lib/auto/Idu_012a/Idu_012a.exp
  34. +22 −0 idu/_Inline/lib/auto/Idu_012a/Idu_012a.inl
  35. BIN idu/_Inline/lib/auto/Idu_012a/Idu_012a.lib
  36. BIN idu/_Inline/lib/auto/Idu_012a/Idu_012a.pdb
  37. BIN idu/add.png
  38. +25 −0 idu/add.xml
  39. +50 −0 idu/asm2ast.pl
  40. +239 −0 idu/asm_tpl2.ast.tt
  41. +23 −0 idu/ast2hex.pl
  42. +25 −0 idu/ast_doc.tt
  43. +37 −0 idu/bin2asm.pl
  44. +61 −0 idu/bin2hex.c
  45. +186 −0 idu/bstree.h
  46. +14 −0 idu/catln.pl
  47. +68 −0 idu/cod2ast.pl
  48. BIN idu/cover_db/runs/1129987950.2460.51454/cover.12
  49. BIN idu/cover_db/structure/68e995d44cd0b8756eb4b3a966418b01
  50. BIN idu/cover_db/structure/bd973c2a13cd462345f76c1d96258aba
  51. BIN idu/cover_db/structure/f4a90eb53a06b1e447707cbf48899912
  52. +3 −0 idu/debug.bat
  53. +1 −0 idu/debug2.bat
  54. +761 −0 idu/docstyle.css
  55. +90 −0 idu/draw_graph.pl
  56. +819 −0 idu/eee
  57. +95 −0 idu/encoding.pod.tt
  58. +627 −0 idu/encoding.txt
  59. +42 −0 idu/exe2hex.pl
  60. +9 −0 idu/filter.pl
  61. +118 −0 idu/gen_asm_tpl.pl
  62. +63 −0 idu/hex2bin.c
  63. +599 −0 idu/idu.c
  64. +37 −0 idu/idu.pl
  65. +397 −0 idu/idu.v.tt
  66. +43 −0 idu/idui.pl
  67. +383 −0 idu/inc/Disasm.pm.tt
  68. +8,616 −0 idu/inc/Idu.pm
  69. +316 −0 idu/inc/Idu.pm.tt
  70. +87 −0 idu/inc/Idu/Util.pm
  71. +76 −0 idu/inc/Ndisasm.pm
  72. +133 −0 idu/inc/pat_tree.pm
  73. +110 −0 idu/inc/state_mac.pm
  74. +52 −0 idu/main.c
  75. BIN idu/my_perl.exe
  76. +40 −0 idu/ndisasmi.pl
  77. +40 −0 idu/new_encoding_ast.pl
  78. +110,111 −0 idu/no_todo_smoke.html
  79. +27 −0 idu/ops.pl
  80. 0 idu/optest.ast
  81. +175 −0 idu/optest.tt.tt
  82. +68 −0 idu/parse_enc.pl
  83. +218 −0 idu/pat_cover.pl
  84. +647 −0 idu/pat_tree.out
  85. +43 −0 idu/pat_tree.pl
  86. +56 −0 idu/pe2ast.pl
  87. +15,102 −0 idu/smoke.html
  88. +32 −0 idu/state_mac.pl
  89. BIN idu/state_mac.png
  90. +56 −0 idu/state_mac.xml.tt
  91. +175 −0 idu/t/01disasm.t
  92. +182 −0 idu/t/01disasm.t.html
  93. +288 −0 idu/t/02disasm.t
  94. +295 −0 idu/t/02disasm.t.html
  95. +97 −0 idu/t/03disasm.t
  96. +103 −0 idu/t/03disasm.t.html
  97. +483 −0 idu/t/Disasm.t.html
  98. +74 −0 idu/t/Idu-Util.t
  99. +81 −0 idu/t/Idu-Util.t.html
  100. +32 −0 idu/t/Idu.t
  101. +39 −0 idu/t/Idu.t.html
  102. +39 −0 idu/t/Makefile
  103. BIN idu/t/bin2asm.bin
  104. +18 −0 idu/t/bin2asm.t
  105. +25 −0 idu/t/bin2asm.t.html
  106. +1 −0 idu/t/bin2hex.bin
  107. +33,015 −0 idu/t/bin2hex.exe.ast.html
  108. +152 −0 idu/t/bin2hex.exe.t.html
  109. +31 −0 idu/t/bin2hex.t
  110. +38 −0 idu/t/bin2hex.t.html
  111. +13 −0 idu/t/catln.dat
  112. +14 −0 idu/t/catln.t
  113. +21 −0 idu/t/catln.t.html
  114. +237 −0 idu/t/cidu.t
  115. +244 −0 idu/t/cidu.t.html
  116. +36 −0 idu/t/disasm_cover.t
  117. +43 −0 idu/t/disasm_cover.t.html
  118. +60 −0 idu/t/encoding.ast.html
  119. +9 −0 idu/t/encoding.txt
  120. +67 −0 idu/t/encoding2.ast
  121. +475 −0 idu/t/error.t.tt
  122. +926 −0 idu/t/exe2hex.hex
  123. +15 −0 idu/t/exe2hex.t
  124. +22 −0 idu/t/exe2hex.t.html
  125. +37,044 −0 idu/t/hex2bin.exe.ast.html
  126. +152 −0 idu/t/hex2bin.exe.t.html
  127. +30 −0 idu/t/hex2bin.t
  128. +37 −0 idu/t/hex2bin.t.html
  129. +666 −0 idu/t/idu.v
  130. +2,108 −0 idu/t/main.cod.ast.html
  131. +152 −0 idu/t/main.cod.t.html
  132. +427 −0 idu/t/my_perl.exe.ast.html
  133. +152 −0 idu/t/my_perl.exe.t.html
  134. +355 −0 idu/t/ndisasm.t
  135. +362 −0 idu/t/ndisasm.t.html
  136. +11 −0 idu/t/ndisasmi.in
  137. +13 −0 idu/t/ndisasmi.out
  138. +23 −0 idu/t/ndisasmi.t
  139. +30 −0 idu/t/ndisasmi.t.html
  140. +231 −0 idu/t/operand.t.tt
  141. +64 −0 idu/t/opname.t.tt
  142. +81 −0 idu/t/optest.ast.html
  143. +78 −0 idu/t/optest.ast.tt
  144. +152 −0 idu/t/optest.t.html
  145. +2,979 −0 idu/t/pat_cover.ast.ast.html
  146. +37 −0 idu/t/pat_cover.t.html
  147. +39 −0 idu/t/pat_cover.t.tt
  148. +161 −0 idu/t/pat_tree.ast.html
  149. +375 −0 idu/t/pat_tree.t
  150. +382 −0 idu/t/pat_tree.t.html
  151. +216 −0 idu/t/state_mac.ast.html
  152. BIN idu/t/state_mac.png
  153. +58 −0 idu/t/state_mac.t
  154. +64 −0 idu/t/state_mac.t.html
  155. +74 −0 idu/t/state_mac.xml
  156. BIN idu/t/test
  157. +33 −0 idu/t/test.asm
  158. +1 −0 idu/t/test.bin
  159. BIN idu/t/test.exe
  160. +1 −0 idu/t/test.hex
  161. +25 −0 idu/tiny/Makefile
Sorry, we could not display the entire diff because it was too big.
187 Config.ast
@@ -0,0 +1,187 @@
+$VAR1 = {
+ 'idu' => {
+ 'bit_fields' => [
+ 's',
+ 'w',
+ 'd',
+ 'R'
+ ],
+ 'prefixes' => [
+ 'f2',
+ 'f3',
+ 'f0',
+ '67',
+ '66',
+ '2e',
+ '36',
+ '3e',
+ '26',
+ '64',
+ '65'
+ ],
+ 'reg_fields' => [
+ 'reg',
+ 'reg1',
+ 'reg2',
+ 'sreg2',
+ 'sreg3',
+ 'eee',
+ 'tttn',
+ 'ST_i'
+ ]
+ },
+ 'word_size' => 32,
+ 'version' => '0.13',
+ 'fld_map' => {
+ 'sreg3' => [
+ 'ES',
+ 'CS',
+ 'SS',
+ 'DS',
+ 'FS',
+ 'GS',
+ 'segr6',
+ 'segr7'
+ ],
+ 'eee' => {
+ 'DR' => [
+ 'DR0',
+ 'DR1',
+ 'DR2',
+ 'DR3',
+ 'DR4',
+ 'DR5',
+ 'DR6',
+ 'DR7'
+ ],
+ 'CR' => [
+ 'CR0',
+ 'CR1',
+ 'CR2',
+ 'CR3',
+ 'CR4',
+ 'CR5',
+ 'CR6',
+ 'CR7'
+ ]
+ },
+ 'reg16' => {
+ 'none' => [
+ 'AX',
+ 'CX',
+ 'DX',
+ 'BX',
+ 'SP',
+ 'BP',
+ 'SI',
+ 'DI'
+ ],
+ 'w0' => [
+ 'AL',
+ 'CL',
+ 'DL',
+ 'BL',
+ 'AH',
+ 'CH',
+ 'DH',
+ 'BH'
+ ],
+ 'w1' => [
+ 'AX',
+ 'CX',
+ 'DX',
+ 'BX',
+ 'SP',
+ 'BP',
+ 'SI',
+ 'DI'
+ ]
+ },
+ 'sreg2' => [
+ 'ES',
+ 'CS',
+ 'SS',
+ 'DS'
+ ],
+ 'reg32' => {
+ 'none' => [
+ 'EAX',
+ 'ECX',
+ 'EDX',
+ 'EBX',
+ 'ESP',
+ 'EBP',
+ 'ESI',
+ 'EDI'
+ ],
+ 'w0' => [
+ 'AL',
+ 'CL',
+ 'DL',
+ 'BL',
+ 'AH',
+ 'CH',
+ 'DH',
+ 'BH'
+ ],
+ 'w1' => [
+ 'EAX',
+ 'ECX',
+ 'EDX',
+ 'EBX',
+ 'ESP',
+ 'EBP',
+ 'ESI',
+ 'EDI'
+ ]
+ },
+ 'tttn' => [
+ 'O',
+ 'NO',
+ 'C',
+ 'NC',
+ 'Z',
+ 'NZ',
+ 'NA',
+ 'A',
+ 'S',
+ 'NS',
+ 'PE',
+ 'PO',
+ 'L',
+ 'NL',
+ 'NG',
+ 'G'
+ ]
+ },
+ 'addr_size' => 32,
+ 'ram' => {
+ 'delay' => 10,
+ 'capacity' => 256
+ },
+ 'alu' => {
+ 'sels' => [
+ 'NOP',
+ 'ADD',
+ 'SUB',
+ 'MUL',
+ 'IMUL',
+ 'DIV',
+ 'IDIV',
+ 'AND',
+ 'OR',
+ 'XOR',
+ 'NOT',
+ 'NEG',
+ 'SHL',
+ 'SHR',
+ 'SAL',
+ 'SAR',
+ 'ROL',
+ 'ROR',
+ 'RCL',
+ 'RCR'
+ ],
+ 'delay' => 1
+ }
+ };
67 Config.ast.tt
@@ -0,0 +1,67 @@
+[% SET
+ ast = {
+ version = '0.13'
+ word_size = 32
+ addr_size = 32
+ alu = {
+ sels =
+ [
+ 'NOP',
+ 'ADD', 'SUB', 'MUL', 'IMUL', 'DIV', 'IDIV',
+ 'AND', 'OR', 'XOR', 'NOT', 'NEG',
+ 'SHL', 'SHR', 'SAL', 'SAR',
+ 'ROL', 'ROR', 'RCL', 'RCR',
+ ]
+ delay = 1
+ }
+ ram = {
+ capacity = 64 * 1024 # in words, not in bytes
+ delay = 10
+ }
+ idu = {
+ reg_fields = [
+ 'reg', 'reg1', 'reg2',
+ 'sreg2', 'sreg3',
+ 'eee', 'tttn', 'ST_i',
+ ]
+ bit_fields = [ 's', 'w', 'd', 'R' ]
+ prefixes = [
+ 'f2', 'f3', # REP & REPE
+ 'f0', # LOCK
+
+ '67', # address size
+ '66', # operand size
+
+ '2e', # CS segment override
+ '36', # SS segment override
+ '3e', # DS segment override
+ '26', # ES segment override
+ '64', # FS segment override
+ '65', # GS segment override
+ ]
+ }
+ fld_map = {
+ reg32 =
+ {
+ w0 = ['AL' 'CL' 'DL' 'BL' 'AH' 'CH' 'DH' 'BH'],
+ w1 = ['EAX' 'ECX' 'EDX' 'EBX' 'ESP' 'EBP' 'ESI' 'EDI'],
+ none = ['EAX' 'ECX' 'EDX' 'EBX' 'ESP' 'EBP' 'ESI' 'EDI']
+ },
+ reg16 =
+ {
+ w0 = ['AL' 'CL' 'DL' 'BL' 'AH' 'CH' 'DH' 'BH'],
+ w1 = ['AX' 'CX' 'DX' 'BX' 'SP' 'BP' 'SI' 'DI'],
+ none = ['AX' 'CX' 'DX' 'BX' 'SP' 'BP' 'SI' 'DI']
+ },
+ sreg2 = ['ES' 'CS' 'SS' 'DS'],
+ sreg3 = ['ES' 'CS' 'SS' 'DS' 'FS' 'GS' 'segr6' 'segr7'],
+ eee = {
+ CR = ['CR0' 'CR1' 'CR2' 'CR3' 'CR4' 'CR5' 'CR6' 'CR7'],
+ DR = ['DR0' 'DR1' 'DR2' 'DR3' 'DR4' 'DR5' 'DR6' 'DR7']
+ }
+ tttn = ['O' 'NO' 'C' 'NC' 'Z' 'NZ' 'NA' 'A' 'S' 'NS' 'PE' 'PO' 'L' 'NL' 'NG' 'G'],
+ }
+ }
+-%]
+[% USE dumper;
+ dumper.dump(ast) -%]
32 alu/Changes
@@ -0,0 +1,32 @@
+v0.13 - 2005-08-26
+
+* Removed vsim_svr.wsc and t\vsim_svr.t.
+
+
+v0.12 - 2005-08-25
+
+* Add vsim_svr.wsc and t/vsim_svr.t to the alu repository.
+* Obviously Windows Script Component is DLL COM Server, not EXE COM Server like MS Word. Hence this
+ approach can be used to eliminate frequent restarting behaviou of vsim.exe. Sigh.
+* I think I have to use Active Template Library (ATL) to build an EXE COM server using C++ myself.
+
+
+v0.09 - 2005-08-11
+
+* Makefile-ize the alu repository and also use cutomized Makefile.PL to generate Makefile
+
+
+v0.08
+
+* Do not set cin in AST when op is div or mul. The tester will broke even if you set c_in all to 0.
+* Ignore the cin and cout completely when div, idiv, mul, and imul are performed.
+* cout is always 0 when logic and, or, and xor are performed. cin will be ignored by ALU for these operations.
+* When generate test cases randomly, be ware of the "divide by zero" exception and "integer over flow exception". The MASM code will crash if a software exception occurred.
+* Don't change word_size to values other than 32. The MASM code impose this limit to us.
+* clean.bat is very handy indeed.
+* It should be noted that NOT has no affect on cout. Unforturnately, there is no easy way to test this behaviour. We can't specify cin when we test NOT in .op file.
+* It is interesting to test
+ rcr 0xe49e0000, 0x11 (CF = 1)
+ and
+ rcr 0x28820000, 0x00 (CF = 1)
+* I wrote talu6.pl to generate the AST directly, without boring to use the cumbersome opc.tt mechanism. I got the test process 5 sec faster in the case of talu1.
14 alu/Makefile.PL
@@ -0,0 +1,14 @@
+#: Makefile.PL
+#: Generate the Makefile via TT2 template
+#: Salent v0.13
+#: Copyright (c) 2005 Agent Zhang
+#: 2005-08-11 2005-08-25
+
+use strict;
+use warnings;
+
+use Template;
+
+my $tpl = Template->new;
+$tpl->process('Makefile.tt', undef, 'Makefile') or
+ die Template->error();
161 alu/Makefile.tt
@@ -0,0 +1,161 @@
+GLOB_AST = ..\Config.ast
+VLOG_TT = alu.v.tt
+PERL_TT = alu.t.tt
+C_TT = alu.c.tt
+DO_TT = alu.do.tt
+VLOG_ALU = ..\alu.v
+RM_F = perl -MExtUtils::Command -e rm_f
+RM_RF = perl -MExtUtils::Command -e rm_rf
+
+# --------------------------------------------------------
+# nmake
+# --------------------------------------------------------
+
+all : $(VLOG_ALU)
+
+$(VLOG_ALU) : $(VLOG_TT) $(GLOB_AST)
+ astt -o $@ -t $(VLOG_TT) $(GLOB_AST)
+
+# --------------------------------------------------------
+# nmake test
+# --------------------------------------------------------
+
+test : all tester run_test
+
+[%- id_list = [1,2,3,4,5] %]
+tester : alu_t[%- FOREACH id IN id_list %] talu[% id %]_t[%- END %] talu6_t
+
+# Test the templates separately:
+
+alu_t : t\alu.t alu.exe.out alu.lst
+
+t\alu.t : $(PERL_TT)
+ tpage $(PERL_TT) > $@
+
+alu.exe.out : alu.exe
+ alu.exe > $@
+
+alu.exe : alu.c
+ cl /nologo alu.c
+
+alu.c : $(C_TT)
+ tpage $(C_TT) > $@
+
+alu.v : $(VLOG_TT)
+ tpage $(VLOG_TT) > $@
+
+alu.do : $(DO_TT)
+ tpage $(DO_TT) > $@
+
+alu.lst : alu.do alu.v
+ vsim -c -quiet -do alu.do
+
+##
+[%- FOREACH id IN id_list %]
+
+# Use TT to generate .op file
+
+BASE = talu[% id %]
+
+OP_FILE = $(BASE).op
+OP_FILE_TT = $(OP_FILE).tt
+AST_FILE = $(OP_FILE).ast
+EXE_FILE = $(OP_FILE).exe
+EXE_OUT = $(EXE_FILE).out
+C_FILE = $(OP_FILE).c
+VLOG_FILE = $(OP_FILE).v
+LST_FILE = $(OP_FILE).lst
+DO_FILE = $(OP_FILE).do
+T_FILE = t\$(OP_FILE).t
+
+$(BASE)_t : $(T_FILE) $(EXE_OUT) $(LST_FILE)
+
+$(T_FILE) : $(AST_FILE) $(GLOB_AST) $(PERL_TT)
+ astt -o $@ -t $(PERL_TT) $(GLOB_AST) $(AST_FILE)
+
+$(AST_FILE) : ast++.pl $(OP_FILE) opc.tt
+ tpage --define op_file=$(OP_FILE) opc.tt > $@
+ perl ast++.pl $@
+
+$(OP_FILE) : $(OP_FILE_TT)
+ tpage $(OP_FILE_TT) > $@
+
+$(EXE_OUT) : $(EXE_FILE)
+ $(EXE_FILE) > $@
+
+$(EXE_FILE) : $(C_FILE)
+ cl /EHs /nologo $(C_FILE)
+
+$(C_FILE) : $(C_TT) $(GLOB_AST) $(AST_FILE)
+ astt -o $@ -t $(C_TT) $(GLOB_AST) $(AST_FILE)
+
+$(LST_FILE) : $(DO_FILE) $(VLOG_FILE)
+ vsim -c -quiet -do $(DO_FILE)
+
+$(VLOG_FILE) : $(VLOG_TT) $(GLOB_AST) $(AST_FILE)
+ astt -o $@ -t $(VLOG_TT) $(GLOB_AST) $(AST_FILE)
+
+$(DO_FILE) : $(DO_TT) $(GLOB_AST) $(AST_FILE)
+ astt -o $@ -t $(DO_TT) $(GLOB_AST) $(AST_FILE)
+
+##
+[%- END %]
+
+# Use perl script to generate .ast file directly:
+
+BASE = talu6
+
+OP_FILE = $(BASE).op
+PERL_FILE = $(BASE).pl
+AST_FILE = $(OP_FILE).ast
+EXE_FILE = $(OP_FILE).exe
+EXE_OUT = $(EXE_FILE).out
+C_FILE = $(OP_FILE).c
+VLOG_FILE = $(OP_FILE).v
+LST_FILE = $(OP_FILE).lst
+DO_FILE = $(OP_FILE).do
+T_FILE = t\$(OP_FILE).t
+
+$(BASE)_t : $(T_FILE) $(EXE_OUT) $(LST_FILE)
+
+$(T_FILE) : $(AST_FILE) $(GLOB_AST) $(PERL_TT)
+ astt -o $@ -t $(PERL_TT) $(GLOB_AST) $(AST_FILE)
+
+$(AST_FILE) : ast++.pl $(PERL_FILE)
+ perl $(PERL_FILE)
+ perl ast++.pl $@
+
+$(EXE_OUT) : $(EXE_FILE)
+ $(EXE_FILE) > $@
+
+$(EXE_FILE) : $(C_FILE)
+ cl /EHs /nologo $(C_FILE)
+
+$(C_FILE) : $(C_TT) $(GLOB_AST) $(AST_FILE)
+ astt -o $@ -t $(C_TT) $(GLOB_AST) $(AST_FILE)
+
+$(LST_FILE) : $(DO_FILE) $(VLOG_FILE)
+ vsim -c -quiet -do $(DO_FILE)
+
+$(VLOG_FILE) : $(VLOG_TT) $(GLOB_AST) $(AST_FILE)
+ astt -o $@ -t $(VLOG_TT) $(GLOB_AST) $(AST_FILE)
+
+$(DO_FILE) : $(DO_TT) $(GLOB_AST) $(AST_FILE)
+ astt -o $@ -t $(DO_TT) $(GLOB_AST) $(AST_FILE)
+
+##
+
+run_test :
+ set HARNESS_OK_SLOW = 1
+ perl -MExtUtils::Command::MM \
+ -e "@ARGV = map glob, @ARGV; test_harness(0, '.', '.');" t\*.t
+
+clean :
+ $(RM_F) $(VLOG_ALU) \
+ vsim.wlf transcript \
+ alu.v alu.do alu.lst alu.c alu.obj alu.exe alu.exe.out alu.pl \
+ *.op.v *.op.pl *.op.do *.op.c *.op.obj *.op.exe* *.op.lst *.op.ast \
+ talu1.op talu2.op talu3.op talu4.op talu5.op \
+ t/talu*.t t/alu.t Makefile *tmp* t/result.lst
+ $(RM_RF) work
+ vlib work
126 alu/alu.c.tt
@@ -0,0 +1,126 @@
+[% USE date -%]
+[% DEFAULT
+ version = '0.13'
+ c_file = 'alu.c'
+ ops = [ # operands must all be in hex form
+ { op = 'mul', A = '20', B = 0 }
+ { op = 'imul', A = 'fffffffd', B = 2 }
+ { op = 'mul', A = 'fffffffd', B = 2 }
+ { op = 'div', A = 6, B = 'fffffffe', D = 0 }
+ { op = 'idiv', A = 6, B = 'fffffffe' }
+ { op = 'nop' }
+ { op = 'add', A = 5, B = 6 }
+ { op = 'add', A = 5, B = 6, cin = 1 }
+ { op = 'add', A = 5, B = 6, cin = 0 }
+ { op = 'sub', A = 'fffffffd', B = 9 }
+ { op = 'sub', A = 'fffffffd', B = 9, cin = 1 }
+ { op = 'sub', A = 'd', B = 9, cin = 1 }
+ { op = 'sub', A = 'fffffffd', B = 9, cin = 0 }
+ { op = 'nop' }
+ { op = 'xor', A = 'fffffffe', B = 3 }
+ { op = 'and', A = 'fffffffe', B = 'fffffffd' }
+ { op = 'or', A = 'fffffffe', B = 3 }
+ { op = 'neg', A = 5 }
+ { op = 'not', A = 'b' }
+ { op = 'nop' }
+ { op = 'shl', A = 'fffffffe', B = 2 }
+ { op = 'shr', A = 'fffffffe', B = 2 }
+ { op = 'sal', A = 'fffffffe', B = 2 }
+ { op = 'sar', A = 'fffffffe', B = 2 }
+ { op = 'rol', A = 'fffffffe', B = 2, cin = 0 }
+ { op = 'ror', A = 'fffffffe', B = 2, cin = 1 }
+ { op = 'rcl', A = 'fffffffe', B = 2, cin = 1 }
+ { op = 'rcr', A = 'fffffffe', B = 2, cin = 0 }
+ ]
+-%]
+[% SET
+ last_mod = date.format(template.modtime, '20%y-%m-%d', 'en_GB')
+ year = date.format(template.modtime, '20%y', 'en_GB')
+-%]
+//: [% c_file %]
+//: Reference implementation of ALU using MASM
+//: This file was generated from alu.c.tt
+//: Salent v[% version %]
+//: Copyright (c) [% year %] Agent Zhang.
+//: 2005-07-08 [% last_mod %]
+
+#include <stdio.h>
+
+void printbin(unsigned char c) {
+ int i = sizeof(c) * 8;
+ while (i > 0)
+ printf("%d", ((1<<--i)&c) != 0);
+}
+
+int main() {
+ int a, d;
+ unsigned char flags;
+
+ printf("SF:ZF:0:AF:0:PF:1:CF eax edx\n");
+[%- FOREACH ops %]
+ __asm {
+ [%- IF cin == 1 %]
+ stc
+ [%- ELSIF cin == 0 %]
+ clc
+ [%- END -%]
+
+ [%- IF cin.defined;
+ SET op = 'adc' IF op == 'add';
+ SET op = 'sbb' IF op == 'sub';
+ END -%]
+
+ [%- IF op == 'mul' OR op == 'imul' %]
+ mov eax, 0x[% A %]
+ mov ebx, 0x[% B %]
+ [% op %] ebx
+ mov a, eax
+ mov d, edx
+ lahf
+ mov flags, ah
+ }
+ printbin(flags);
+ printf(" %x %x\n", a, d);
+ [%- ELSIF op == 'div' OR op == 'idiv' %]
+ mov eax, 0x[% A %]
+ [%- IF D.defined %]
+ mov edx, 0x[% D %]
+ [%- ELSIF op == 'idiv' %]
+ cdq
+ [%- ELSE %]
+ mov edx, 0
+ [%- END %]
+ mov ebx, 0x[% B %]
+ [% op %] ebx
+ mov a, eax
+ mov d, edx
+ lahf
+ mov flags, ah
+ }
+ printbin(flags);
+ printf(" %x %x\n", a, d);
+ [%- ELSIF op == 'not' OR op == 'neg' %]
+ mov eax, 0x[% A %]
+ [% op %] eax
+ mov a, eax
+ lahf
+ mov flags, ah
+ }
+ printbin(flags);
+ printf(" %x\n", a);
+ [%- ELSIF op == 'nop' %]
+ }
+ printf("\n");
+ [%- ELSE # add sub and or xor shl shr rol ror sal sar %]
+ mov eax, 0x[% A %]
+ [% op %] eax, 0x[% B %]
+ mov a, eax
+ lahf
+ mov flags, ah
+ }
+ printbin(flags);
+ printf(" %x\n", a);
+ [%- END %]
+[% END %]
+ return 0;
+}
142 alu/alu.do.tt
@@ -0,0 +1,142 @@
+[% DEFAULT
+ list_file = 'alu.lst'
+ vlog_file = 'alu.v'
+ alu = {
+ sels =
+ [
+ 'NOP',
+ 'ADD', 'SUB', 'MUL', 'IMUL', 'DIV', 'IDIV',
+ 'AND', 'OR', 'XOR', 'NOT', 'NEG',
+ 'SHL', 'SHR', 'SAL', 'SAR',
+ 'ROL', 'ROR', 'RCL', 'RCR',
+ ]
+ }
+ ops = [ # operands must all be in hex form
+ { op = 'mul', A = '20', B = 0,
+ op_time = 0, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'imul', A = 'fffffffd', B = 2,
+ op_time = 0, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'mul', A = 'fffffffd', B = 2,
+ op_time = 1, A_time = 2, B_time = 1,
+ run_time = 4 }
+ { op = 'div', A = 6, B = 'fffffffe', D = 0,
+ op_time = 1, A_time = 0, B_time = 1, D_time = 1,
+ run_time = 4 }
+ { op = 'idiv', A = 6, B = 'fffffffe',
+ op_time = 0, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'nop', op_time = 1, run_time = 4 }
+ { op = 'add', A = 5, B = 6,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'add', A = 5, B = 6, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'add', A = 5, B = 6, cin = 0,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'sub', A = 'fffffffd', B = 9,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'sub', A = 'fffffffd', B = 9, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'sub', A = 'd', B = 9, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'sub', A = 'fffffffd', B = 9, cin = 0,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'nop', op_time = 1, run_time = 4 }
+ { op = 'xor', A = 'fffffffe', B = 3,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'and', A = 'fffffffe', B = 'fffffffd',
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'or', A = 'fffffffe', B = 3,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'neg', A = 5,
+ op_time = 1, A_time = 0,
+ run_time = 4 }
+ { op = 'not', A = 'b',
+ op_time = 1, A_time = 0,
+ run_time = 4 }
+ { op = 'nop', op_time = 1, run_time = 4 }
+ { op = 'shl', A = 'fffffffe', B = 2,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'shr', A = 'fffffffe', B = 2,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'sal', A = 'fffffffe', B = 2,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'sar', A = 'fffffffe', B = 2,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'rol', A = 'fffffffe', B = 2, cin = 0,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 1,
+ run_time = 4 }
+ { op = 'ror', A = 'fffffffe', B = 2, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'rcl', A = 'fffffffe', B = 2, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'rcr', A = 'fffffffe', B = 2, cin = 0,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ ]
+-%]
+[% USE Perl -%]
+[% sel_map = {};
+ i = 0;
+ FOREACH sel IN alu.sels;
+ sel = Perl.lc(sel);
+ sel_map.$sel = i;
+ i = i + 1;
+ END -%]
+vlog -nologo -quiet -incr [% vlog_file %]
+vsim -quiet work.alu
+add wave -hex data1 data2 data3 cin sel cout res1 res2
+add list -nodelta -hex cout res1 res2
+
+force data1 'bz
+force data2 'bz
+force data3 'bz
+force cin 0
+
+[% FOREACH ops -%]
+ [%- IF A.defined -%]
+force data1 16#[% A %] [% A_time %]
+
+ [%- END -%]
+
+ [%- IF B.defined -%]
+force data2 16#[% B %] [% B_time %]
+
+ [%- END -%]
+
+ [%- IF D.defined -%]
+force data3 16#[% D %] [% D_time %]
+
+ [%- END -%]
+
+ [%- IF cin.defined -%]
+force cin 1'b[% cin %] [% cin_time %]
+
+ [%- ELSE -%]
+force cin 1'b0
+
+ [%- END -%]
+# [% op %]:
+force sel 10#[% sel_map.$op %] [% op_time %]
+run [% run_time %]
+
+[% END -%]
+write list -event [% list_file %]
+quit
163 alu/alu.t.tt
@@ -0,0 +1,163 @@
+[% DEFAULT
+ version = '0.13'
+ list_file = 'alu.lst'
+ perl_file = 'alu.t'
+ solu_file = 'alu.exe.out'
+ ops = [ # operands must all be in hex form
+ { op = 'mul', A = '20', B = 0,
+ op_time = 0, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'imul', A = 'fffffffd', B = 2,
+ op_time = 0, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'mul', A = 'fffffffd', B = 2,
+ op_time = 1, A_time = 2, B_time = 1,
+ run_time = 4 }
+ { op = 'div', A = 6, B = 'fffffffe', D = 0,
+ op_time = 1, A_time = 0, B_time = 1, D_time = 1,
+ run_time = 4 }
+ { op = 'idiv', A = 6, B = 'fffffffe',
+ op_time = 0, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'nop', op_time = 1, run_time = 4 }
+ { op = 'add', A = 5, B = 6,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'add', A = 5, B = 6, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'add', A = 5, B = 6, cin = 0,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'sub', A = 'fffffffd', B = 9,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'sub', A = 'fffffffd', B = 9, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'sub', A = 'd', B = 9, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'sub', A = 'fffffffd', B = 9, cin = 0,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'nop', op_time = 1, run_time = 4 }
+ { op = 'xor', A = 'fffffffe', B = 3,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'and', A = 'fffffffe', B = 'fffffffd',
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'or', A = 'fffffffe', B = 3,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'neg', A = 5,
+ op_time = 1, A_time = 0,
+ run_time = 4 }
+ { op = 'not', A = 'b',
+ op_time = 1, A_time = 0,
+ run_time = 4 }
+ { op = 'nop', op_time = 1, run_time = 4 }
+ { op = 'shl', A = 'fffffffe', B = 2,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'shr', A = 'fffffffe', B = 2,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'sal', A = 'fffffffe', B = 2,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'sar', A = 'fffffffe', B = 2,
+ op_time = 2, A_time = 0, B_time = 1,
+ run_time = 4 }
+ { op = 'rol', A = 'fffffffe', B = 2, cin = 0,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 1,
+ run_time = 4 }
+ { op = 'ror', A = 'fffffffe', B = 2, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'rcl', A = 'fffffffe', B = 2, cin = 1,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ { op = 'rcr', A = 'fffffffe', B = 2, cin = 0,
+ op_time = 2, A_time = 0, B_time = 1, cin_time = 2,
+ run_time = 4 }
+ ]
+-%]
+[% USE date;
+ USE Perl -%]
+[% SET
+ last_mod = date.format(template.modtime, '20%y-%m-%d', 'en_GB')
+ year = date.format(template.modtime, '20%y', 'en_GB')
+-%]
+#: [% perl_file %]
+#: Working with alu.do.tt to check in simulation list
+#: outputs of alu.v
+#: This file was generated according to alu.t.tt
+#: Salent v[% version %]
+#: Copyright (C) [% year %] Agent Zhang.
+#: 2005-07-12 [% last_mod %]
+
+use strict;
+use warnings;
+
+[%- tests = 1 -%]
+[% FOREACH op IN ops;
+ tests = tests + 1;
+ IF op.op != 'nop';
+ tests = tests + 1;
+ IF op.op == 'mul' OR op.op == 'imul' OR
+ op.op == 'div' OR op.op == 'idiv';
+ tests = tests + 2;
+ END;
+ IF op.cin.defined;
+ tests = tests + 1;
+ END;
+ END;
+ END
+-%]
+
+use Test::More tests => [% tests %];
+use ModelSim::List;
+
+my $fh;
+ok(open($fh, "[% solu_file %]"), 'Open the solution file');
+<$fh>; # Shift the first line
+
+my $list = ModelSim::List->new;
+$list->parse('[% list_file %]');
+
+my $line;
+my @sols;
+my $cf;
+
+[%- start = 0 -%]
+[% FOREACH op IN ops -%]
+
+ [%- end = start + op.run_time -%]
+ [%- des = Perl.sprintf('%s %s - %s($.) - (@ %d ~ %d)', op.op, op.A, solu_file, start, end) -%]
+
+$line = <$fh>;
+ok(defined $line, 'Not the end of file');
+ [%- IF op.op != 'nop' %]
+@sols = split(/\s+/, $line);
+like($list->strobe('/alu/res1', [% start + op.run_time %]), qr/^0*$sols[1]$/i, "
+ [%- des %] - res1");
+
+ [%- IF op.op == 'mul' OR op.op == 'imul' OR
+ op.op == 'div' OR op.op == 'idiv' -%]
+is(scalar(@sols), 3, "number of items in line $. is 3");
+like($list->strobe('/alu/res2', [% start + op.run_time %]), qr/^0*$sols[2]$/i, "
+ [%- des %] - res2");
+ [%- END -%]
+
+ [%- IF op.cin.defined -%]
+$cf = substr($sols[0], -1, 1);
+like($list->strobe('/alu/cout', [% start + op.run_time %]), qr/^0*$cf$/i, "
+ [%- des %] - cout");
+ [%- END -%]
+ [%- END %]
+ [% start = start + op.run_time -%]
+[% END -%]
+
+close $fh;
136 alu/alu.v.tt
@@ -0,0 +1,136 @@
+[% DEFAULT
+ version = '0.13'
+ word_size = 32
+ alu = {
+ sels =
+ [
+ 'NOP',
+ 'ADD', 'SUB', 'MUL', 'IMUL', 'DIV', 'IDIV',
+ 'AND', 'OR', 'XOR', 'NOT', 'NEG',
+ 'SHL', 'SHR', 'SAL', 'SAR',
+ 'ROL', 'ROR', 'RCL', 'RCR',
+ ]
+ delay = 1
+ }
+-%]
+[% USE Perl;
+ USE POSIX;
+ USE date;
+ SET
+ last_mod = date.format(template.modtime, '20%y-%m-%d', 'en_GB')
+ year = date.format(template.modtime, '20%y', 'en_GB')
+
+ temp = Perl.log(alu.sels.size) / Perl.log(2)
+ sel_size = POSIX.ceil(temp);
+-%]
+//: alu.v.tt
+//: Arithmetic Logic Unit (ALU)
+//: Salent v[% version %]
+//: Copyright (c) [% year %] Agent Zhang.
+//: 2005-07-11 [% last_mod %]
+
+/*
+ res1 is the normal output port.
+ When division is performed, res2 stores the remainder and data3
+ stores the higher word of the dividend.
+ When multiplication is performed, res2 stores the higher word of
+ the product.
+*/
+module alu (cout, res1, res2, data1, data2, data3, cin, sel);
+ parameter WORD_SIZE = [% word_size %];
+ parameter DELAY = [% alu.delay %];
+ parameter SEL_SIZE = [% sel_size %];
+
+ // Opcodes:
+[%- fmt = Perl.sprintf("%d'b%%0%db", sel_size, sel_size);
+ i = 0 %]
+[%- FOREACH sel IN alu.sels %]
+ parameter [% Perl.sprintf("%-4s", sel) %] = [% Perl.sprintf(fmt, i) %];
+ [%- i = i + 1 %]
+[%- END %]
+
+ output cout; // Carry out
+ output [WORD_SIZE-1:0] res1, res2;
+ input [WORD_SIZE-1:0] data1, data2, data3;
+ input cin; // Carry in
+ input [SEL_SIZE-1:0] sel; // Specifies the operation to be carried out
+
+ reg cout;
+ reg [WORD_SIZE-1:0] res1, res2;
+ reg [WORD_SIZE-1:0] temp1, temp2;
+
+ always @ (sel or data1 or data2 or data3 or cin) begin
+ #(DELAY);
+ case (sel)
+ NOP: ;
+
+ ADD: { cout, res1 } = data1 + data2 + cin;
+ SUB: { cout, res1 } = data1 - data2 - cin;
+ MUL: { cout, res2, res1 } = data1 * data2;
+ IMUL: { cout, res2, res1 } = $signed(data1) * $signed(data2);
+
+ DIV: // Carry out is undefined.
+ begin
+ res1 = {data3, data1} / data2;
+ res2 = {data3, data1} % data2;
+ end
+
+ IDIV: // Carry out is undefined.
+ begin
+ res1 = $signed({data3, data1}) / $signed(data2);
+ res2 = $signed({data3, data1}) % $signed(data2);
+ end
+
+ AND: {cout, res1} = data1 & data2;
+ OR: {cout, res1} = data1 | data2;
+ XOR: {cout, res1} = data1 ^ data2;
+ NOT: res1 = ~ data1; // Carry out is unaffected.
+ NEG: {cout, res1} = ~ data1 + 1;
+
+ SHL: {cout, res1} = {cin, data1} << data2;
+ SAL: {cout, res1} = $signed({cin, data1}) <<< data2;
+
+ SHR: {res1, cout} = {data1, cin} >> data2;
+ SAR: {res1, cout} = $signed({data1, cin}) >>> data2;
+
+ ROL:
+ begin
+ {cout, temp1} = {cin, data1} << data2;
+ temp2 = data1 >> (WORD_SIZE - data2);
+ res1 = temp1 + temp2;
+ end
+
+ RCL:
+ begin
+ {cout, temp1} = {cin, data1} << data2;
+ temp2 = {cin, data1} >> (WORD_SIZE - data2 + 1);
+ res1 = temp1 + temp2;
+ end
+
+ ROR:
+ begin
+ {temp1, cout} = {data1, cin} >> data2;
+ temp2 = data1 << (WORD_SIZE - data2);
+ res1 = temp1 + temp2;
+ end
+
+ RCR:
+ begin
+ {temp1, cout} = {cin, data1, cin} >> data2;
+ temp2 = data1 << (WORD_SIZE - data2 + 1);
+ res1 = temp1 + temp2;
+ end
+
+ default:
+ begin
+ [%- IF word_size > 32 # adapt to vlog-1995 %]
+ res1 = [% word_size %]'bx;
+ res2 = [% word_size %]'bx;
+ [%- ELSE %]
+ res1 = 'bx;
+ res2 = 'bx;
+ [%- END %]
+ end
+ endcase
+ end
+endmodule
63 alu/ast++.pl
@@ -0,0 +1,63 @@
+#: ast++.pl
+#: Add random timing info to the ALU AST
+#: Salent v0.13
+#: Copyright (c) Agent Zhang.
+#: 2005-07-18 2005-07-18
+
+use strict;
+use warnings;
+use Template::Ast;
+
+@ARGV == 1 or
+ die "Usage: ast++ <ast-file>\n";
+my $astfile = shift;
+
+# Read the AST description from the file given:
+my $ast = Template::Ast->read($astfile);
+die Template::Ast->error() unless $ast;
+
+# Add timing info to the AST:
+#die Template::Ast->dump([$ast], ['ast']);
+$ast->{alu} = { delay => 10 } unless defined $ast->{alu};
+$ast->{alu}->{delay} = 10 unless $ast->{alu}->{delay};
+my $ops = $ast->{ops};
+foreach my $op (@$ops) {
+ my $op_time = genrand(1, 20) if defined $op->{op};
+ my $A_time = genrand(1, 20) if defined $op->{A};
+ my $B_time = genrand(1, 20) if defined $op->{B};
+ my $D_time = genrand(1, 20) if defined $op->{D};
+ my $cin_time = genrand(1, 20) if defined $op->{cin};
+ #warn $ast->{alu}->{delay};
+ my $run_time = genrand(
+ max($op_time, $A_time, $B_time, $D_time, $cin_time) +
+ $ast->{alu}->{delay} + 1,
+ 20);
+ #warn "op $op_time, A $A_time, B $B_time, D $D_time, cin $cin_time, ".
+ # "run $run_time";
+
+ $op->{op_time} = $op_time;
+ $op->{A_time} = $A_time;
+ $op->{B_time} = $B_time;
+ $op->{D_time} = $D_time;
+ $op->{cin_time} = $cin_time;
+ $op->{run_time} = $run_time;
+}
+
+# Dump the AST to the original file:
+Template::Ast->write($ast, $astfile) or
+ die Template::Ast->error();
+print "$astfile generated.\n";
+
+sub genrand {
+ my ($start, $len) = @_;
+ return (int rand($len)) + $start;
+}
+
+sub max {
+ my @vals = grep { defined $_ } @_;
+ my $max = shift @vals;
+ foreach (@vals) {
+ $max = $_ if $_ > $max;
+ }
+ return $max;
+}
39 alu/opc.tt
@@ -0,0 +1,39 @@
+[% DEFAULT
+ op_file = 'talu1.op'
+-%]
+[% SET
+ ast = {
+ c_file = op_file _ '.c',
+ vlog_file = op_file _ '.v',
+ perl_file = op_file _ '.t',
+ list_file = op_file _ '.lst',
+ solu_file = op_file _ '.exe.out'
+
+ alu = {},
+ ops = [],
+ };
+ USE data = datafile(op_file, delim = ':');
+ FOREACH record IN data;
+ IF record.delay.defined;
+ ast.alu.delay = record.delay;
+ END;
+ IF record.word_size.defined;
+ ast.word_size = record.word_size;
+ END;
+ NEXT IF !record.op;
+ op = { op = record.op };
+ op.A = record.A;
+ IF record.B.defined;
+ op.B = record.B;
+ END;
+ IF record.D.defined;
+ op.D = record.D;
+ END;
+ IF record.cin.defined;
+ op.cin = record.cin;
+ END;
+ ast.ops.push(op);
+ END;
+ USE dumper;
+ dumper.dump(ast);
+-%]
58 alu/talu1.op.tt
@@ -0,0 +1,58 @@
+#: talu1.op.tt
+#: Test add, sub, mul, imul.
+#: Salent v0.13
+#: Copyright (c) 2005 Agent Zhang.
+#: 2005-07-18 2005-07-18
+
+op : A : B : D : cin : word_size : delay
+:::::32:5
+[% USE Perl;
+ #CALL Perl.srand(1);
+ max = Perl.pow(2, 32); -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+add : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+sub : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+-%]
+mul : [% A %] : [% B %] : : : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+-%]
+imul : [% A %] : [% B %] : : : :
+ [%- i = i + 1 %]
+[% END -%]
+
67 alu/talu2.op.tt
@@ -0,0 +1,67 @@
+#: talu2.op.tt
+#: Test div and idiv.
+#: Salent v0.13
+#: Copyright (c) 2005 Agent Zhang.
+#: 2005-07-18 2005-07-18
+
+op : A : B : D : cin : word_size : delay
+:::::32:5
+[% USE Perl;
+
+ max = Perl.pow(2, 32);
+ max2 = Perl.pow(2, 16);
+-%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ D = '00000000';
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+ NEXT IF B.match('^0+$');
+-%]
+div : [% A %] : [% B %] : [% D %] : : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ D = Perl.int(Perl.rand(max2));
+ D = Perl.sprintf("%08x", D);
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+ NEXT IF B.match('^0+$');
+-%]
+div : [% A %] : [% B %] : [% D %] : : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ D = '00000000';
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+ NEXT IF B.match('^0+$');
+-%]
+idiv : [% A %] : [% B %] : [% D %] : : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ D = Perl.int(Perl.rand(max2));
+ D = Perl.sprintf("%08x", D);
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+ NEXT IF B.match('^0+$');
+-%]
+idiv : [% A %] : [% B %] : [% D %] : : :
+ [%- i = i + 1 %]
+[% END -%]
67 alu/talu3.op.tt
@@ -0,0 +1,67 @@
+#: talu3.op.tt
+#: Test and, or, xor, not, and neg.
+#: Salent v0.13
+#: Copyright (c) 2005 Agent Zhang.
+#: 2005-07-18 2005-07-18
+
+op : A : B : D : cin : word_size : delay
+:::::32:5
+[% USE Perl;
+ #CALL Perl.srand(1);
+ max = Perl.pow(2, 32); -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+and : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+or : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(max));
+ B = Perl.sprintf("%08x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+xor : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ #cin = Perl.int(Perl.rand(2));
+-%]
+not : [% A %] : : : : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ cin = Perl.int(Perl.rand(2));
+-%]
+neg : [% A %] : : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
61 alu/talu4.op.tt
@@ -0,0 +1,61 @@
+#: talu4.op.tt
+#: Test shl, shr, sal, and sar.
+#: Salent v0.13
+#: Copyright (c) 2005 Agent Zhang.
+#: 2005-07-18 2005-07-18
+
+op : A : B : D : cin : word_size : delay
+:::::32:5
+[% USE Perl;
+ #CALL Perl.srand(1);
+ max = Perl.pow(2, 32);
+-%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(32));
+ B = Perl.sprintf("%02x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+shl : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(32));
+ B = Perl.sprintf("%02x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+shr : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(32));
+ B = Perl.sprintf("%02x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+sal : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(32));
+ B = Perl.sprintf("%02x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+sar : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
63 alu/talu5.op.tt
@@ -0,0 +1,63 @@
+#: talu5.op.tt
+#: Test rol, ror, rcl, and rcr.
+#: Salent v0.13
+#: Copyright (c) 2005 Agent Zhang.
+#: 2005-07-18 2005-07-18
+
+op : A : B : D : cin : word_size : delay
+:::::32:5
+[% USE Perl;
+ #CALL Perl.srand(1);
+ max = Perl.pow(2, 32);
+-%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(32));
+ B = Perl.sprintf("%02x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+rol : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(32));
+ B = Perl.sprintf("%02x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+ror : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(32));
+ B = Perl.sprintf("%02x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+rcl : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+rcl : 0000e49e : 11 : : 1 : :
+
+[% i = 0 -%]
+[% WHILE i < 100;
+ A = Perl.int(Perl.rand(max));
+ A = Perl.sprintf("%08x", A);
+ B = Perl.int(Perl.rand(32));
+ B = Perl.sprintf("%02x", B);
+ cin = Perl.int(Perl.rand(2));
+-%]
+rcr : [% A %] : [% B %] : : [% cin %] : :
+ [%- i = i + 1 %]
+[% END -%]
+rcr : e49e0000 : 11 : : 1 : :
+rcr : 28820000 : 00 : : 1 : :
58 alu/talu6.pl
@@ -0,0 +1,58 @@
+#: talu6.pl
+#: Generate talu6.op.ast directly.
+#: Salent v0.13
+#: Copyright (c) 2005 Agent Zhang.
+#: 2005-07-21 2005-07-21
+
+use strict;
+use warnings;
+use Template::Ast;
+
+my $op_file = 'talu6.op';
+my @ops;
+my $ast = {
+ c_file => $op_file . '.c',
+ vlog_file => $op_file . '.v',
+ perl_file => $op_file . '.pl',
+ list_file => $op_file . '.lst',
+ solu_file => $op_file . '.exe.out',
+
+ alu => { delay => 5 },
+ ops => \@ops,
+};
+
+gen_op('add');
+gen_op('sub');
+gen_op('mul');
+gen_op('imul');
+
+Template::Ast->write($ast, "$op_file.ast") or
+ die Template::Ast->error();
+#print "$op_file.ast generated.\n";
+
+sub gen_op {
+ my $op = shift;
+ foreach my $i (1..100) {
+ my $A = rand_hex(8);
+ my $B = rand_hex(8);
+ my $cin = int(rand(2));
+ push @ops, {
+ op => $op,
+ A => $A,
+ B => $B,
+ };
+ unless ($op =~ m/mul/) {
+ $ops[-1]->{cin} = $cin;
+ }
+ }
+}
+
+sub rand_hex {
+ my $len = shift;
+ my $hex_val;
+ for (1..$len) {
+ my $digit = int(rand(16));
+ $hex_val .= sprintf("%1x", $digit);
+ }
+ return $hex_val;
+}
3 alu/work/_info
@@ -0,0 +1,3 @@
+m255
+cModel Technology
+dD:\Agent2002\AISystem1.0\LogicDesign\Salent\Salent\alu
5 build.bat
@@ -0,0 +1,5 @@
+@echo off
+
+call tpage Config.ast.tt > Config.ast
+call astt -o ram.v -t ram\ram.v.tt Config.ast
+call astt -o alu.v -t alu\alu.v.tt Config.ast
20 clean.bat
@@ -0,0 +1,20 @@
+@echo off
+
+del vsim.wlf transcript
+del *.v
+
+pushd ram
+perl Makefile.PL
+nmake clean
+popd
+
+pushd alu
+perl Makefile.PL
+nmake clean
+popd
+
+pushd idu
+nmake clean
+popd
+
+del *.html
14 exclude
@@ -0,0 +1,14 @@
+notes*
+Changes
+ChangeLog
+*.pdf
+*.exe
+*.obj
+*.ast
+*.bin
+*.dll
+*.pdb
+*.hex
+*.htm*
+catln.dat~
+catln.dat
4 idu/.smoker.yml
@@ -0,0 +1,4 @@
+---
+name: Agent Zhang
+email: agent2002@126.com
+
130 idu/C/Idu.pm
@@ -0,0 +1,130 @@
+#: Idu.pm
+#: Perl wrapper for the C IDU
+#: Salent v0.13
+#: Copyright (c) 2005 Agent Zhang
+#: 2005-08-17 2005-08-19
+
+package Idu;
+
+use strict;
+use warnings;
+use Data::Dumper;
+
+my ($lib, $inc);
+BEGIN {
+ require 'File/Spec.pm';
+ $lib = File::Spec->rel2abs("C/idu.lib");
+ $inc = File::Spec->rel2abs("C");
+ $ENV{PATH} .= ";$inc";
+}
+
+use Inline C => Config =>
+ ENABLE => AUTOWRAP =>
+ MYEXTLIB => $lib =>
+ INC => "-I $inc";
+use Inline C => <<'_EOC_';
+#include <idu.h>
+
+enum { BUFSIZE = 8 };
+
+void set_source(char* buf);
+
+char* get_source();
+
+char* get_cur_token();
+
+char* get_error_info();
+
+int set_debug(int value);
+
+int readbytes2(SV* rlist, int len) {
+ int retval, i;
+ Byte outbuf[BUFSIZE];
+ AV* array;
+ array = newAV();
+ sv_setsv(rlist, newRV_noinc((SV*)array));
+
+ retval = readbytes(outbuf, len);
+ if (retval != len) return retval;
+ for (i = 0; i < len; i++)
+ av_push(array, newSViv(*(outbuf+i)));
+ return len;
+}
+
+int slice2(int byte, int i, int j) {
+ return slice((Byte)byte, i, j);
+};
+
+int match2(int byte, char* pat) {
+ return match((Byte)byte, pat);
+}
+
+int get_imm_len(int s, int w, int bits16);
+
+int process_ModRM2(SV* rhash, Byte byte) {
+ Result res;
+ return process_ModRM(&res, byte);
+}
+
+SV* dump_byte2(int byte) {
+ enum { BUFSIZE = 10 };
+ char buf[BUFSIZE];
+ dump_byte((Byte)byte, buf);
+ return newSVpv(buf, 0);
+}
+
+SV* decode2(char* src) {
+ Result* res;
+ char* code;
+ SV* sv;
+ //printf("src - %s\n", src);
+ set_source(src);
+ res = decode(NULL);
+ //printf("res - %x\n", res);
+ if (res == NULL) return &PL_sv_undef;
+ code = dump_res_to_perl(res);
+ /*
+ if (code) {
+ printf("---------------\n");
+ printf("code - %s", code);
+ printf("---------------\n");
+ }
+ */
+ sv = newSVpv(code, 0);
+ free_ptr(code);
+ return sv;
+}
+
+_EOC_
+
+our $debug = 0;
+my $max_code_len = 0;
+
+sub decode {
+ shift if @_ > 1;
+ my $src = shift;
+ my $code = decode2($src);
+ #die $code;
+ return undef unless $code;
+ #print "----------------\n";
+ #print $code;
+ #print "================\n";
+ my $res = eval $code;
+ #warn Data::Dumper->Dump([$res], ['res']);
+ die $@ if $@;
+ if ($debug and length($code) > $max_code_len) {
+ $max_code_len = length($code);
+ }
+ #warn "Hey!";
+ return $res;
+}
+
+sub error {
+ return get_error_info();
+}
+
+END {
+ warn "Maximal code size: $max_code_len" if $debug;
+}
+
+1;
686 idu/C/idu.c.tt
@@ -0,0 +1,686 @@
+[% DEFAULT
+ version = '0.13'
+ idu = {
+ reg_fields = []
+ bit_fields = []
+ state_machine = []
+ prefixes = []
+ }
+-%]
+[% USE date;
+ USE Perl -%]
+[% SET
+ last_mod = date.format(template.modtime, '20%y-%m-%d', 'en_GB')
+ states = idu.state_machine
+-%]
+//: idu.c
+//: C implemetation of Instruction Decoding Unit (IDU)
+//: Salent v[% version %]
+//: Copyright (c) 2005 Agent Zhang
+//: 2005-08-17 [% last_mod %]
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdio.h>
+
+#define _IDU_C_
+#include <idu.h>
+
+#define NELEMS(list) sizeof(list)/sizeof((list)[0])
+
+#define READ_DISP(len) \
+ retval = readbytes(bytes, (len)); \
+ if (retval != (len)) return retval; \
+ memcpy(res->disp, bytes, len); \
+ res->disp_len = len;
+
+#define READ_SIB \
+ retval = readbytes(bytes, 1); \
+ if (retval != 1) return retval; \
+ byte = bytes[0];
+
+#define READ_BYTE \
+ retval = readbytes(bytes, 1); \
+ if (retval == EOF) { \
+ state = S_END_ERROR; \
+ break; \
+ } else if (retval == 0) { \
+ state = S_SYN_ERROR; \
+ break; \
+ } \
+ byte = bytes[0];
+
+#define READ_IMM_DATA(len) \
+ retval = readbytes(bytes, (len)); \
+ if (retval == EOF) { \
+ state = S_END_ERROR; \
+ break; \
+ } else if (retval == 0) { \
+ state = S_SYN_ERROR; \
+ break; \
+ } \
+ memcpy(res->imm, bytes, (len)); \
+ res->imm_len = (len);
+
+#define CARP(fmt,val) \
+ fprintf(stderr, fmt##" - %s(line %d)\n", (val), __FILE__, __LINE__);
+
+enum {
+ BUFSIZE = 256,
+ UNDEF = -1
+};
+
+static const char* Source;
+static char Token[BYTES_LEN];
+static char Error[BUFSIZE];
+
+static int Debug = 0;
+
+void set_source(char* buf) {
+ Source = buf;
+ strcpy(Token, "");
+}
+
+char* get_source(void) {
+ return (char*) Source;
+}
+
+// get the current token:
+char* get_cur_token(void) {
+ return Token;
+}
+
+// get the error info:
+char* get_error_info(void) {
+ return Error;
+}
+
+// set the debug mode:
+int set_debug(int value) {
+ int oldval;
+ oldval = Debug;
+ Debug = value;
+ return oldval;
+}
+
+// read one or more bytes from the source:
+int readbytes(Byte* outbuf, int len) {
+ enum { FMTSIZE = 10 };
+ char fmt[FMTSIZE];
+ int i, j, token_len;
+
+ sprintf(fmt, "%%%ds", NELEMS(Token)-1);
+ //CARP("fmt - %s", fmt);
+ for (i = 0; i < len; i++) {
+ int retval;
+ while (*Source == ' ' || *Source == '\t' || *Source == '\n')
+ Source++;
+ retval = sscanf(Source, fmt, Token);
+ //CARP("%d", retval);
+ if (retval == 0 || retval == EOF) {
+ //CARP("retval - %d", retval)
+ //Source = "";
+ return retval;
+ }
+ token_len = strlen(Token);
+ Source += token_len;
+ //CARP("token_len : %d", token_len)
+ for (j = 0; j < token_len; j++) {
+ if ((Token[j] >= '0' && Token[j] <= '9') ||
+ (Token[j] >= 'a' && Token[j] <= 'f') ||
+ Token[j] >= 'A' && Token[j] <= 'F')
+ continue;
+ else
+ return 0;
+ }
+ if (token_len != 2) return 0;
+ //CARP("%s", Token);
+ //CARP("%s", Source);
+ retval = sscanf(Token, "%02x", outbuf+i);
+ //CARP("%02x", outbuf[0]);
+ if (retval == 0 || retval == EOF) {
+ //CARP("retval - %d", retval)
+ return retval;
+ }
+ }
+ //CARP("%02x", outbuf[0]);
+ return len;
+}
+
+// slice the byte via subscripts:
+Byte slice(Byte byte, int i, int j) {
+ Byte retval = 0;
+ assert(i >= j);
+ while (i >= j) retval += byte & (1 << i--);
+ return retval >>= j;
+}
+
+// match the byte against the pattern:
+int match(Byte byte, const char* pat) {
+ Byte filter, c;
+ for (filter = 0x80; (c = *pat) != '\0'; filter >>= 1, pat++) {
+ //printf("%c", c);
+ if (c == '.') continue;
+ if (byte & filter) {
+ if (c == '0') return 0;
+ } else {
+ if (c == '1') return 0;
+ }
+ }
+ return 1;
+}
+
+static int defined(int fld) {
+ return fld != UNDEF;
+}
+
+// derive the length of immediate data (in bytes):
+int get_imm_len(int s, int w, int bits16) {
+ if (defined(s) && !defined(w)) {
+ if (s == 1) // 8-bit imm size
+ return 1;
+ else // full size imm size
+ return bits16 == 1 ? 2 : 4;
+ } else if (defined(w) && !defined(s)) {
+ if (w == 0) // 8-bit imm size
+ return 1;
+ else // full size imm size
+ return bits16 == 1 ? 2 : 4;
+ } else if (defined(w) && defined(s)) {
+ if (s == 1) // 8-bit imm size
+ return 1;
+ else if (w == 0) // 8-bit imm size
+ return 1;
+ else
+ return bits16 == 1 ? 2 : 4;
+ } else { // both w and s fields are absent
+ return bits16 == 1 ? 2 : 4;
+ }
+}
+
+// Process the ModR/M byte:
+int process_ModRM(Result* res, Byte byte) {
+ int mod, rm, base, retval;
+ Byte bytes[NBYTES_MAX];
+ mod = slice(byte, 7, 6);
+ rm = slice(byte, 2, 0);
+ res->mod = mod;
+ res->rm = rm;
+ if (mod == 0 /* 00 */) {
+ if (rm == 5 /* 101 */) { // Direct: EA = Disp32
+ // Get 32-bit displacement:
+ READ_DISP(4)
+ } else if (rm == 4 /* 100 */) { // Base with index (uses SIB byte)
+ // Get SIB byte:
+ READ_SIB
+ byte = bytes[0];
+ res->scale = slice(byte, 7, 6);
+ res->index_reg = slice(byte, 5, 3);
+ base = slice(byte, 2, 0);
+ if (base == 5 /* 101 */) { // Base == EBP: EA = [Index] x Scale + Disp32
+ // Get 32-bit displacement:
+ READ_DISP(4)
+ } else { // EA = [Base] + [Index] x Scale
+ res->base_reg = base;
+ }
+ }
+ } else if (mod == 1 /* 01 */) {
+ if (rm == 4 /* 100 */) { // EA = [Base] + [Index] x Scale + Disp8
+ // Get SIB byte:
+ READ_SIB
+ res->scale = slice(bytes[0], 7, 6);
+ res->index_reg = slice(bytes[0], 5, 3);
+ res->base_reg = slice(bytes[0], 2, 0);
+ // Get 8-bit displacement:
+ READ_DISP(1)
+ } else { // EA = [Reg] + Disp8
+ // Get 8-bit displacement:
+ READ_DISP(1)
+ }
+ } else if (mod == 2 /* 10 */) {
+ if (rm == 4 /* 100 */) { // EA = [Base] + [Index] x Scale + Disp32
+ // Get SIB byte:
+ READ_SIB
+ res->scale = slice(bytes[0], 7, 6);
+ res->index_reg = slice(bytes[0], 5, 3);
+ res->base_reg = slice(bytes[0], 2, 0);
+ // Get 32-bit displacement:
+ READ_DISP(4)
+ } else { // EA = [Reg] + Disp32
+ // Get 32-bit displacement:
+ READ_DISP(4)
+ }
+ }
+ return 1;
+}
+
+Result* new_res() {
+ Result* res = (Result*) malloc(sizeof(Result));
+ assert(res);
+ memset(res, 0, sizeof(Result));
+[%- FOREACH bit IN idu.bit_fields %]
+ res->[% bit %] = UNDEF;
+[%- END -%]
+
+[%- FOREACH reg IN idu.reg_fields %]
+ res->[% reg %] = UNDEF;
+[%- END %]
+ res->mod = UNDEF;
+ res->rm = UNDEF;
+ res->base_reg = UNDEF;
+ res->index_reg = UNDEF;
+ res->scale = UNDEF;
+ return res;
+}
+
+void dump_byte(Byte byte, char* outbuf) {
+ int i;
+ for (i = 0; i < 8; i++)
+ sprintf(outbuf++, "%1d", ((0x80 >> i) & byte) ? 1 : 0);
+ *outbuf = '\0';
+}
+
+// dump the content of Result instance to the given file handle:
+void dump_res(Result* res, FILE* fh) {
+ enum { BUFSIZE = 10 };
+ char buf[BUFSIZE];
+
+ fprintf(fh, "Instruction Set : %s\nInstruction: %s\nDescription: %s\n",
+ res->ins_set, res->ins, res->des);
+ if (res->subdes) fprintf(fh, "Sub-Description: %s\n", res->subdes);
+ fprintf(fh, "Encoding Pattern: %s\n", res->encoding);
+
+ fprintf(fh, "Operand-Size Attribute: ");
+ if (res->bits16 == 1) fprintf(fh, "16-bit\n");
+ else fprintf(fh, "32-bit\n");
+
+[%- FOREACH bit IN idu.bit_fields %]
+ if (defined(res->[% bit %]))
+ fprintf(fh, "[% bit %] Field: %1d\n", res->[% bit %]);
+[% END -%]
+
+[%- FOREACH reg IN ['reg', 'reg1', 'reg2', 'sreg3', 'eee', 'ST_i'] %]
+ dump_byte((Byte)res->[% reg %], buf);
+ if (defined(res->[% reg %])) {
+ fprintf(fh, "[% reg %] Field: %3s\n", buf + 5);
+ }
+[%- END %]
+
+[%- FOREACH reg IN ['tttn'] %]
+ dump_byte((Byte)res->[% reg %], buf);
+ if (defined(res->[% reg %])) {
+ fprintf(fh, "[% reg %] Field: %4s\n", buf + 4);
+ }
+[%- END %]
+
+ dump_byte((Byte)res->sreg2, buf);
+ if (defined(res->sreg2)) {
+ fprintf(fh, "sreg2 Field: %2s\n", buf + 6);
+ }
+
+ if (defined(res->mod)) {
+ dump_byte((Byte)res->mod, buf);
+ fprintf(fh, "Mod field: %2s\n", buf + 6);
+ dump_byte((Byte)res->rm, buf);
+ fprintf(fh, "R/M field: %3s\n", buf + 5);
+ }
+
+ if (defined(res->base_reg)) {
+ dump_byte((Byte)res->base_reg, buf);
+ fprintf(fh, "Base Register: %3s\n", buf + 5);
+ }
+ if (defined(res->index_reg)) {
+ dump_byte((Byte)res->index_reg, buf);
+ fprintf(fh, "Index Register: %3s\n", buf + 5);
+ }
+ if (defined(res->scale)) {
+ dump_byte((Byte)res->scale, buf);
+ fprintf(fh, "Scale for Index Register: %2s\n", buf + 6);
+ }
+ if (res->disp_len > 0) {
+ int i;
+ fprintf(fh, "Displacement:");
+ for (i = 0; i < res->disp_len; i++)
+ fprintf(fh, " %02x", res->disp[i]);
+ fprintf(fh, "\n");
+ }
+ if (res->imm_len > 0) {
+ int i;
+ fprintf(fh, "Immediate Data:");
+ for (i = 0; i < res->imm_len; i++)
+ fprintf(fh, " %02x", res->imm[i]);
+ fprintf(fh, "\n");
+ }
+ if (res->nprefs > 0) {
+ int i;
+ fprintf(fh, "Prefix Bytes:");
+ for (i = 0; i < res->nprefs; i++)
+ fprintf(fh, " %02x", res->prefix[i]);
+ fprintf(fh, "\n");
+ }
+
+ fprintf(fh, "Bytes read: %s\n", res->bytes);
+}
+
+// dump the content of Result instance to Perl code:
+char* dump_res_to_perl(Result* res) {
+ enum { BUFSIZE = 10, CODE_BUF_SIZE = 512 };
+ char buf[BUFSIZE];
+ char *code;
+ int len;
+
+ len = 0;
+ code = (char*) malloc(CODE_BUF_SIZE * sizeof(char));
+ assert(code);
+
+ len += sprintf(code + len, "{\n");
+ assert(len < CODE_BUF_SIZE);
+ len += sprintf(code + len, " 'ins_set' => \"%s\",\n 'ins' => \"%s\",\n 'des' => \"%s\",\n",
+ res->ins_set, res->ins, res->des);
+ assert(len < CODE_BUF_SIZE);
+ if (res->subdes) {
+ len += sprintf(code + len, " 'subdes' => \"%s\",\n", res->subdes);
+ assert(len < CODE_BUF_SIZE);
+ }
+ len += sprintf(code + len, " 'encoding' => \"%s\",\n", res->encoding);
+ assert(len < CODE_BUF_SIZE);
+
+ if (res->bits16 == 1) {
+ len += sprintf(code + len, " 'bits16' => '1',\n");
+ assert(len < CODE_BUF_SIZE);
+ }
+
+[%- FOREACH bit IN idu.bit_fields %]
+ if (defined(res->[% bit %])) {
+ len += sprintf(code + len, " '[% bit %]' => '%1d',\n", res->[% bit %]);
+ assert(len < CODE_BUF_SIZE);
+ }
+[% END -%]
+
+[%- FOREACH reg IN ['reg', 'reg1', 'reg2', 'sreg3', 'eee', 'ST_i'] %]
+ dump_byte((Byte)res->[% reg %], buf);
+ if (defined(res->[% reg %])) {
+ len += sprintf(code + len, " '[% reg %]' => '%3s',\n", buf + 5);
+ assert(len < CODE_BUF_SIZE);
+ }
+[%- END %]
+
+[%- FOREACH reg IN ['tttn'] %]
+ dump_byte((Byte)res->[% reg %], buf);
+ if (defined(res->[% reg %])) {
+ len += sprintf(code + len, " '[% reg %]' => '%4s',\n", buf + 4);
+ assert(len < CODE_BUF_SIZE);
+ }
+[%- END %]
+
+ dump_byte((Byte)res->sreg2, buf);
+ if (defined(res->sreg2)) {
+ len += sprintf(code + len, " 'sreg2' => '%2s',\n", buf + 6);
+ assert(len < CODE_BUF_SIZE);
+ }
+
+ if (defined(res->mod)) {
+ dump_byte((Byte)res->mod, buf);
+ len += sprintf(code + len, " 'mod' => '%2s',\n", buf + 6);
+ dump_byte((Byte)res->rm, buf);
+ len += sprintf(code + len, " 'rm' => '%3s',\n", buf + 5);
+ assert(len < CODE_BUF_SIZE);
+ }
+
+ if (defined(res->base_reg)) {
+ dump_byte((Byte)res->base_reg, buf);
+ len += sprintf(code + len, " 'base_reg' => '%3s',\n", buf + 5);
+ assert(len < CODE_BUF_SIZE);
+ }
+ if (defined(res->index_reg)) {
+ dump_byte((Byte)res->index_reg, buf);
+ len += sprintf(code + len, " 'index_reg' => '%3s',\n", buf + 5);
+ assert(len < CODE_BUF_SIZE);
+ }
+ if (defined(res->scale)) {
+ dump_byte((Byte)res->scale, buf);
+ len += sprintf(code + len, " 'scale' => '%2s',\n", buf + 6);
+ assert(len < CODE_BUF_SIZE);
+ }
+ if (res->disp_len > 0) {
+ int i;
+ len += sprintf(code + len, " 'disp' => [qw(");
+ for (i = 0; i < res->disp_len; i++) {
+ len += sprintf(code + len, " %02x", res->disp[i]);
+ assert(len < CODE_BUF_SIZE);
+ }
+ len += sprintf(code + len, " )],\n");
+ assert(len < CODE_BUF_SIZE);
+ }
+ if (res->imm_len > 0) {
+ int i;
+ len += sprintf(code + len, " 'imm' => [qw(");
+ for (i = 0; i < res->imm_len; i++) {
+ len += sprintf(code + len, " %02x", res->imm[i]);
+ assert(len < CODE_BUF_SIZE);
+ }
+ len += sprintf(code + len, " )],\n");
+ assert(len < CODE_BUF_SIZE);
+ }
+ if (res->nprefs > 0) {
+ int i;
+ len += sprintf(code + len, " 'prefix' => [qw(");
+ for (i = 0; i < res->nprefs; i++) {
+ len += sprintf(code + len, " %02x", res->prefix[i]);
+ assert(len < CODE_BUF_SIZE);
+ }
+ len += sprintf(code + len, " )],\n");
+ assert(len < CODE_BUF_SIZE);
+ }
+ len += sprintf(code + len, " 'bytes' => [qw( %s )],\n", res->bytes);
+ assert(len < CODE_BUF_SIZE);
+ len += sprintf(code + len, "};\n");
+ assert(len < CODE_BUF_SIZE);
+ return code;
+}
+
+enum {
+[% count = 0 %]
+[%- FOREACH state IN states %]
+ [%- IF count == 0 %]
+ [%- GET " S_" _ state.state_id _ "," %]
+ [%- ELSE %]
+ [%- GET " S_" _ state.state_id _ "," %]
+ [%- END %]
+ [%- count = count + 1 %]
+ [%- IF count == 10 %]
+ [%- GET "\n"; count = 0 %]
+ [%- END %]
+[%- END %]
+ S_START, S_PREFIX,
+ S_END_ERROR, S_SYN_ERROR, S_TOO_MANY_PREF
+};
+
+// Decode one instruction:
+Result* decode(char* src) {
+ const char* saved_src;
+ char oldbytes[BUFSIZE];
+ Byte byte;
+ Byte bytes[NBYTES_MAX];
+ Result* res;
+ int state, len, retval, success = 1;
+
+ res = new_res();
+ if (src != NULL) set_source(src);
+ saved_src = Source;
+ state = S_START;
+ while (1) {
+ if (Debug) {
+ int val = byte;
+ fprintf(stderr, "Switching to state %d with byte %02x...\n", state, val);
+ }
+ switch (state) {
+ case S_START:
+ retval = readbytes(bytes, 1);
+ //CARP("retval - %d", retval);
+ if (retval == EOF) {
+ //Source = "";
+ Error[0] = '\0';
+ return 0;
+ } else if (retval == 0) {
+ state = S_SYN_ERROR;
+ continue;
+ }
+ byte = bytes[0];
+ case S_PREFIX:
+ // Process preffix byte (if any):
+ switch(byte) {
+ [%- FOREACH prefix IN idu.prefixes %]
+ case 0x[% prefix %]:
+ if (res->nprefs == NBYTES_MAX) {
+ state = S_TOO_MANY_PREF;
+ break;
+ }
+ res->prefix[res->nprefs++] = 0x[% prefix %];
+ [% IF prefix == '66' %]
+ res->bits16 = 1;
+ [% END %]
+ READ_BYTE
+ state = S_PREFIX;
+ break;
+ [%- END %]
+ default:
+ state = S_[% states.0.state_id %];
+ break;
+ }
+ break;
+ [%- FOREACH state IN states %]
+ case S_[% state.state_id %]:
+ [%- # Process the various fields (if any) -%]
+
+ [%- IF state.item('mod') OR state.modA %]
+ // Process the current ModR/M byte:
+ retval = process_ModRM(res, byte);
+ if (retval == EOF) {
+ state = S_END_ERROR;
+ break;
+ } else if (retval == 0) {
+ state = S_SYN_ERROR;
+ break;
+ }
+ [%- END -%]
+
+ [%- FOREACH bit IN idu.bit_fields %]
+ [%- NEXT UNLESS state.$bit.defined %]
+ // Get the [% bit %] field from the current byte:
+ res->[% bit %] = slice(byte, [% state.$bit %], [% state.$bit %]);
+ [%- END -%]
+
+ [%- FOREACH reg IN idu.reg_fields %]
+ [%- NEXT UNLESS state.$reg %]
+ // Get the [% reg %] field from the current byte:
+ res->[% reg %] = slice(byte, [% state.$reg.0
+ %], [% state.$reg.1 %]);
+ [%- END -%]
+
+ [%- IF state.imm == 'full' %]
+ // Get full immediate data:
+ len = res->bits16 ? 2 : 4;
+ READ_IMM_DATA(len)
+ [%- ELSIF state.imm == 'normal' %]
+ // Get immediate data:
+ len = get_imm_len(res->s, res->w, res->bits16);
+ READ_IMM_DATA(len)
+ [%- ELSIF state.imm == 'pointer' %]
+ // Get immediate data:
+ len = res->bits16 ? 4 : 6;
+ READ_IMM_DATA(len)
+ [%- ELSIF state.imm %]
+ [%- nbytes = state.imm / 8;
+ nbytes = Perl.int(nbytes) %]
+ // Get [% state.imm %]-bit immediate data:
+ [%- IF state.pattern and nbytes == 1 %]
+ res->imm[0] = byte;
+ res->imm_len = 1;
+ [%- ELSE %]
+ len = [% nbytes %];
+ READ_IMM_DATA(len)
+ [%- END -%]
+ [%- END %]
+
+ [%- # Determine the next state -%]
+
+ [%- IF state.next.0.pattern # Conditional switch %]
+ [%- UNLESS state == states.0 %]
+ READ_BYTE
+ [%- END -%]
+
+ [%- FOREACH next_state IN state.next %]
+ [%- regex = next_state.pattern %]
+ [% GET '} else ' UNLESS next_state == state.next.0
+ %]if (match(byte, "[% regex %]")) {
+ state = S_[% next_state.state %];
+ [%- END %]
+ } else {
+ state = S_SYN_ERROR;
+ }
+ [%- ELSIF state.next.0 # Unconditional switch %]
+ state = S_[% state.next.0.state %];
+ [%- ELSE # Reach the end of the instruction %]
+ res->ins = "[% state.ins.op_name %]";
+ res->des = "[% state.ins.des %]";
+ [%- IF state.ins.sub_des %]
+ res->subdes = "[% state.ins.sub_des %]";
+ [%- END %]
+ res->encoding = "[% state.ins.enco