diff --git a/80386/binary/bits_addr_l.py b/80386/binary/bits_addr_l.py new file mode 100644 index 0000000..1d1c267 --- /dev/null +++ b/80386/binary/bits_addr_l.py @@ -0,0 +1,186 @@ +bits=[ + [0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,], + [1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,], + [0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,], + [0,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,], + [1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,], + [0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,], + [0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,], + [1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,], + [0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,], + [0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,], + [0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,], + [0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,], + [1,0,0,1,0,0,0,0,1,1,1,0,0,0,0,0,], + [0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,], + [0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,0,], + [0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,0,1,0,0,0,0,0,0,0,1,0,0,0,], + [0,1,0,0,1,1,0,1,0,0,1,0,0,0,0,0,], + [0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,], + [0,0,0,0,0,0,0,0,1,1,1,0,1,0,0,0,], + [0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,], + [0,0,0,0,0,1,1,1,0,0,1,0,1,0,0,0,], + [0,1,1,1,0,0,1,0,1,1,0,0,0,0,0,0,], + [1,0,0,0,0,0,1,1,0,1,1,0,1,0,0,0,], + [1,0,0,1,0,0,1,0,1,1,0,0,1,0,0,0,], + [0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,1,], + [0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,], + [0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,], + [0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,1,1,0,1,0,0,0,1,0,0,1,], + [0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,], + [0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,], + [0,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,], + [0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,], + [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,1,1,1,0,0,0,0,0,0,1,0,0,], + [0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,], + [0,0,0,1,1,1,0,0,1,0,1,0,1,0,0,0,], + [0,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,], + [0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,], + [0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,], + [0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,], + [1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,], + [0,0,1,1,1,1,1,0,0,0,0,0,1,0,0,0,], + [0,0,1,1,1,0,1,0,0,0,1,0,1,0,0,0,], + [0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,], + [1,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,], + [1,1,0,0,1,0,1,1,1,0,0,0,0,0,0,0,], + [0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,0,0,0,1,0,1,0,1,0,1,0,0,0,], + [0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,0,], + [0,1,0,1,1,0,1,0,1,0,0,0,0,0,0,0,], + [0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,], + [1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,1,1,0,1,0,1,0,0,0,0,0,0,0,], + [0,0,0,0,1,1,1,1,1,1,0,0,1,0,0,0,], + [0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,1,0,1,1,1,1,0,0,0,0,0,0,0,], + [0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,], + [0,1,0,1,1,0,1,1,0,1,0,0,1,0,0,0,], + [1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,], + [0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,0,0,1,1,1,0,1,1,0,0,0,0,0,], + [1,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,], + [1,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,], + [0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,], + [0,0,1,1,1,0,1,0,1,1,0,0,0,0,0,0,], + [0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,], + [0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,], + [0,0,0,1,1,1,0,0,1,0,1,0,1,0,0,0,], + [0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,], + [0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,], + [0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,], + [0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,], + [0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,1,1,1,1,0,0,1,0,0,0,0,1,1,0,0,], + [0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,0,0,0,1,0,1,0,0,0,0,0,0,], + [1,1,1,0,1,0,1,1,0,0,1,0,1,0,0,0,], + [0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,], + [0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,], + [1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,], + [1,0,1,0,1,1,1,1,0,1,0,0,1,0,0,0,], + [0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,], + [1,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,1,0,1,0,0,0,1,0,1,0,0,0,], + [0,1,0,0,1,0,1,1,0,0,0,0,0,0,0,0,], + [0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,0,], + [0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,], + [0,0,1,1,1,0,1,1,0,0,0,0,0,0,0,0,], + [1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,], + [1,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,], + [1,0,0,0,1,0,0,1,0,0,0,0,1,1,0,0,], + [0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,], + [1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,1,0,1,1,0,1,1,0,0,0,0,0,0,], + [1,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,], + [0,0,1,1,1,1,0,0,1,0,1,0,1,0,0,0,], + [1,0,0,1,1,1,1,0,1,1,0,0,0,0,0,0,], + [0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,1,1,0,0,1,0,1,0,1,0,0,0,], + [1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,], + [1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,], + [1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,1,0,1,1,0,0,0,0,1,0,0,0,], + [1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,], + [1,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,], + [1,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,], + [0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,], + [0,0,1,0,1,1,1,0,0,1,0,0,0,0,0,0,], + [0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,], + [1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,], + [0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,], + [1,0,0,1,1,0,1,1,1,1,0,0,0,0,0,0,], + [0,0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,], + [1,0,0,0,1,1,1,0,1,1,0,0,0,0,0,0,], + [1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,], + [0,1,0,0,1,1,1,1,1,1,1,0,0,1,0,0,], + [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0,], + [0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,], + [0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,], + [0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,], + [0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,], + [0,0,1,0,1,1,0,0,1,0,0,0,1,0,0,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,], + [0,0,1,1,0,0,0,0,1,0,0,0,1,0,0,0,], + [1,1,1,0,0,0,1,0,0,1,0,0,0,0,0,0,], + [1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,], + [0,0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,], + [0,0,1,1,1,1,0,0,1,0,0,1,0,0,0,0,], + [1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,1,0,0,1,0,0,0,0,0,1,0,0,1,], + [1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], +] diff --git a/80386/binary/bits_addr_r.py b/80386/binary/bits_addr_r.py new file mode 100644 index 0000000..911a7fe --- /dev/null +++ b/80386/binary/bits_addr_r.py @@ -0,0 +1,186 @@ +bits=[ + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,0,1,1,1,0,1,0,0,0,0,1,0,0,0,], + [0,1,1,0,1,1,0,1,0,0,0,0,0,0,0,0,], + [0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,1,0,0,1,0,0,1,1,0,0,0,0,0,0,], + [0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,], + [1,1,0,1,1,1,1,0,1,1,0,0,0,0,0,0,], + [1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,1,1,1,1,0,1,0,0,1,1,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,1,0,1,0,1,1,0,0,1,0,1,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,1,1,0,1,1,1,0,1,0,0,0,1,0,0,0,], + [1,1,0,1,1,0,0,1,0,0,0,0,0,1,0,0,], + [1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,0,1,0,1,1,1,0,0,1,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,], + [1,0,1,1,1,1,0,1,1,0,0,0,1,0,0,0,], + [1,1,1,0,0,1,1,1,0,1,1,0,0,0,0,0,], + [1,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,], + [0,1,0,1,0,1,1,1,0,1,1,0,1,0,0,0,], + [0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,1,0,1,1,1,1,0,0,0,0,0,0,0,], + [1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,1,0,0,1,1,1,0,1,0,0,0,0,0,0,], + [0,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,], + [1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,], + [0,1,0,1,0,0,0,1,1,1,0,0,0,0,0,0,], + [1,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,], + [1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,], + [1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,1,1,1,1,0,1,1,1,0,0,0,0,0,0,], + [0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,1,0,1,0,1,0,1,1,0,1,0,0,0,], + [1,1,0,0,1,1,1,0,0,1,1,0,1,1,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,], + [1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,], + [0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,], + [1,0,0,1,1,1,1,1,1,1,1,0,0,1,0,0,], + [0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,], + [1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,0,1,1,0,1,0,1,1,0,0,0,0,0,], + [0,1,1,0,1,1,0,1,1,1,0,0,0,0,0,0,], + [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,], + [0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,], + [0,1,0,0,1,1,1,0,0,0,0,0,1,1,0,0,], + [0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,], + [1,1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,], + [1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,1,0,1,1,0,0,0,0,0,0,1,0,0,0,], + [0,0,0,1,0,1,1,0,1,0,0,0,0,0,0,0,], + [1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,], + [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,1,1,1,1,0,1,0,0,1,0,0,0,0,0,0,], + [1,0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,], + [0,1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,0,1,1,1,0,1,1,0,0,0,0,0,], + [1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,], + [0,0,1,0,0,1,1,1,0,1,1,0,1,0,0,0,], + [1,0,0,0,1,1,0,1,0,0,0,0,1,0,0,1,], + [0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,0,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [0,1,1,0,1,1,0,1,0,0,0,0,0,0,0,0,], + [1,1,0,0,1,1,0,1,1,0,0,0,0,0,0,0,], + [1,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,], + [1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,], + [0,1,1,0,0,1,0,1,1,1,0,0,0,0,0,0,], + [1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,], + [1,1,0,0,1,0,1,1,0,0,1,0,1,0,0,0,], + [1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,], + [1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,1,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [0,1,0,1,1,0,1,1,1,1,0,0,0,0,0,0,], + [1,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,], + [1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,], + [1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [1,0,0,1,0,0,1,1,0,0,0,0,1,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,], + [1,1,1,0,0,1,0,1,0,0,0,0,1,1,0,0,], + [0,1,0,1,1,0,0,0,0,0,0,0,1,0,0,0,], + [0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,], + [1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,], + [1,0,1,0,1,1,1,0,0,0,0,0,0,1,0,0,], + [0,1,0,1,1,0,0,1,0,0,0,0,0,1,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [0,1,0,1,1,1,1,0,0,1,0,0,0,0,0,0,], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,1,], + [1,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,], + [1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,], + [0,0,0,0,0,1,1,1,0,0,1,0,1,0,0,0,], + [1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,], + [0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,], + [1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,], + [0,1,0,0,0,1,0,1,0,0,0,0,1,1,0,0,], + [0,1,1,0,1,0,1,1,0,1,0,0,0,1,0,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,], + [0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,], + [1,0,0,0,1,0,0,1,1,1,0,0,0,0,0,0,], + [1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,], + [0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,], + [0,1,1,0,0,0,0,1,0,0,0,0,1,1,0,0,], + [0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,], + [1,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,], + [1,1,1,0,0,1,0,0,0,0,0,1,0,0,0,0,], + [0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,], + [1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [1,0,1,0,0,1,0,1,1,0,0,0,0,0,0,0,], + [1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,], + [0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,0,], + [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,], +] diff --git a/80386/binary/bits_l.py b/80386/binary/bits_l.py new file mode 100644 index 0000000..a923437 --- /dev/null +++ b/80386/binary/bits_l.py @@ -0,0 +1,186 @@ +bits=[ + [0,0,1,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,1,0,1,0,], + [0,0,1,0,1,0,1,0,0,1,1,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,], + [0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,0,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,1,1,0,1,0,0,1,1,0,0,1,1,0,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,], + [0,0,0,1,1,0,1,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,1,0,0,1,], + [0,0,1,0,1,0,1,0,0,0,1,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,0,0,1,0,1,1,0,0,1,], + [0,0,1,0,1,0,0,1,0,1,0,1,1,0,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,0,1,0,1,1,0,0,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,], + [0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,0,1,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,1,0,0,1,], + [0,0,0,1,1,0,1,0,0,1,1,0,1,0,1,0,1,0,0,0,0,1,1,0,0,1,], + [0,0,0,1,1,0,1,0,0,1,0,1,0,1,1,0,0,1,0,0,0,1,0,1,1,0,], + [0,0,0,1,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,], + [0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,], + [0,0,1,0,0,1,0,0,1,0,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,], + [0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,0,1,], + [0,0,1,0,1,0,0,1,1,0,0,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,1,0,], + [1,0,0,1,0,1,1,0,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,1,0,], + [0,0,0,1,0,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,0,1,0,0,1,], + [0,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,1,0,1,0,0,0,1,0,0,1,], + [0,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,], + [0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,0,1,0,1,0,1,0,1,0,0,1,1,0,0,1,], + [0,0,0,1,1,0,1,0,0,1,0,0,1,0,1,0,1,0,0,1,0,1,1,0,0,1,], + [0,0,0,1,1,0,1,0,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,1,0,1,0,0,1,], + [0,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,], + [0,0,0,1,1,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1,1,0,0,1,], + [0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,1,0,1,0,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,], + [0,0,0,1,1,0,0,0,0,1,0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,0,0,1,1,0,0,1,1,0,0,1,1,0,1,0,], + [0,0,0,1,0,1,0,1,0,0,0,1,1,0,0,1,1,0,1,0,0,0,1,0,0,1,], + [0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,1,1,0,1,0,0,1,1,0,0,1,], + [0,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,0,0,0,1,0,1,0,0,], + [0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,0,1,], + [0,0,0,1,1,0,1,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,], + [0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,1,0,], + [0,1,0,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,1,0,1,0,1,0,], + [0,0,0,0,1,0,0,1,1,0,0,1,0,1,0,1,1,0,1,0,0,0,1,0,1,0,], + [0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,1,1,0,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,0,1,1,0,0,1,0,1,1,0,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,0,0,1,0,0,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,], + [0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,], + [0,0,1,0,1,0,0,1,1,0,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,1,1,0,0,1,0,1,1,0,1,0,], + [0,0,1,0,0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,0,], + [0,0,0,1,0,1,0,1,1,0,0,1,1,0,0,1,0,1,0,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,1,0,1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,1,0,1,1,0,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,0,0,0,1,0,0,1,0,1,1,0,], + [0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,1,0,1,], + [0,0,0,1,1,0,1,0,0,1,0,0,0,1,0,1,1,0,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,0,1,], + [0,0,1,0,0,1,0,1,0,1,0,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,], + [0,0,0,1,1,0,1,0,0,1,0,1,0,1,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,0,1,], + [0,0,0,1,1,0,0,1,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,0,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,], + [1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,1,0,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,], + [0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,1,1,0,0,1,], + [0,0,1,0,0,1,1,0,0,1,0,1,1,0,0,1,1,0,0,1,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,], + [0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,1,], + [0,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,1,0,0,1,0,1,1,0,0,1,], + [0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,1,0,1,0,0,1,0,1,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,0,1,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,], + [0,0,0,1,1,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,1,0,1,0,1,0,1,0,0,1,1,0,0,0,1,0,0,1,], + [0,0,0,1,1,0,0,1,1,0,1,0,1,0,0,1,0,1,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,1,0,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,], + [0,0,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,1,1,0,0,1,1,0,], + [0,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,0,0,1,], + [0,0,0,1,1,0,0,1,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,1,0,], + [0,0,0,0,0,1,0,1,1,0,0,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,0,1,0,0,0,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,], + [0,1,0,1,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,1,0,0,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,], + [0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,1,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,], + [0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,1,1,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,1,0,], + [0,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,0,1,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1,1,0,], + [0,0,1,0,1,0,1,0,0,0,0,0,1,0,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,0,], + [0,0,0,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,0,1,1,0,0,1,1,0,0,1,0,1,1,0,1,0,], + [0,0,0,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,1,0,0,], + [0,0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,0,1,1,0,1,0,1,0,1,0,], + [0,0,0,1,0,1,0,1,1,0,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,0,0,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,1,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,1,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,1,0,], + [0,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,1,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,0,1,0,1,0,], + [0,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,1,1,0,1,0,0,1,0,1,0,0,0,0,0,1,0,1,1,0,], + [0,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,1,0,0,0,1,0,0,0,1,0,], + [0,0,0,1,0,1,1,0,0,1,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,1,], + [0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,0,0,1,1,0,0,1,0,1,0,1,1,0,1,0,], + [0,0,0,1,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,0,0,1,0,0,1,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,0,1,0,0,1,0,0,1,0,1,0,1,0,1,1,0,1,0,], + [0,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,1,0,1,0,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,0,1,0,0,1,1,0,1,0,], + [0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,1,0,1,], + [0,0,0,1,0,1,0,1,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,1,0,0,1,1,0,0,1,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,1,0,1,0,1,0,], + [0,0,0,1,1,0,0,1,0,1,1,0,0,1,1,0,0,1,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,0,0,1,0,1,0,1,0,0,1,], + [0,0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,1,1,0,0,1,], + [0,0,0,1,0,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,0,1,0,1,0,1,1,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,0,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,0,0,0,0,0,1,0,1,], + [1,0,0,1,0,1,1,0,1,0,0,1,1,0,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,1,0,1,0,1,0,], + [0,0,0,1,1,0,0,1,0,1,0,1,0,1,1,0,0,1,0,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,], + [0,0,0,1,0,1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,1,0,1,1,0,1,0,0,0,0,1,0,1,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,1,0,0,0,1,0,1,0,1,0,], + [0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,1,0,0,], + [0,0,0,1,0,1,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,1,0,], + [0,0,0,1,0,1,0,1,0,1,1,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,1,0,0,1,0,0,1,], + [0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,1,0,1,0,1,0,1,0,], + [0,0,0,1,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,1,0,1,1,0,0,1,], + [0,0,0,1,0,1,1,0,0,1,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,], + [0,0,0,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,], + [0,0,0,1,0,1,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,1,0,1,0,1,0,0,1,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,1,0,1,0,], + [0,0,0,1,0,1,0,1,0,1,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,1,0,1,1,0,1,0,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,1,0,1,0,], + [0,0,0,1,1,0,0,1,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,1,0,0,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,], +] diff --git a/80386/binary/bits_r.py b/80386/binary/bits_r.py new file mode 100644 index 0000000..a3df395 --- /dev/null +++ b/80386/binary/bits_r.py @@ -0,0 +1,186 @@ +bits=[ + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], + [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,1,0,0,0,], + [0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,], + [0,0,1,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,], + [0,0,1,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,], + [0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,1,], + [0,0,0,1,0,1,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,1,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,0,1,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,1,0,], + [0,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,1,], + [0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,], + [0,0,1,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,1,1,0,0,1,], + [0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,0,0,1,], + [0,0,0,1,0,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,0,0,0,1,1,0,1,0,1,0,0,0,0,0,1,0,1,0,], + [0,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,], + [0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,], + [0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,], + [0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1,0,1,0,], + [0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,], + [0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,1,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,0,1,], + [0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,1,0,1,0,0,1,], + [0,0,0,1,0,1,1,0,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,1,0,], + [0,0,0,1,0,1,0,0,1,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,1,], + [0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,1,0,1,0,1,1,0,1,0,1,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,0,1,], + [0,0,0,1,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,1,], + [0,0,1,0,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,], + [0,0,0,1,0,1,0,1,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,1,0,0,0,0,1,1,0,0,0,1,0,1,0,1,0,1,0,], + [0,0,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,0,0,0,0,1,1,0,0,0,1,0,1,0,1,0,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,1,0,], + [0,0,1,0,0,1,1,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0,0,0,1,], + [0,0,1,0,0,1,1,0,0,0,0,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,1,0,1,0,1,0,0,0,0,1,], + [0,0,0,1,1,0,1,0,0,1,0,1,1,0,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,1,0,], + [0,0,0,1,0,1,1,0,1,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,1,0,1,1,0,0,0,1,0,1,0,], + [0,0,1,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,1,0,1,0,0,1,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,0,], + [0,0,0,1,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,1,0,0,1,], + [0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,0,0,1,0,1,1,0,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,0,0,0,1,0,0,1,0,1,0,1,0,0,1,0,0,1,], + [0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,], + [0,0,0,0,0,0,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,1,], + [0,0,0,0,0,1,0,0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,], + [0,0,1,0,1,0,0,1,1,0,0,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,1,0,1,0,1,0,0,1,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,1,0,1,0,0,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,1,0,1,0,0,1,1,0,1,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,1,], + [0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,], + [0,0,1,0,0,1,0,1,0,1,0,1,1,0,0,0,1,0,0,0,0,0,1,0,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0,0,], + [0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,1,], + [0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,], + [0,0,0,1,0,1,0,0,0,0,0,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,], + [0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,1,0,1,1,0,1,0,0,1,], + [0,0,0,1,0,1,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,1,1,0,0,1,1,0,0,1,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,0,1,], + [0,0,0,1,1,0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,0,0,0,0,1,1,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,], + [0,0,1,0,0,1,0,1,0,0,0,1,1,0,0,0,1,0,0,0,1,0,1,0,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,0,1,0,1,1,0,1,0,0,1,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,1,0,1,1,0,0,0,], + [0,0,1,0,1,0,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,], + [0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,], + [0,0,1,0,0,0,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,1,0,1,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,1,0,0,1,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,1,1,0,0,1,], + [0,0,1,0,0,1,0,0,0,1,0,1,1,0,0,0,1,0,0,0,1,0,1,0,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,], + [0,0,0,1,1,0,0,1,0,0,0,1,1,0,0,0,1,0,0,1,0,0,1,0,0,1,], + [0,0,0,1,1,0,0,1,0,0,0,0,0,1,0,1,1,0,1,0,1,0,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,0,1,0,1,0,], + [0,0,0,1,0,1,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0,1,0,1,1,0,], + [0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,0,0,1,1,0,0,0,1,0,1,0,], + [0,0,0,1,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,0,1,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,1,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,], + [0,0,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,], + [0,0,0,0,0,1,0,1,0,0,0,0,0,1,1,0,0,1,1,0,0,0,1,0,1,0,], + [0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,], + [0,0,0,1,1,0,1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,0,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,0,1,1,0,0,1,1,0,1,0,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,1,], + [0,0,0,0,1,0,1,0,1,0,0,0,0,1,1,0,1,0,0,0,0,0,0,1,0,0,], + [0,0,0,1,1,0,0,1,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,], + [0,0,0,1,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0,1,0,0,1,], + [0,0,0,1,0,1,0,1,1,0,0,1,0,1,1,0,0,0,0,0,1,0,0,1,1,0,], + [0,0,0,0,1,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,1,0,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,1,1,0,1,0,], + [0,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,], + [0,0,0,1,0,1,0,0,1,0,0,0,1,0,0,1,0,1,0,0,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,0,1,0,0,1,0,1,1,0,0,1,0,0,0,0,1,0,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,0,0,1,0,1,1,0,0,1,0,1,1,0,0,0,1,0,0,1,0,1,1,0,], + [0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,0,1,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,], + [0,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,0,1,1,0,0,0,0,1,0,1,0,0,1,0,0,1,1,0,1,0,], + [0,0,1,0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,1,], + [0,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,1,1,0,0,1,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,], + [0,0,0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,0,0,1,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,0,1,0,1,0,0,1,0,0,0,0,0,1,0,1,], + [0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,1,0,1,], + [0,0,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,1,0,], + [0,0,0,1,0,1,1,0,1,0,0,1,0,1,0,1,1,0,0,0,0,0,0,1,1,0,], + [0,0,0,1,1,0,0,1,1,0,0,1,0,1,1,0,0,0,0,0,0,0,0,1,1,0,], + [0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,1,1,0,0,1,0,0,1,0,1,0,], + [0,0,0,0,1,0,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,1,0,], + [0,0,1,0,0,1,0,1,1,0,0,0,1,0,0,1,0,1,1,0,0,0,1,0,1,0,], + [0,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,0,], + [0,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,], + [0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,1,0,1,0,], + [0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,], +] diff --git a/80386/binary/image (3).raw b/80386/binary/image (3).raw new file mode 100644 index 0000000..e4c4d64 Binary files /dev/null and b/80386/binary/image (3).raw differ diff --git a/80386/binary/pla4_input_new.txt b/80386/binary/pla4_input_new.txt new file mode 100644 index 0000000..a3ca16b --- /dev/null +++ b/80386/binary/pla4_input_new.txt @@ -0,0 +1,160 @@ +10..001.0.101110 +1...010001.11110 +11..0001..101000 +....010001.11101 +.....0011.011.11 +.....1011.011.11 +1...011000011110 +01........111010 +1...010000011110 +1...01.001011110 +....111101100100 +1...011010011110 +.....011..0000.1 +1...011010101001 +1...011010101100 +....011000011101 +....010000011101 +......0111011011 +101.100...101101 +.....11101011011 +10..101.0.100011 +....1..1..11010. +1...11.011101001 +1...11.011101100 +....01.001011101 +1...11101.101001 +1...11101.101100 +....011010011101 +1...01.110101001 +1...01.110101100 +....11.100100001 +101.100...10101. +1...1110.0011110 +1...010011101001 +1...010011101100 +....111101100101 +1...011011101001 +1...011011101100 +....1......10100 +1...1.....1111.1 +10..101.0.10.110 +.....001.1011011 +....11.1101000.0 +10..100...100111 +..........010010 +..........010100 +....1.....01100. +..........010001 +..........010000 +10..100...101011 +1...11.110101001 +....1.....110.11 +1...11.110101100 +....1......10111 +101.000...101010 +1...1000..100111 +10..001.0.100011 +....10000.101111 +....1.....011111 +....1110.0011101 +01.....1..011010 +101.000...101101 +1...1000..101101 +01....1...011010 +....01.110100000 +....1.....11111. +....01110110010. +1...11.00.011110 +......0110011011 +....01.100100001 +..........01001. +....01.110100010 +1...100...101000 +1...1000..10101. +10..001.0.10.110 +11..1.....111101 +....11.00.011101 +1......011001111 +.....111.0011011 +10..000...100111 +1.....1.10001111 +1...10..0.101111 +1...101...101111 +.....111..000110 +.....1100.011011 +1.....110.001111 +.....011..000110 +10..000...101011 +1...0000..101010 +1...0000..100111 +....00000.101111 +1...0000..101011 +1...0000..101101 +.....111..000010 +.....0000.0011.1 +.....111..000011 +1....01.0.00110. +1.....110.001110 +.....111..000100 +.....011..000100 +.....11.1.011011 +.....011..00001. +1...000...101000 +1......1.0001111 +.....000..001111 +.....0....000001 +1...00..0.101111 +1...001...101111 +.....1....000001 +1......1.0001110 +1....0..0.0011.1 +.....000..001110 +1....01...0011.1 +....0.....010111 +.....0....000000 +1....0....001111 +......0.0.00.011 +....0.....111111 +01........11110. +....0.....110111 +....0.....01100. +.....1....000000 +.1........110011 +.1........110110 +.......0..110010 +.....1....101010 +1....0....001110 +..........010101 +.1........111100 +....0.....110010 +1.........111010 +......0...0001.0 +....0.....110100 +.......0..0001.0 +.......0..110101 +....0.....110011 +.1........111011 +....1.....111011 +.....1....101101 +....0.....111000 +......0...000.1. +.......0..000.1. +.......0..11100. +....0.....11.110 +....0.....11.101 +....0.....111.01 +....0.....11110. +..........011111 +................ +................ +................ +................ +................ +................ +................ +................ +................ +................ +................ +................ diff --git a/80386/binary/pla4_output_new.txt b/80386/binary/pla4_output_new.txt new file mode 100644 index 0000000..355006a --- /dev/null +++ b/80386/binary/pla4_output_new.txt @@ -0,0 +1,160 @@ +100000000000000000 +000010010000000000 +110010000100000000 +000010010000000000 +000010000000000000 +000000100000000000 +000011000011000110 +001000000000000000 +000000110011000110 +000001000011000110 +000000001110000111 +000000111000111010 +000010000000000000 +000000111000111010 +000000111000111010 +000011000011000110 +000000110011000110 +000001000110000110 +000000001110000111 +000001000110000110 +000001010110000111 +010000000000000000 +000000001110000111 +000000001110000111 +000001000011000110 +000000001110000111 +000000001110000111 +000000111000111010 +000011000010111010 +000011000010111010 +000000001110000111 +000000001110000111 +000010001110000111 +000001111101101010 +000001111101101010 +000010111010000111 +000010111101101010 +000010111101101010 +010000000000000000 +010000000000000000 +000001010110000111 +000001000110000110 +000000001110000111 +000000001110000111 +100000000000000000 +010000000000000000 +010000000000000000 +100100000000000000 +000000000000000001 +000000001110000111 +000000010111111011 +010000000000000000 +000000010111111011 +010000000000000000 +000110101011101010 +000000001110000111 +000101011011101010 +000000001110000111 +000000010000000000 +000010001110000111 +000000010101011010 +000110101011101010 +000000001110000111 +000000010101011010 +000011001011101010 +010000000000000000 +000010101011101010 +000010001110000111 +000001011010000110 +000011001011101010 +001000000000000000 +000011111000111010 +000000001110000111 +000000001110000111 +000110101011101010 +000001100001011010 +000010001110000111 +000001011000111010 +000011011010000110 +000110101011101010 +000001011000111010 +000000001110000111 +000000001110000111 +000000010111001010 +000001111010000110 +000001011000111010 +000000111000101010 +000101011011101010 +000110101011101010 +000110101011101010 +000110101011101010 +000101011011101010 +000110101011101010 +000010110010101010 +000001011000111010 +000001110010101010 +000001011000111010 +000001110111011010 +000011100111001010 +000001110111001010 +000011011010000110 +000000101010101010 +000101011011101010 +000001011000111010 +000001011000111010 +000010010010001010 +000110101011101010 +000110101011101010 +000010001010001010 +000001110111011010 +000001011000111010 +000001110111011010 +000001011000111010 +000001001001101010 +000010101101001010 +000001011000111010 +000001101100101010 +000001001001101010 +000010111010000111 +000001110110000110 +000001001001101010 +000011011101001010 +000010111010000111 +000010111010000111 +000010111010000111 +000000011101101010 +000001110111011010 +000010100110000111 +000010111010000111 +000010100111111010 +000011001101011010 +000001101100101010 +000010100111111010 +000001101100101010 +000010111010000111 +000010111010000111 +000011011010000111 +000011011010000111 +000011001101101010 +000010111011011010 +000001101100101010 +000001101100101010 +000010111010000111 +000010111010000111 +000010111010000111 +000010111010000111 +000010111010000111 +000010101111011010 +000000000000000000 +000000000000000000 +000000000000000000 +000000000000000000 +000000000000000000 +000000000000000000 +000000000000000000 +000000000000000000 +000000000000000000 +000000000000000000 +000000000000000000 +000000000000000000 diff --git a/80386/binary/rom1_input_new.txt b/80386/binary/rom1_input_new.txt new file mode 100644 index 0000000..eb72b60 --- /dev/null +++ b/80386/binary/rom1_input_new.txt @@ -0,0 +1,177 @@ +....10000011100000. +....01100011100000. +....00110100000000. +....01110101000000. +....0110011.100000. +....01100110.00000. +....0101.100100000. +....01111011.00000. +....01111111.00000. +....1.00001100000.. +....01001101000000. +....0110011010000.. +....0111.000100000. +....0011010.100000. +....01110.0.000000. +....11010.00.00000. +.....100000.100000. +....01110100.00000. +....011.0100000000. +....0.001100.00000. +....11011.11.00000. +....01100.01000000. +....01101011.00000. +....0111010..00000. +....01010100.00000. +....1001000..00000. +....0000..11000000. +....01100.01.00000. +.....000100..00000. +....000...10100000. +....00001.11.00000. +....0111001..00000. +....0000.011.00000. +....00.10001.00000. +....01.00000.00000. +....01.00011.00000. +....110...01100000. +....0110100..00000. +....0100001..00000. +....100100..000000. +....0.11010.000000. +....010111...00000. +1.00.00......0011.1 +....01.00010.00000. +1.00.0000....00001. +....1..101.1000000. +....01101010.00000. +1.00.00......00111. +....0.11011..00000. +....11.10.0.000000. +....0101.00..00000. +....110..1.1100000. +.....1.1.0110000... +....110.0.10.00000. +....011011...00000. +....011100...00000. +....0.111.10.0000.. +....010001...00000. +....0.11110..0000.. +00...00......0011.1 +00...0000....00001. +....0...0.0110.0.0. +....0001..1.10000.. +....110.1..1.00000. +....110..01..00000. +....11.1..00.00000. +.............111110 +.....01..000.000.0. +.......01....000101 +00...00......00111. +1..1.01......0011.. +.....000.00..00000. +.......10....000101 +....0.000.0..00000. +....10....1.1000.0. +.....110.1.0.0..00. +1.1..00......00111. +01....0......00111. +....01.0.11..0..00. +....01011....00000. +...0.01......0011.. +....110.1.1..00000. +0....01......0011.. +....00111....00000. +1..1.01......00.10. +1..1.01......00.1.0 +.......00......0011 +1..1..0......00111. +.....1.0.1.1.0..00. +.............1111.0 +....01010....00000. +1.1..00......00.10. +1.1..00......00.1.0 +..1..........1.0010 +.............110010 +1..1.01......00001. +01....0......00.110 +....11001....00000. +...0.10......0011.. +.....11.01...0000.. +0....10......0011.. +...0.01......00.10. +...0.01......00.1.0 +....10.0..1..000.0. +0....01......00.10. +0....01......00.1.0 +....10.11....0000.. +1.1..00......00001. +1..1..0......00.10. +1..1..0......00.1.0 +.............001111 +...0.01......00001. +.....01......00111. +0....01......00001. +01....0......00.10. +...0.10......00.10. +...0.10......00.1.0 +1..1..0......00001. +0....10......00.10. +0....10......00.1.0 +.............1.0011 +....000...10.00000. +.....10.10...000... +.............11010. +01....0......00001. +....010.1....0000.. +....0010.....000.0. +...0.10......00001. +0....10......00001. +....11000....00000. +....000...0..00000. +.............10101. +.....10......00.1.0 +....10...1...000.0. +....1..1....1000... +.....10......00111. +.....11......0011.1 +.....1100....00001. +..0..........10001. +.............01.011 +.....10........001. +.....11......00111. +.............101..0 +.....10......00.10. +.............1110.. +..0..........1000.1 +.............1..11. +..............01100 +.............000110 +......11.....0..00. +.............0011.1 +...............0111 +.....00......0..00. +....1.1......00000. +.............1010.. +..1..........1.00.. +.............1100.. +.............1...00 +.............1..1.1 +........1....00001. +.......1.....00001. +.............01.0.1 +.............1.01.. +.............01.1.. +.............01.01. +.............01..0. +.............00010. +.............0010.. +................... +................... +................... +................... +................... +................... +................... +................... + diff --git a/80386/binary/rom1_output_new.txt b/80386/binary/rom1_output_new.txt new file mode 100644 index 0000000..7a806bc --- /dev/null +++ b/80386/binary/rom1_output_new.txt @@ -0,0 +1,176 @@ +000000100000 +010000000000 +110000000000 +111000000000 +000000100000 +000000100000 +010000000000 +010000000010 +001000000010 +000000010000 +011111100000 +000111000000 +100000100001 +011100010000 +000000100000 +000000001000 +010000000000 +011101000000 +001111000000 +000000010010 +000000010010 +010111000000 +100000000111 +000010100000 +000111010000 +001101000000 +100000001001 +000000100101 +000000000010 +010000000000 +100000001001 +000101000010 +100000001001 +101100000000 +001100000110 +001100000110 +001100010100 +101000000110 +100000010010 +101101000000 +000111000001 +010000000000 +100111000000 +101100000100 +100111010001 +100000000101 +100111010101 +000111011001 +100000000011 +100000000101 +000110000000 +001100010100 +100000000000 +001100010100 +101011000000 +100010000001 +100000010001 +101100000000 +100000010001 +100111000000 +100111010001 +100000000000 +100000010001 +001100000100 +001100000100 +100000000101 +001101000000 +100000000001 +000000100000 +000111011001 +000101000100 +101100000000 +000000100000 +001100000110 +000000000001 +100000000100 +010110011101 +010110010000 +100000000100 +000111000010 +000010000000 +101100000100 +000010000000 +100010010001 +000101000100 +100101000100 +010000000000 +010001011101 +000000000100 +000010000100 +100000000111 +000110000100 +100110000100 +110000000000 +110000000000 +000101010101 +100110001001 +101100010100 +000100000000 +000000000001 +000100000000 +000010000000 +100010000000 +100000000001 +000010000000 +100010000000 +100000000001 +000110010101 +000001000100 +100001000100 +010000000000 +000010010001 +010000011001 +000010010001 +000110000000 +000100000000 +100100000000 +000001010101 +000100000000 +100100000000 +010000000000 +100111010011 +100000000000 +011000000000 +000110010001 +100000000001 +100000010001 +000100010001 +000100010001 +011111010101 +101100010010 +010000000000 +000010000000 +100000000001 +100000000000 +010010011001 +100111000000 +100111010001 +000111000000 +110000000000 +000010000000 +000111011001 +100000000000 +000010000000 +100000000100 +100111000000 +000000000100 +100000001001 +100000001001 +000000000100 +000000011001 +100000000100 +000000000100 +100000000101 +000010000000 +000110000000 +000110000000 +100000000000 +100000000100 +100000010001 +100000010001 +000111000000 +100000000100 +100000000100 +000111000100 +100000000100 +100000010001 +100000000100 +000000000000 +000000000000 +000000000000 +000000000000 +000000000000 +000000000000 +000000000000 +000000000000 diff --git a/80386/constant_rom.txt b/80386/constant_rom.txt new file mode 100644 index 0000000..ddb5e4e --- /dev/null +++ b/80386/constant_rom.txt @@ -0,0 +1,112 @@ +00002000 +00037bbf +3ddc04f0 +0000000f +000f0000 +00001000 +fffffff7 +00000040 +80005550 +80005540 +00000051 +00001151 +00008008 +00005557 +00001500 +00001505 +ffff0000 +00000014 +00001015 +00000005 +00000441 +00000041 +00001400 +0000557f +00000155 +00001411 +00000015 +00000055 +00000010 +00000100 +00000001 +00000004 +fffffffa +0000ffff +ffffffff +fffffffe + +----------------fdb97531eca86420 +.................*.............. 00 00004000 19 CLTS, FSAVE, FRSTOR, LSL 3 +..............**.*********.*.*** 01 00037fd7 1b LLDT, LSL 2 +..****.***.***......**....*.**.. 02 3ddc0c2c 1d FSAVE, FRSTOR, LOADALL386 4 +......................**......** 03 00000303 1f FIADD, FIST, LTR, LOADALL386 5 +............****................ 04 000f0000 21 BOOTUP 1 +.........................*...... 05 00000040 23 11 +**********************.********* 06 fffffdff 25 16 +............................*... 07 00000008 27 9 CNST2C +*.......................******.. 08 800000fc 29 3 +*.......................*****... 09 800000f8 2b 9 +............................**.* 0a 0000000d 2d 5 CNST1C +.........................*.***.* 0b 0000005d 2f 2 +................*.....*......... 0c 00008200 31 13 +.......................********* 0d 000001ff 33 16 +.........................***.... 0e 00000070 35 3 +.........................***..** 0f 00000073 37 8 +****************................ 10 ffff0000 +.............................**. 11 00000006 CNST26 +.........................*...*** 12 00000047 18 67f, 765 1 +..............................** 13 00000003 1a PROT_MD_LFSLGS, BOOTUP 2 CNST25 +..........................*.*..* 14 00000029 1c 398, FSTENV, FLDENV, LSL 9 +............................*..* 15 00000009 1e FENI,FSTSW,FSAVE,FRSTOR,FIADD,FIST 3 +.........................**..... 16 00000060 20 LSL 2 +.....................*********** 17 000007ff 22 1 +...........................***** 18 0000001f 24 1 +.........................**..*.* 19 00000065 26 5 +.............................*** 1a 00000007 28 2 CNST24 +............................**** 1b 0000000f 2a 4 +.............................*.. 1c 00000004 2c 13 CNST33 +...........................*.... 1d 00000010 2e 3 CNST32 +...............................* 1e 00000001 30 43 CNST30 +..............................*. 1f 00000002 32 11 CNST31 +******************************.. 20 fffffffc 34 PUSHAd, WAIT, FRSTOR, LSL 10 +................**************** 21 0000ffff 36 39 CNST36 +******************************** 22 ffffffff +*******************************. 23 fffffffe + +...............................* 1e 00000001 +..............................*. 1f 00000002 +..............................** 13 00000003 +.............................*.. 1c 00000004 +.............................**. 11 00000006 +.............................*** 1a 00000007 +............................*... 07 00000008 +............................*..* 15 00000009 +............................**.* 0a 0000000d +............................**** 1b 0000000f +...........................*.... 1d 00000010 +...........................***** 18 0000001f +..........................*.*..* 14 00000029 +.........................*...... 05 00000040 +.........................*...*** 12 00000047 +.........................*.***.* 0b 0000005d +.........................**..... 16 00000060 +.........................**..*.* 19 00000065 +.........................***.... 0e 00000070 +.........................***..** 0f 00000073 +.......................********* 0d 000001ff +......................**......** 03 00000303 +.....................*********** 17 000007ff +.................*.............. 00 00004000 +................*.....*......... 0c 00008200 +................**************** 21 0000ffff +..............**.*********.*.*** 01 00037fd7 +............****................ 04 000f0000 +..****.***.***......**....*.**.. 02 3ddc0c2c +*.......................*****... 09 800000f8 +*.......................******.. 08 800000fc +****************................ 10 ffff0000 +**********************.********* 06 fffffdff +******************************.. 20 fffffffc +*******************************. 23 fffffffe +******************************** 22 ffffffff + diff --git a/80386/decode2.txt b/80386/decode2.txt new file mode 100644 index 0000000..de315c9 --- /dev/null +++ b/80386/decode2.txt @@ -0,0 +1,2559 @@ +00: alu rm,r excluding CMP +001D +001D +001D +001D +001D +001D +001D +001D + +01: +0 +0 +0 +0 +0 +0 +0 +0 + +02: +904A +904A +904A +904A +904A +904A +904A +904A + +03: +0 +0 +0 +0 +0 +0 +0 +0 + +04: +001D alu r,rm excluding CMP +001D +001D +001D +001D +001D +001D +001D + +05: +0 +0 +0 +0 +0 +0 +0 +0 + +06: +1027 +1027 +1027 +1027 +1027 +1027 +1027 +1027 + +07: +0 +0 +0 +0 +0 +0 +0 +0 + +08: +0 unused? +0 +0 +0 +0 +0 +0 +0 + +09: +0 +0 +0 +0 +0 +0 +0 +0 + +0A: +0 +0 +0 +0 +0 +0 +0 +0 + +0B: +0 +0 +0 +0 +0 +0 +0 +0 + +0C: +0 IMUL rm,rmv +0 +0 +0 +0 +0 +0 +0 + +0D: +01B3 +01B3 +01B3 +01B3 +01B3 +01B3 +01B3 +01B3 + +0E: +0 +0 +0 +0 +0 +0 +0 +0 + +0F: +11BD +11BD +11BD +11BD +11BD +11BD +11BD +11BD + +10: +001F CMP rm,r +001F +001F +001F +001F +001F +001F +001F + +11: +0 +0 +0 +0 +0 +0 +0 +0 + +12: +1035 +1035 +1035 +1035 +1035 +1035 +1035 +1035 + +13: +0 +0 +0 +0 +0 +0 +0 +0 + +14: +001F CMP r,rm +001F +001F +001F +001F +001F +001F +001F + +15: +0 +0 +0 +0 +0 +0 +0 +0 + +16: +102C +102C +102C +102C +102C +102C +102C +102C + +17: +0 +0 +0 +0 +0 +0 +0 +0 + +18: alu rm,i +0023 +0023 +0023 +0023 +0023 +0023 +0023 +0025 + +19: +0 +0 +0 +0 +0 +0 +0 +0 + +1A: +9039 +9039 +9039 +9039 +9039 +9039 +9039 +1031 + +1B: +0 +0 +0 +0 +0 +0 +0 +0 + +1C: +001F TEST rm,r +001F +001F +001F +001F +001F +001F +001F + +1D: +0 +0 +0 +0 +0 +0 +0 +0 + +1E: +1035 +1035 +1035 +1035 +1035 +1035 +1035 +1035 + +1F: +0 +0 +0 +0 +0 +0 +0 +0 + +20: +00B6 XCHG rm,r +00B6 +00B6 +00B6 +00B6 +00B6 +00B6 +00B6 + +21: +0 +0 +0 +0 +0 +0 +0 +0 + +22: +90B1 +90B1 +90B1 +90B1 +90B1 +90B1 +90B1 +90B1 + +23: +0 +0 +0 +0 +0 +0 +0 +0 + +24: +01C4 IMUL rv,rmv,i +01C4 +01C4 +01C4 +01C4 +01C4 +01C4 +01C4 + +25: +0 +0 +0 +0 +0 +0 +0 +0 + +26: +11C1 +11C1 +11C1 +11C1 +11C1 +11C1 +11C1 +11C1 + +27: +0 +0 +0 +0 +0 +0 +0 +0 + +28: +0003 MOV rm,r +0003 +0003 +0003 +0003 +0003 +0003 +0003 + +29: +0003 +0003 +0003 +0003 +0003 +0003 +0003 +0003 + +2A: +1013 +1013 +1013 +1013 +1013 +1013 +1013 +1013 + +2B: +1013 +1013 +1013 +1013 +1013 +1013 +1013 +1013 + +2C: +0003 MOV r,rm +0003 +0003 +0003 +0003 +0003 +0003 +0003 + +2D: +0003 +0003 +0003 +0003 +0003 +0003 +0003 +0003 + +2E: +1019 +1019 +1019 +1019 +1019 +1019 +1019 +1019 + +2F: +1019 +1019 +1019 +1019 +1019 +1019 +1019 +1019 + +30: MOV segreg,rmw real +0009 MOV ES,rmw real +082B illegal MOV CS,rmw real +0009 MOV SS,rmw real +0009 MOV DS,rmw real +0009 MOV FS,rmw real +0009 MOV GS,rmw real +082B illegal +082B illegal + +31: +0 +0 +0 +0 +0 +0 +0 +0 + +32: +100F MOV ES,rmw +082B illegal MOV CS,rmw +100B MOV SS,rmw +100F MOV DS,rmw +100F MOV FS,rmw +100F MOV GS,rmw +082B illegal +082B illegal + +33: +0 +0 +0 +0 +0 +0 +0 +0 + +34: MOV(ZX) rmv,segreg +0007 MOV rmw,ES +0007 MOV rmw,CS +0007 MOV rmw,SS +0007 MOV rmw,DS +0007 MOV rmw,FS +0007 MOV rmw,GS +082B illegal +082B illegal + +35: +0 +0 +0 +0 +0 +0 +0 +0 + +36: +1017 MOV rmw,ES +1017 MOV rmw,CS +1017 MOV rmw,SS +1017 MOV rmw,DS +1017 MOV rmw,FS +1017 MOV rmw,GS +082B illegal +082B illegal + +37: +0 +0 +0 +0 +0 +0 +0 +0 + +38: MOV segreg,rmw protected +0580 MOV ES,rmw protected +082B illegal MOV CS,rmw protected +0585 MOV SS,rmw protected +0580 MOV DS,rmw protected +0580 MOV FS,rmw protected +0580 MOV GS,rmw protected +082B illegal +082B illegal + +39: +0 +0 +0 +0 +0 +0 +0 +0 + +3A: +100F MOV ES,rmw protected +082B illegal MOV CS,rmw protected +100B MOV SS,rmw protected +100F MOV DS,rmw protected +100F MOV FS,rmw protected +100F MOV GS,rmw protected +082B illegal +082B illegal + +3B: +0 +0 +0 +0 +0 +0 +0 +0 + +3C: +0 unused? +0 +0 +0 +0 +0 +082B illegal +082B illegal + +3D: +0 +0 +0 +0 +0 +0 +0 +0 + +3E: +0 +0 +0 +0 +0 +0 +082B illegal +082B illegal + +3F: +0 +0 +0 +0 +0 +0 +0 +0 + +40: POP mv +309F POP rmv? +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +41: +0 +0 +0 +0 +0 +0 +0 +0 + +42: +30AC POP rmv? +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +43: +0 +0 +0 +0 +0 +0 +0 +0 + +44: MOV rm,i +0005 +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +45: +0 +0 +0 +0 +0 +0 +0 +0 + +46: +1015 +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +47: +0 +0 +0 +0 +0 +0 +0 +0 + +48: +0 MOV TRn,rd +0 +0 +0 +0 +0 +0 +0 + +49: +082B illegal +082B illegal +082B illegal +082B illegal +0391 TR4 +0391 TR5 +0391 TR6 +0391 TR7 + +4A: +0 +0 +0 +0 +0 +0 +0 +0 + +4B: +082B illegal +082B illegal +082B illegal +082B illegal +0391 TR4 +0391 TR5 +0391 TR6 +0391 TR7 + +4C: +06B6 ARPL rmw,rw protected +06B6 +06B6 +06B6 +06B6 +06B6 +06B6 +06B6 + +4D: +0 +0 +0 +0 +0 +0 +0 +0 + +4E: +16AA +16AA +16AA +16AA +16AA +16AA +16AA +16AA + +4F: +0 +0 +0 +0 +0 +0 +0 +0 + +50: misc rmb +0021 INC +0021 DEC +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +51: +0 +0 +0 +0 +0 +0 +0 +0 + +52: +904E INC +904E DEC +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +53: +0 +0 +0 +0 +0 +0 +0 +0 + +54: misc rmv +0021 +0021 +2079 +082B illegal +006D +082B illegal +2086 +082B illegal + +55: +0 +0 +0 +0 +0 +0 +0 +0 + +56: +904E INC +904E DEC +107C CALL rmv +12DA CALL FAR m +106F JMP rmv +12F5 JMP FAR m +1081 PUSH rmv +082B illegal + +57: +0 +0 +0 +0 +0 +0 +0 +0 + +58: math rm +0025 TEST +0025 TEST +0021 NOT +0021 NEG +01A5 MUL +01A5 IMUL +01C7 DIV +01D3 IDIV + +59: +0 +0 +0 +0 +0 +0 +0 +0 + +5A: +1031 TEST +1031 TEST +904E NOT +904E NEG +11AF MUL +11AF IMUL +11CF DIV +11E1 IDIV + +5B: +0 +0 +0 +0 +0 +0 +0 +0 + +5C: +0 MOV rd,TRn +0 +0 +0 +0 +0 +0 +0 + +5D: +082B illegal +082B illegal +082B illegal +082B illegal +03B6 TR4 +03B6 TR5 +03B6 TR6 +03B6 TR7 + +5E: +0 +0 +0 +0 +0 +0 +0 +0 + +5F: +082B illegal +082B illegal +082B illegal +082B illegal +03B6 TR4 +03B6 TR5 +03B6 TR6 +03B6 TR7 + +60: rot rm,ib +00F9 +00F9 +00E5 +00E5 +00F9 +00F9 +00F9 +00F9 + +61: +0 +0 +0 +0 +0 +0 +0 +0 + +62: +111E +111E +1108 +1108 +111E +111E +111E +111E + +63: +0 +0 +0 +0 +0 +0 +0 +0 + +64: rot rm,1 +0105 +0105 +0105 +0105 +0105 +0105 +0105 +0105 + +65: +0 +0 +0 +0 +0 +0 +0 +0 + +66: +112A +112A +112A +112A +112A +112A +112A +112A + +67: +0 +0 +0 +0 +0 +0 +0 +0 + +68: rot rm,CL +00FF +00FF +00E9 +00E9 +00FF +00FF +00FF +00FF + +69: +0 +0 +0 +0 +0 +0 +0 +0 + +6A: +112D +112D +110C +110C +112D +112D +112D +112D + +6B: +0 +0 +0 +0 +0 +0 +0 +0 + +6C: BT rv/m,rv +0 +0 +0 +0 +0 +0 +0 +0 + +6D: +0131 +0131 +0131 +0131 +0131 +0131 +0131 +0131 + +6E: +0 +0 +0 +0 +0 +0 +0 +0 + +6F: +1134 +1134 +1134 +1134 +1134 +1134 +1134 +1134 + +70: BT/BTS/BTR/BTC rv/m,ib +0 +0 +0 +0 +0 +0 +0 +0 + +71: +082B illegal +082B illegal +082B illegal +082B illegal +013F TR4 +015A TR5 +015A TR6 +015A TR7 + +72: +0 +0 +0 +0 +0 +0 +0 +0 + +73: +082B illegal +082B illegal +082B illegal +082B illegal +1142 TR4 +9160 TR5 +9160 TR6 +9160 TR7 + +74: BTS/BTR/BTC rv/m,rv +0 +0 +0 +0 +0 +0 +0 +0 + +75: +0147 +0147 +0147 +0147 +0147 +0147 +0147 +0147 + +76: +0 +0 +0 +0 +0 +0 +0 +0 + +77: +914D +914D +914D +914D +914D +914D +914D +914D + +78: LFS/LGS rv,m +0 +0 +0 +0 +0 +0 +0 +0 + +79: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +7A: +0 +0 +0 +0 +0 +0 +0 +0 + +7B: +10D0 +10D0 +10D0 +10D0 +10D0 +10D0 +10D0 +10D0 + +7C: ARPL/SLDT/STR/LLT/LTR/VERR/VERW/LAR/LSL real mode +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +7D: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +7E: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +7F: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +80: SLDT/STR/LLT/LTR/VERR/VERW rmw +0 +0 +0 +0 +0 +0 +0 +0 + +81: +06E2 +06CF +06D6 +06C3 +0703 +0709 +082B illegal +082B illegal + +82: +0 +0 +0 +0 +0 +0 +0 +0 + +83: +16E0 +16CD +16D1 +16BE +1700 +1706 +082B illegal +082B illegal + +84: INC/DEC rv SGDT/SIDT/LGDT/LIDT/SMSW/LMSW rmw +0 +0 +0 +0 +0 +0 +0 +0 + +85: +082B illegal +082B illegal +082B illegal +082B illegal +0358 +082B illegal +034E +082B illegal + +86: +0 +0 +0 +0 +0 +0 +0 +0 + +87: +0340 +033D +1332 +132E +135A +082B illegal +1349 +082B illegal + +88: LAR rv,rmv protected +0 +0 +0 +0 +0 +0 +0 +0 + +89: +06E7 +06E7 +06E7 +06E7 +06E7 +06E7 +06E7 +06E7 + +8A: +0 +0 +0 +0 +0 +0 +0 +0 + +8B: +16E4 +16E4 +16E4 +16E4 +16E4 +16E4 +16E4 +16E4 + +8C: LSL rv,rmv alu A,i excluding CMP +0 +0 +0 +0 +0 +0 +0 +0 + +8D: +06EC +06EC +06EC +06EC +06EC +06EC +06EC +06EC + +8E: +0 +0 +0 +0 +0 +0 +0 +0 + +8F: +16EA +16EA +16EA +16EA +16EA +16EA +16EA +16EA + +90: IBTS rmv,eAX,CL,rv +0 +0 +0 +0 +0 +0 +0 +0 + +91: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +92: +0 +0 +0 +0 +0 +0 +0 +0 + +93: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +94: XBTS rv,rmv,eAX,CL CMP/TEST A,i +0 +0 +0 +0 +0 +0 +0 +0 + +95: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +96: +0 +0 +0 +0 +0 +0 +0 +0 + +97: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +98: SHxD rmv,rv,ib +0 +0 +0 +0 +0 +0 +0 +0 + +99: +00FC +00FC +00FC +00FC +00FC +00FC +00FC +00FC + +9A: +0 +0 +0 +0 +0 +0 +0 +0 + +9B: +1124 +1124 +1124 +1124 +1124 +1124 +1124 +1124 + +9C: SHxD rmv,rv,CL +0 +0 +0 +0 +0 +0 +0 +0 + +9D: +0102 +0102 +0102 +0102 +0102 +0102 +0102 +0102 + +9E: +0 +0 +0 +0 +0 +0 +0 +0 + +9F: +112F +112F +112F +112F +112F +112F +112F +112F + +A0: ESC? +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 + +A1: +0 +0 +0 +0 +0 +0 +0 +0 + +A2: +14D7 +14D7 +14D7 +14D7 +14D7 +14D7 +14D7 +14D7 + +A3: +0 +0 +0 +0 +0 +0 +0 +0 + +A4: ESC? +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 + +A5: +0 +0 +0 +0 +0 +0 +0 +0 + +A6: +14E0 +14E0 +14E0 +14E0 +14E0 +14E0 +14E0 +14E0 + +A7: +0 +0 +0 +0 +0 +0 +0 +0 + +A8: ESC? +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 + +A9: +0 +0 +0 +0 +0 +0 +0 +0 + +AA: +14DB +04C1 +1540 +1540 +145C +04C1 +13F0 +03D9 + +AB: +0 +0 +0 +0 +0 +0 +0 +0 + +AC: ESC? +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 + +AD: +0 +0 +0 +0 +0 +0 +0 +0 + +AE: +14D7 +04C1 +153C +153C +1459 +14DF +13ED +03D9 + +AF: +0 +0 +0 +0 +0 +0 +0 +0 + +B0: ESC? +04C1 +04C1 +04C1 +04C1 +03DA +03DA +03DA +03DA + +B1: +0 +0 +0 +0 +0 +0 +0 +0 + +B2: +14E0 +04C1 +1544 +1544 +14D3 +14DB +1538 +1540 + +B3: +0 +0 +0 +0 +0 +0 +0 +0 + +B4: SETcond rmb +0 +0 +0 +0 +0 +0 +0 +0 + +B5: +003D +003D +003D +003D +003D +003D +003D +003D + +B6: +0 +0 +0 +0 +0 +0 +0 +0 + +B7: +1043 +1043 +1043 +1043 +1043 +1043 +1043 +1043 + +B8: MOVZX/MOVSX r,rm (16-bit?) +0 +0 +0 +0 +0 +0 +0 +0 + +B9: +01E8 +01E8 +01E8 +01E8 +01E8 +01E8 +01E8 +01E8 + +BA: +0 +0 +0 +0 +0 +0 +0 +0 + +BB: +11EB +11EB +11EB +11EB +11EB +11EB +11EB +11EB + +BC: MOVZX/MOVSX r,rm (32-bit?) +0 +0 +0 +0 +0 +0 +0 +0 + +BD: +01F0 +01F0 +01F0 +01F0 +01F0 +01F0 +01F0 +01F0 + +BE: +0 +0 +0 +0 +0 +0 +0 +0 + +BF: +11F3 +11F3 +11F3 +11F3 +11F3 +11F3 +11F3 +11F3 + +C0: BSF rv,rmv +0 +0 +0 +0 +0 +0 +0 +0 + +C1: +0168 +0168 +0168 +0168 +0168 +0168 +0168 +0168 + +C2: +0 +0 +0 +0 +0 +0 +0 +0 + +C3: +1177 +1177 +1177 +1177 +1177 +1177 +1177 +1177 + +C4: BSR rv,rmv +0 +0 +0 +0 +0 +0 +0 +0 + +C5: +017A +017A +017A +017A +017A +017A +017A +017A + +C6: +0 +0 +0 +0 +0 +0 +0 +0 + +C7: +1184 +1184 +1184 +1184 +1184 +1184 +1184 +1184 + +C8: MOV CRn,rd +0 +0 +0 +0 +0 +0 +0 +0 + +C9: +035C CR0 +082B illegal +0368 CR2 +036C CR3 +082B illegal +082B illegal +082B illegal +082B illegal + +CA: +0 +0 +0 +0 +0 +0 +0 +0 + +CB: +035C CR0 +082B illegal +0368 CR2 +036C CR3 +082B illegal +082B illegal +082B illegal +082B illegal + +CC: MOV rd,CRn +0 +0 +0 +0 +0 +0 +0 +0 + +CD: +0371 CR0 +082B illegal +0377 CR2 +0379 CR3 +082B illegal +082B illegal +082B illegal +082B illegal + +CE: +0 +0 +0 +0 +0 +0 +0 +0 + +CF: +0371 CR0 +082B illegal +0377 CR2 +0379 CR3 +082B illegal +082B illegal +082B illegal +082B illegal + +D0: MOV DRn,rd +0 +0 +0 +0 +0 +0 +0 +0 + +D1: +038A +038A +038A +038A +037B +037F +037B +037F + +D2: +0 +0 +0 +0 +0 +0 +0 +0 + +D3: +038A +038A +038A +038A +037B +037F +037B +037F + +D4: MOV rd,DRn +0 +0 +0 +0 +0 +0 +0 +0 + +D5: +03AE +03AE +03AE +03AE +03A6 +03AA +03A6 +03AA + +D6: +0 +0 +0 +0 +0 +0 +0 +0 + +D7: +03AE +03AE +03AE +03AE +03A6 +03AA +03A6 +03AA + +D8: ESC? +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 +04C1 + +D9: +0 +0 +0 +0 +0 +0 +0 +0 + +DA: +14DB +14DB +14DB +14DB +14DB +14DB +14DB +14DB + +DB: +0 +0 +0 +0 +0 +0 +0 +0 + +DC: ESC? +03CD +03CD +03CD +03CD +03CD +03CD +03CD +03CD + +DD: +0 +0 +0 +0 +0 +0 +0 +0 + +DE: +14D7 +04C1 +153C +153C +04C1 +14D3 +0 +1538 + +DF: +0 +0 +0 +0 +0 +0 +0 +0 + +E0: LEA rv,m +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +E1: +0 +0 +0 +0 +0 +0 +0 +0 + +E2: +10B9 +10B9 +10B9 +10B9 +10B9 +10B9 +10B9 +10B9 + +E3: +0 +0 +0 +0 +0 +0 +0 +0 + +E4: LES +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +E5: +0 +0 +0 +0 +0 +0 +0 +0 + +E6: +10C2 +10C2 +10C2 +10C2 +10C2 +10C2 +10C2 +10C2 + +E7: +0 +0 +0 +0 +0 +0 +0 +0 + +E8: LDS +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +E9: +0 +0 +0 +0 +0 +0 +0 +0 + +EA: +10BB +10BB +10BB +10BB +10BB +10BB +10BB +10BB + +EB: +0 +0 +0 +0 +0 +0 +0 +0 + +EC: BOUND rv,m2v +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +ED: +0 +0 +0 +0 +0 +0 +0 +0 + +EE: +1818 +1818 +1818 +1818 +1818 +1818 +1818 +1818 + +EF: +0 +0 +0 +0 +0 +0 +0 +0 + +F0: LSS rv,m +0 +0 +0 +0 +0 +0 +0 +0 + +F1: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +F2: +0 +0 +0 +0 +0 +0 +0 +0 + +F3: +10C9 +10C9 +10C9 +10C9 +10C9 +10C9 +10C9 +10C9 + +F4: unused? +0849 +0849 +0849 +0849 +0849 +0849 +0849 +0849 + +F5: +0849 +0849 +0849 +0849 +0849 +0849 +0849 +0849 + +F6: +0849 +0849 +0849 +0849 +0849 +0849 +0849 +0849 + +F7: +0849 +0849 +0849 +0849 +0849 +0849 +0849 +0849 + +F8: unused? +0844 +0844 +0844 +0844 +0844 +0844 +0844 +0844 + +F9: +0844 +0844 +0844 +0844 +0844 +0844 +0844 +0844 + +FA: +0844 +0844 +0844 +0844 +0844 +0844 +0844 +0844 + +FB: +0844 +0844 +0844 +0844 +0844 +0844 +0844 +0844 + +FC: unused? +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +FD: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +FE: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal + +FF: +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal +082B illegal diff --git a/80386/decoder23.txt b/80386/decoder23.txt new file mode 100644 index 0000000..1d12a54 --- /dev/null +++ b/80386/decoder23.txt @@ -0,0 +1,538 @@ +?000000001?01 0000000000000000 +?0001?0001?01 0000000000000000 +?001?00001?01 0000000000000000 +?00?010001?01 0000000000000000 +?000000010?01 0000000000000000 +?0001?0010?01 0000000000000000 +?0010?0010?01 0000000000000000 +?001110010?0? 0000000000000000 +?001110011?00 0000000000000000 +?00000001??00 0000000000000000 +?0001?001??00 0000000000000000 +?001?0001??00 0000000000000000 +?00?01001??00 0000000000000000 +?0000100?0?01 0000000000000000 +?0011000?0?01 0000000000000000 +?0000001???01 0000000000000000 +?0001?01???01 0000000000000000 +?0010?01???01 0000000000000000 +?00001100??01 0000000000000000 +?00110100??01 0000000000000000 +?000011111?00 0000000000000000 +?000001111?0? 0000000000000000 +?0001?1111?0? 0000000000000000 +?0010?1111?0? 0000000000000000 +?0000011?0?01 0000000000000000 +?0001?11?0?01 0000000000000000 +?0010?11?0?01 0000000000000000 +?000001?01?01 0000000000000000 +?0001?1?01?01 0000000000000000 +?0010?1?01?01 0000000000000000 +?00000?000?01 0000000000000000 +?0001??000?01 0000000000000000 +?0010??000?01 0000000000000000 +?00111?00??01 0000000000000000 +?00001?1???01 0000000000000000 +?0011??1???01 0000000000000000 +?01???0000?01 0000000000000000 +?01???0010?00 0000000000000000 +?01???0011?01 0000000000000000 +?01???0101?01 0000000000000000 +?01???0111?00 0000000000000000 +?01???01?0?01 0000000000000000 +?010001011?00 0000000000000000 +?01?011011?00 0000000000000000 +?01?1?1011?00 0000000000000000 +?011001011?00 0000000000000000 +?01???10?0?01 0000000000000000 +?010001101?00 0000000000000000 +?01?011101?00 0000000000000000 +?01?1?1101?00 0000000000000000 +?011001101?00 0000000000000000 +?0100011?0?00 0000000000000000 +?01?0111?0?00 0000000000000000 +?01?1?11?0?00 0000000000000000 +?0110011?0?00 0000000000000000 +?01????001?01 0000000000000000 +?100000000100 0000000000000000 +?10???0001?00 0000000000000000 +?1000?0100?00 0000000000000000 +?1001?0?00?00 0000000000000000 +?101??0?00?00 0000000000000000 +?10???1001?01 0000000000000000 +?10???101??01 0000000000000000 +?10???1?00?01 0000000000000000 +?10????101?00 0000000000000000 +?10????11??00 0000000000000000 +?111?00000000 0000000000000000 +?11?000000100 0000000000000000 +?1101?0000?00 0000000000000000 +?111?10000?00 0000000000000000 +?11110000?100 0000000000000000 +?11???011??01 0000000000000000 +?1111001?1100 0000000000000000 +?111100?01000 0000000000000000 +?110010?01?00 0000000000000000 +?1101?0?01?00 0000000000000000 +?111?10?01?00 0000000000000000 +?11?000?01?00 0000000000000000 +?11???10???01 0000000000000000 +?11????100?00 0000000000000000 +?1?0000000000 0000000000000000 +?1?0010000?00 0000000000000000 +?1????001??00 0000000000000000 + +.abRRRcdefg0i +?00???101?00? 0000000000000011 MOV rm,r / MOV r,rm rm = register +?010000001000 0000000000000101 MOV rm,i rm = register +?0001?1101000 0000000000000111 MOV(ZX) rmv,SS/DS rm = register +?00?0?1101000 0000000000000111 MOV(ZX) rmv,ES/CS/FS/GS rm = register +?000001100000 0000000000001001 MOV ES,rmw real rm = register +?0001?1100000 0000000000001001 MOV SS/DS,rmw real rm = register +?0010?1100000 0000000000001001 MOV FS/GS,rmw real rm = register +?0001011?0100 0001000000001011 MOV SS,rmw rm = memory +?0000011?0100 0001000000001111 MOV ES,rmw rm = memory +?0001111?0100 0001000000001111 MOV DS,rmw rm = memory +?0010?11?0100 0001000000001111 MOV FS/GS,rmw rm = memory +?00???101010? 0001000000010011 MOV rm,r rm = memory +?010000001100 0001000000010101 MOV rm,i rm = memory +?0001?1101100 0001000000010111 MOV(ZX) rmv,SS/DS rm = memory +?00?0?1101100 0001000000010111 MOV(ZX) rmv,ES/CS/FS/GS rm = memory +?00???101110? 0001000000011001 MOV r,rm rm = memory +?00???000?000 0000000000011101 alu rm<->r excluding CMP rm = register +?00???0100000 0000000000011111 CMP rm,r rm = register +?00???01?1000 0000000000011111 CMP r,rm / TEST rm,r rm = register +?0100?010?000 0000000000100001 INC/DEC rm rm = register +?0101?0110000 0000000000100001 NOT/NEG rm rm = register +?000000110000 0000000000100011 ADD rm,i rm = register +?0001?0110000 0000000000100011 ADC/SBB rm,i rm = register +?001?00110000 0000000000100011 AND/XOR rm,i rm = register +?00?010110000 0000000000100011 OR/SUB rm,i rm = register +?001110110000 0000000000100101 CMP rm,i rm = register +?0100?0110000 0000000000100101 TEST rm,i rm = register +?00???0001100 0001000000100111 alu r,rm excluding CMP rm = memory +?00???0101100 0001000000101100 CMP r,rm rm = memory +?001110110100 0001000000110001 CMP rm,i rm = memory +?0100?0110100 0001000000110001 TEST rm,i rm = memory +?00???0100100 0001000000110101 CMP rm,r rm = memory +?00???0111100 0001000000110101 TEST rm,r rm = memory +?000000110100 1001000000111001 ADD rm,i rm = memory +?0001?0110100 1001000000111001 ADC/SBB rm,i rm = memory +?001?00110100 1001000000111001 AND/XOR rm,i rm = memory +?00?010110100 1001000000111001 AND/XOR rm,i rm = memory +?10???1101001 0000000000111101 SETcond rmb rm = register +?10???1101101 0001000001000011 SETcond rmb rm = memory +?00???0000100 1001000001001010 alu rm,r excluding CMP rm = memory +?0100?010?100 1001000001001110 INC/DEC rm rm = memory +?0101?0110100 1001000001001110 NOT/NEG rm rm = memory +?011000101000 0000000001101101 JMP rmv rm = register +?011000101100 0001000001101111 JMP rmv rm = memory +?010100101000 0010000001111001 CALL rmv rm = register +?010100101100 0001000001111100 CALL rmv rm = memory +?011100101100 0001000010000001 PUSH rmv rm = memory +?011100101000 0010000010000110 PUSH rmv rm = register +?010000000000 0011000010011111 POP rmv rm = register +?010000000100 0011000010101100 POP rmv rm = memory +?00???1000100 1001000010110001 XCHG rm,r rm = memory +?00???1000000 0000000010110110 XCHG rm,r rm = register +?11???1000100 0001000010111001 LEA rv,m rm = memory +?11???1010100 0001000010111011 LDS rv,m rm = memory +?11???1001100 0001000011000010 LES rv,m rm = memory +?11???1100101 0001000011001001 LSS rv,m rm = memory +?01???1110101 0001000011010000 LFS/LGS rv,m rm = memory +?0101?1000000 0000000011100101 RCL/RCR rm,ib rm = register +?0101?1010000 0000000011101001 RCL/RCR rm,CL rm = register +?0100?1000000 0000000011111001 ROL/ROR rm,ib rm = register +?011??1000000 0000000011111001 SHL/SHR/SAR rm,ib rm = register +?10???0110001 0000000011111100 SHxD rmv,rv,ib rm = register +?0100?1010000 0000000011111111 ROL/ROR rm,CL rm = register +?011??1010000 0000000011111111 SHL/SHR/SAR rm,CL rm = register +?10???0111001 0000000100000010 SHxD rmv,rv,CL rm = register +?01???1001000 0000000100000101 rot rm,1 rm = register +?0101?1000100 0001000100001000 RCL/RCR rm,ib rm = memory +?0101?1010100 0001000100001100 RCL/RCR rm,CL rm = memory +?0100?1000100 0001000100011110 ROL/ROR rm,ib rm = memory +?011??1000100 0001000100011110 SHL/SHR/SAR rm,ib rm = memory +?10???0110101 0001000100100100 SHxD rmv,rv,ib rm = memory +?01???1001100 0001000100101010 rot rm,1 rm = memory +?0100?1010100 0001000100101101 ROL/ROR rm,CL rm = memory +?011??1010100 0001000100101101 SHL/SHR/SAR rm,CL rm = memory +?10???0111101 0001000100101111 SHxD rmv,rv,CL rm = memory +?01???1011001 0000000100110001 BT rv/m,rv rm = register +?01???1011101 0001000100110100 BT rv/m,rv rm = memory +?011001100001 0000000100111111 BT rv/m,ib rm = register +?011001100101 0001000101000010 BT rv/m,ib rm = memory +?01???1101001 0000000101000111 BTS/BTR/BTC rv/m,rv rm = register +?01???1101101 1001000101001101 BTS/BTR/BTC rv/m,rv rm = memory +?011011100001 0000000101011010 BTS rv/m,ib rm = register +?0111?1100001 0000000101011010 BTR/BTC rv/m,ib rm = register +?011011100101 1001000101100000 BTS rv/m,ib rm = memory +?0111?1100101 1001000101100000 BTR/BTC rv/m,ib rm = memory +?11???0000001 0000000101101000 BSF rv,rmv rm = register +?11???0000101 0001000101110111 BSF rv,rmv rm = memory +?11???0001001 0000000101111010 BSR rv,rmv rm = register +?11???0001101 0001000110000100 BSR rv,rmv rm = memory +?0110?0110000 0000000110100101 MUL/IMUL rm rm = register +?0110?0110100 0001000110101111 MUL/IMUL rm rm = memory +?00???0011001 0000000110110011 IMUL rm,rmv rm = register +?00???0011101 0001000110111101 IMUL rm,rmv rm = memory +?00???1001100 0001000111000001 IMUL rv,rmv,i rm = memory +?00???1001000 0000000111000100 IMUL rv,rmv,i rm = register +?011100110000 0000000111000111 DIV rm rm = register +?011100110100 0001000111001111 DIV rm rm = memory +?011110110000 0000000111010011 IDIV rm rm = register +?011110110100 0001000111100001 IDIV rm rm = memory +?10???1110001 0000000111101000 MOVZX/MOVSX r,rm (16-bit?) rm = register +?10???1110101 0001000111101011 MOVZX/MOVSX r,rm (16-bit?) rm = memory +?10???1111001 0000000111110000 MOVZX/MOVSX r,rm (32-bit?) rm = register +?10???1111101 0001000111110011 MOVZX/MOVSX r,rm (32-bit?) rm = memory +?010110101100 0001001011011010 CALL mp rm = memory +?011010101100 0001001011110101 JMP mp rm = memory +?100110001101 0001001100101110 LIDT rmw rm = memory +?100100001101 0001001100110010 LGDT rmw rm = memory +?100010001101 0000001100111101 SIDT rmw rm = memory +?100000001101 0000001101000000 SGDT rmw rm = memory +?101100001101 0001001101001001 LMSW rmw rm = memory +?101100001001 0000001101001110 LMSW rmw rm = register +?101000001001 0000001101011000 SMSW rmw rm = register +?101000001101 0001001101011010 SMSW rmw rm = memory +?110000010?01 0000001101011100 MOV CR0,rd +?110100010?01 0000001101101000 MOV CR2,rd +?110110010?01 0000001101101100 MOV CR3,rd +?110000011?01 0000001101110001 MOV rd,CR0 +?110100011?01 0000001101110111 MOV rd,CR2 +?110110011?01 0000001101111001 MOV rd,CR3 +?111?00100?01 0000001101111011 MOV DR4/6,rd +?111?10100?01 0000001101111111 MOV DR5/7,rd +?110??0100?01 0000001110001010 MOV DR0-3,rd +?011??0010?01 0000001110010001 MOV TRn,rd +?111?00101?01 0000001110100110 MOV rd,DR4/6 +?111?10101?01 0000001110101010 MOV rd,DR5/7 +?110??0101?01 0000001110101110 MOV rd,DR0-3 +?011??0111?01 0000001110110110 MOV rd,TRn +?11???0111000 0000001111001101 ESC 3 rm = register FENI/FDISI/FCLEX/FINIT/FSETPM/FRSTPM +?10111101?100 0000001111011001 ESC 5/1,7 rm = memory FSTCW/FSTSW mw +?101??1100000 0000001111011010 ESC 7,4-7 rm = register FSTSW AX/FNSTDW/FNSTSG +?101101011100 0001001111101101 ESC 1,6 rm = memory FSTENV m +?101101010100 0001001111110000 ESC 5,6 rm = memory FSAVE m +?101001011100 0001010001011001 ESC 1,4 rm = memory FLDENV m +?101001010100 0001010001011100 ESC 5,4 rm = memory FRSTOR m +?100??1001000 0000010011000001 ESC 6,0-3 rm = register FADDP/FMULP/FCOMP/??? STi,ST0 +?10?011010100 0000010011000001 ESC 5,1/5 rm = memory unknown fp op? +?100011011?00 0000010011000001 ESC 1,1 FXCH ST0,STi +?10000101?000 0000010011000001 ESC 5/1,0 rm = register FLD STi/FFREE STi +?1001?101?000 0000010011000001 ESC 5/1,2-3 rm = register FCOM/FCOMP STi +?1000110?0000 0000010011000001 ESC 0/2/5,1 rm = register FMUL/FXCH ST0,STi +?101??10??000 0000010011000001 ESC 0/2/6/5/1,4-7 rm = register FSUB/FSUBR/FDIV/FDIVR ST0,STi / FCHS/FABS/FTST/FXAM/FLD1/FLD1/FLDL2T/FLDL2E/FLDPI/FLDLG2/FLDLN2/FLDZ/F2XM1/FYL2X/FPTAN/FPATAN/FXTRACT/FPREM1/FDECSTP/FINCSTP/FPREM/FYL2XP1/FSQRT/FSINCOS/FRNDINT/FSCALE/FSIN/FCOS/FUCOMPP / FUCOM/FUCOMP STi / FSUBRP/FSUBP/FDIVRP/FDIVP STi,ST0 +?100011100?00 0000010011000001 ESC 7,1 FXCH ST0,STi +?100001?00000 0000010011000001 ESC 0/2/7,0 rm = register +?1001?1?00000 0000010011000001 ESC 0/2/7,2-3 rm = register +?11???0110000 0000010011000001 ESC 4 rm = register FADD/FMUL/FCOM/FCOMP/FSUBR/FSUB/FDIVR/FDIV STi,ST0 +?110010111100 0000010011000001 ESC 3,1 rm = memory unknown fp op? +?111000111100 0000010011000001 ESC 3,4 rm = memory unknown fp op? +?101001100100 0001010011010011 ESC 7,4 rm = memory FBLD mt +?111010111100 0001010011010011 ESC 3,5 rm = memory FLD mt +?10???1000100 0001010011010111 ESC 0/2 rm = memory FADD/FMUL/FCOM/FCOMP/FSUB/FSUBR/FDIV/FDIVR/FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR md +?100001011100 0001010011010111 ESC 1,0 rm = memory FLD md +?110000111100 0001010011010111 ESC 3,0 rm = memory FILD md +?100001010100 0001010011011011 ESC 5,0 rm = memory FLD mq +?101011100100 0001010011011011 ESC 7,5 rm = memory FILD mq +?11???0110100 0001010011011011 ESC 4 rm = memory FADD/FMUL/FCOM/FCOMP/FSUBR/FSUB/FDIVR/FDIV mq +?101011011100 0001010011011111 ESC 1,5 rm = memory FLDCW mw +?10???1001100 0001010011100000 ESC 6 rm = memory FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR mw +?100001100100 0001010011100000 ESC 7,0 rm = memory FILD mw +?101101100100 0001010100111000 ESC 7,6 rm = memory FBSTP mt +?111110111100 0001010100111000 ESC 3,7 rm = memory FSTP mt +?1001?1011100 0001010100111100 ESC 1,2-3 rm = memory FST/FSTP md +?1101?0111100 0001010100111100 ESC 3,2-3 rm = memory FIST/FISTP md +?1001?1010100 0001010101000000 ESC 5,2-3 rm = memory FST/FSTP mq +?101111100100 0001010101000000 ESC 7,7 rm = memory FISTP mq +?1001?1100100 0001010101000100 ESC 7,2-3 rm = memory FIST/FISTP mw +?000001110000 0000010110000000 MOV ES,rmw protected rm = register +?000111110000 0000010110000000 MOV DS,rmw protected rm = register +?0010?1110000 0000010110000000 MOV FS/GS,rmw protected rm = register +?000101110000 0000010110000101 MOV SS,rmw protected rm = register +?01???0011100 0001011010101010 ARPL rmw,rw protected rm = memory +?01???0011000 0000011010110110 ARPL rmw,rw protected rm = register +?100110000101 0001011010111110 LTR rmw rm = memory +?100110000001 0000011011000011 LTR rmw rm = register +?100010000101 0001011011001101 STR rmw rm = memory +?100010000001 0000011011001111 STR rmw rm = register +?100100000101 0001011011010001 LLDT rmw rm = memory +?100100000001 0000011011010110 LLDT rmw rm = register +?100000000101 0001011011100000 SLDT rmw rm = memory +?100000000001 0000011011100010 SLDT rmw rm = register +?10???0010101 0001011011100100 LAR rv,rmv protected rm = memory +?10???0010001 0000011011100111 LAR rv,rmv protected rm = register +?10???0011101 0001011011101010 LSL rv,rmv rm = memory +?10???0011001 0000011011101100 LSL rv,rmv rm = register +?101000000101 0001011100000000 VERR rmw rm = memory +?101000000001 0000011100000011 VERR rmw rm = register +?101010000101 0001011100000110 VERW rmw rm = memory +?101010000001 0000011100001001 VERW rmw rm = register +?11???1011100 0001100000011000 BOUND rv,m2v rm = memory +?0000111?0?00 0000100000101011 illegal? +?0011?11???00 0000100000101011 illegal? +?0101?0000000 0000100000101011 illegal? +?0110?0000000 0000100000101011 illegal? +?010100000100 0000100000101011 illegal? +?011000000100 0000100000101011 illegal? +?010010000?00 0000100000101011 illegal? +?0101?0001?00 0000100000101011 illegal? +?011?00001?00 0000100000101011 illegal? +?01?010001?00 0000100000101011 illegal? +?010??0010?01 0000100000101011 illegal? +?010100100?00 0000100000101011 illegal? +?011000100?00 0000100000101011 illegal? +?01011010?000 0000100000101011 illegal? +?01101010?000 0000100000101011 illegal? +?010110?00100 0000100000101011 illegal? +?011010?00100 0000100000101011 illegal? +?011100?00?00 0000100000101011 illegal? +?011110?0??00 0000100000101011 illegal? +?010??1100101 0000100000101011 illegal? +?011??1110001 0000100000101011 illegal? +?011??1111?01 0000100000101011 illegal? +?010??11?0001 0000100000101011 illegal? +?010???111?01 0000100000101011 illegal? +?101100000?01 0000100000101011 illegal? +?100??0001001 0000100000101011 illegal? +?101010001?01 0000100000101011 illegal? +?10111000??01 0000100000101011 illegal? +?1000?010??01 0000100000101011 illegal? +?1010?010??01 0000100000101011 illegal? +?10?1?010??01 0000100000101011 illegal? +?11001001??01 0000100000101011 illegal? +?111??001??01 0000100000101011 illegal? +?11???10??000 0000100000101011 illegal? +?11???1100001 0000100000101011 illegal? +?11???1111?01 0000100000101011 illegal? +??1???1111?00 0000100000101011 illegal? +?11???1110?0? 0000100001000100 unused? +?11???1101?0? 0000100001001001 unused? + +?0000000???10 0000000000000000 ADD rm,r 00 +?0001?00???10 0000000000000000 ADC/SBB rm,r +?001?000???10 0000000000000000 AND/XOR rm,r +?00?0100???10 0000000000000000 OR/SUB rm,r +?00001111??10 0000000000000000 0F prefix +?001??110??10 0000000000000000 ES:/CS:/SS:/DS: +?0110010???10 0000000000000000 FS:/GS: +?0110011???10 0000000000000000 operand size prefix, address size prefix +?1111001???10 0000000000000000 REP/REPNE +?11110000??10 0000000000000000 LOCK +?0000001???10 0000000000000001 ADD r,rm 04 +?0001?01???10 0000000000000001 ADC/SBB r,rm +?001?001???10 0000000000000001 AND/XOR r,rm +?00?0101???10 0000000000000001 OR/SUB r,rm +?10101111??11 0000000000000011 IMUL rm,rmv 0c +?0011100???10 0000000000000100 CMP rm,r 10 +?0011101???10 0000000000000101 CMP r,rm 14 +?1011??????10 0000000000000101 MOV r,i +?100000????10 0000000000000110 alu rm,i 18 +?1000010???10 0000000000000111 TEST rm,r 1c +?1000011???10 0000000000001000 XCHG rm,r 20 +?011010?1??10 0000000000001001 IMUL rv,rmv,i 24 +?1000100???10 0000000000001010 MOV rm,r 28 +?0001000???11 0000000000001010 UMOV rm,r +?1000101???10 0000000000001011 MOV r,rm 2c +?0001001???11 0000000000001011 UMOV r,rm +?10001110?010 0000000000001100 MOV segreg,rmw 30 +?10001100??10 0000000000001101 MOV(ZX) rmv,segreg 34 +?10001110?110 0000000000001110 MOV segreg,rmw 38 +?10001111??10 0000000000010000 POP mv 40 +?1100011???10 0000000000010001 MOV rm,i 44 +?00100110??11 0000000000010010 MOV TRn,rd 48 +?01100011?110 0000000000010011 ARPL rmw,rw 4c +?1010001???10 0001000000010011 MOV [i],A +?11111110??10 0000000000010100 misc rmb 50 +?11111111??10 0000000000010101 misc rmv 54 +?1111011???10 0000000000010110 math rm 58 +?00100100??11 0000000000010111 MOV rd,TRn 5c +?1100000???10 0000000000011000 rot rm,ib 60 +?1101000???10 0000000000011001 rot rm,1 64 +?1010000???10 0001000000011001 MOV A,[i] +?1101001???10 0000000000011010 rot rm,CL 68 +?10100011??11 0000000000011011 BT rv/m,rv 6c +?10111010??11 0000000000011100 BT/BTS/BTR/BTC rv/m,ib 70 +?10101011??11 0000000000011101 BTS rv/m,rv 74 +?1011?011??11 0000000000011101 BTR/BTC rv/m,rv +?1011010???11 0000000000011110 LFS/LGS rv,m 78 IMM = 0x34 for LFS (opcode = 0xb4) and 0x35 for LGS (opcode = 0xb5) +?01100011?010 0000000000011111 ARPL rmw,rw 7c +?00000000?011 0000000000011111 SLDT/STR/LLT/LTR/VERR/VERW rmw +?0000001??011 0000000000011111 LAR/LSL rv,rmv +?00000000?111 0000000000100000 SLDT/STR/LLT/LTR/VERR/VERW rmw 80 +?0100??????10 0000000000100001 INC/DEC rv 84 +?00000001??11 0000000000100001 SGDT/SIDT/LGDT/LIDT/SMSW/LMSW rmw +?00000010?111 0000000000100010 LAR rv,rmv 88 +?0000010???10 0000000000100011 ADD A,i weird? 8c +?0001?10???10 0000000000100011 ADC/SBB A,i weird? +?001?010???10 0000000000100011 AND/XOR A,i weird? +?00?0110???10 0000000000100011 OR/SUB A,i weird? +?00000011?111 0000000000100011 LSL rv,rmv +?10100111??11 0000000000100100 IBTS rmv,eAX,CL,rv 90 +?0011110???10 0000000000100101 CMP A,i 94 +?1010100???10 0000000000100101 TEST A,i +?10100110??11 0000000000100101 XBTS rv,rmv,eAX,CL +?1010?100??11 0000000000100110 SHxD rmv,rv,ib 98 +?1010?101??11 0000000000100111 SHxD rmv,rv,CL 9c +?110110?0??10 0000000000101000 ESC 0/2 a0 +?11011110??10 0000000000101001 ESC 6 a4 +?11011101??10 0000000000101010 ESC 5 a8 +?11011001??10 0000000000101011 ESC 1 ac +?11011111??10 0000000000101100 ESC 7 b0 +?1001??????11 0000000000101101 SETcond rmb b4 +01011?11???11 0000000000101110 MOVZX/MOVSX r,rm b8 +11011?11???11 0000000000101111 MOVZX/MOVSX r,rm bc +?10111100??11 0000000000110000 BSF rv,rmv c0 +?10111101??11 0000000000110001 BSR rv,rmv c4 +?00100010??11 0000000000110010 MOV CRn,rd c8 +?00100000??11 0000000000110011 MOV rd,CRn cc +?00100011??11 0000000000110100 MOV DRn,rd d0 +?00100001??11 0000000000110101 MOV rd,DRn d4 +?11011100??10 0000000000110110 ESC 4 d8 +?11011011??10 0000000000110111 ESC 3 dc +?10001101??10 0000000000111000 LEA rv,m e0 +?11000100??10 0000000000111001 LES e4 +?11000101??10 0000000000111010 LDS e8 +?01100010??10 0000000000111011 BOUND rv,m2v ec +?10110010??11 0000000000111100 LSS rv,m f0 IMM = 0x32 (opcode = 0xb2) +?11100011??10 0000000001010001 JCXZ cb +?11100010??10 0000000001010111 LOOP cb +?1110000???10 0000000001011111 LOOPE/LOOPNE cb +?0111??????10 0000000001100101 Jcond cb +?1000??????11 0000000001100101 Jcond cv +?111010?1??10 0000000001101010 JMP c +?1100001???10 0011000001110010 RET/RET iw +?11101000??10 0010000001110101 CALL cw +?01010?????10 0010000010000110 PUSH rv +?01100000??10 0000000010001000 PUSHAd +001100001??10 0011000010010001 POPAd +101100001??10 0011000010010111 POPAd +?000??110??10 0010000010011011 PUSH segreg +?1010?000??11 0010000010011011 PUSH FS/GS +?011010?0??10 0010000010011101 PUSH i +?01011?????10 0011000010011111 POP rv +?00010111??10 0011000010100010 POP SS +?00000111??10 0011000010100111 POP ES +?00011111??10 0011000010100111 POP DS +?1010?001??11 0011000010100111 POP FS/GS +?10010?????10 0000000010110110 XCHG eAX,rv +?10011111??10 0000000011010111 LAHF +?10011110??10 0000000011011001 SAHF +?00000110??11 0000000011011100 CLTS +?11010110??10 0000000011100001 SALC +?0011?111??10 0000000110000111 AAD/AAS +?0010?111??10 0000000110001011 DAA/DAS +?11010100??10 0000000110001111 AAM ib +?11010101??10 0000000110011001 AAD ib +?10011001??10 0000000111100110 CWD / CDQ +010011000??10 0000000111101000 CBW / CWDE +110011000??10 0000000111110000 CBW / CWDE +?1010010?1?10 0000000111111000 REP MOVS +?1010010?0?10 0000001000010001 MOVS +?1010011?1?10 0000001000011000 REP CMPS +?1010011?0?10 0000001000101011 CMPS +?1010111?1?10 0000001000110101 REP SCAS +?1010111?0?10 0000001001000111 SCAS +?1010110?1?10 0000001001001110 REP LODS +?1010110?0?10 0000001001011010 LODS +?11010111??10 0000001001011111 XLATB +?1010101?1?10 0000001001100011 REP STOS +?1010101?0?10 0000001001101110 STOS +?1110010??110 0000001001110010 IN A,ib +?1110010??010 0000001001110100 IN A,ib +?1110110??110 0000001001111001 IN A,DX +?1110110??010 0000001001111010 IN A,DX +?0110110?0110 0000001001111111 INS +?0110110?0010 0000001010000001 INS +?0110110?1110 0000001010001010 REP INS +?0110110?1010 0000001010001011 REP INS +?1110011??110 0000001010011011 OUT ib,A +?1110011??010 0000001010011101 OUT ib,A +?1110111??110 0000001010100001 OUT DX,A +?1110111??010 0000001010100010 OUT DX,A +?0110111?0110 0000001010100111 OUTS +?0110111?0010 0000001010101001 OUTS +?0110111?1110 0000001010110001 REP OUTS +?0110111?1010 0000001010110010 REP OUTS +?10011010??10 0010001011010110 CALL cp +?11101010??10 0000001011100101 JMP cp +?1100101???10 0011001011111100 RETF/RETF iw +011001000??10 0010001100000100 ENTER +111001000??10 0010001100001000 ENTER +011001001??10 0000001100011111 LEAVE +111001001??10 0000001100100011 LEAVE +?11110100??10 0000001100100111 HLT +?10011011??10 0000001110111101 WAIT +?11001111?110 0011011001110011 IRETd +?11110101??10 0000011111101111 CMC +?11111?0???10 0000011111101111 CLC/STC/CLD/STD +?10011100?110 0010011111110010 PUSHFd +?1111101???10 0000011111110111 CLI/STI +?10011100?010 0010011111111001 PUSHFd +?10011101?010 0011011111111011 POPFd +?11001101?010 0000011111111101 INT ib +?11001111?010 0011011111111111 IRETd +?10011101?110 0011100000000011 POPFd +?11001101?110 0000100000001000 INT ib +?11001100??10 0000100000010110 INT 3 +?11001110??10 0000100000100111 INTO +?0000010???11 0000100000101011 illegal? LOADALL286 +?00001000??11 0000100000101011 illegal? +?000011????11 0000100000101011 illegal? +?00101?00??11 0000100000101011 illegal? +?0010?1?1??11 0000100000101011 illegal? +?001100000?11 0000100000101011 illegal? +?00110001??11 0000100000101011 illegal? +?0011001???11 0000100000101011 illegal? +?00?01001??11 0000100000101011 illegal? +?00?0101???11 0000100000101011 illegal? +?00?101????11 0000100000101011 illegal? +?00?11?????11 0000100000101011 illegal? +?010??0000011 0000100000101011 illegal? +?010??0010?11 0000100000101011 illegal? +?010???000111 0000100000101011 illegal? +?010??01?0?11 0000100000101011 illegal? +?010??1100111 0000100000101011 illegal? +?010??1?00011 0000100000101011 illegal? +?010??1?10?11 0000100000101011 illegal? +?010???011?11 0000100000101011 illegal? +?010???111?11 0000100000101011 illegal? +?010????01?11 0000100000101011 illegal? +?011??0001?11 0000100000101011 illegal? +?011??01???11 0000100000101011 illegal? +?011??1111?11 0000100000101011 illegal? +?011??11?0?11 0000100000101011 illegal? +?011??1?01?11 0000100000101011 illegal? +?011???000?11 0000100000101011 illegal? +?011???01??11 0000100000101011 illegal? +?1010?010??11 0000100000101011 illegal? +?101100000?11 0000100000101011 illegal? +?10111000??11 0000100000101011 illegal? +?1011?001??11 0000100000101011 illegal? +?11000001??11 0000100000101011 illegal? +?11001001??11 0000100000101011 illegal? +?1100?101??11 0000100000101011 illegal? +?1101??01??11 0000100000101011 illegal? +?111??001??11 0000100000101011 illegal? +?111??101??11 0000100000101011 illegal? +?11???0001?11 0000100000101011 illegal? +?11???01???11 0000100000101011 illegal? +?11???1111?11 0000100000101011 illegal? +?11???11?0?11 0000100000101011 illegal? +?11???1?01?11 0000100000101011 illegal? +?11????000?11 0000100000101011 illegal? +??0101110??11 0000100000101011 illegal? +??01100001?11 0000100000101011 illegal? +?00000111??11 0000100011110110 LOADALL386 +?11110001??10 0000100100111100 ICEBP + +Bits 1-8 opcode +Bit 12 = 0F prefix present +Bit 11 = this is an instruction? +Bit 10 = protected mode? +Bit 9 = repeat flag present +Bit 0 = 32 bit mode? + + diff --git a/80386/disassembler/386_microcode.cpp b/80386/disassembler/386_microcode.cpp new file mode 100644 index 0000000..d9dd8b7 --- /dev/null +++ b/80386/disassembler/386_microcode.cpp @@ -0,0 +1,2179 @@ +#include "alfe/main.h" +#include + +class EntryPoint +{ +public: + EntryPoint(int u, int a, int t, String s) : _u(u), _a(a), _t(t), _s(s) { } + int _u; // Extra bits from decxoder rom. bit 1 is set if the initial bus address is SS:eSP instead of the EA from the instruction + int _a; // micro-op address of this entry point in microcode ROM + int _t; // Number of cycles the manual says that this instruction takes (may not be accurate) + String _s; // Name of entry point (x86 instructions or subroutine that this part of the microcode implements) +}; + +EntryPoint entryPoints[] = { + {0, 0x003, 2, " MOV r,r"}, + {0, 0x005, 2, " MOV r,i"}, + {0, 0x007, 2, " MOVZX rv,segreg"}, + {0, 0x009, 2, " r MOV ES/SS/DS/FS/GS,rw"}, + {1, 0x00b, 5, " MOV SS,mw"}, + {1, 0x00f, 5, " MOV ES/DS/FS/GS,mw"}, + {1, 0x013, 2, " MOV [i],A MOV m,r"}, + {1, 0x015, 2, " MOV m,i"}, + {1, 0x017, 2, " MOV mw,segreg"}, + {1, 0x019, 4, " MOV A,[i] MOV r,m"}, + {0, 0x01d, 2, " ADD/OR/ADC/SBB/AND/SUB/XOR r,r"}, + {0, 0x01f, 2, " CMP r,r TEST r,r"}, // TEST reg,reg has cycle count of 1? + {0, 0x021, 2, " INC/DEC/NOT/NEG r"}, + {0, 0x023, 2, " ADD/OR/ADC/SBB/AND/SUB/XOR r,i"}, + {0, 0x025, 2, " CMP/TEST A,i"}, + {1, 0x027, 6, " ADD/OR/ADC/SBB/AND/SUB/XOR r,m"}, + {1, 0x02c, 6, " CMP r,m"}, + {1, 0x031, 5, " CMP/TEST m,i"}, + {1, 0x035, 5, " CMP/TEST m,r"}, + {9, 0x039, 7, " ADD/OR/ADC/SBB/AND/SUB/XOR m,i"}, + {0, 0x03d, 4, " SETcond rb"}, + { 0, 0x041, 0, "SETCONDR_FALSE"}, + {1, 0x043, 5, " SETcond mb"}, + { 0, 0x046, 0, "WRITE_RESULT "}, + { 0, 0x048, 0, "SETCONDM_FALSE"}, + {9, 0x04a, 7, " ADD/OR/ADC/SBB/AND/SUB/XOR m,r"}, + {9, 0x04e, 6, " INC/DEC/NOT/NEG m"}, + {0, 0x051, 5, " JeCXZ cb"}, // cycle count is 5/9+m + {0, 0x057,11, " LOOP cb"}, // cycle count is 11+m/? + { 0, 0x05b, 0, "LOOP_DONE "}, + { 0, 0x05d, 0, "LOOP_UNTAKEN "}, + {0, 0x05f,11, " LOOPE/LOOPNE cb"}, // cycle count is 11+m/? + {0, 0x065, 3, " Jcond cb/cv"}, // cycle count is 3/7+m + { 0, 0x067, 0, "JMP_PREFINAL "}, + { 0, 0x068, 0, "JMP_FINAL "}, + { 0, 0x069, 0, "Jcond_DONE "}, + {0, 0x06a, 7, " JMP c"}, // cycle count is 7+m + { 0, 0x06b, 0, "JMP_PREF "}, + {0, 0x06d, 7, " JMP rv"}, // cycle count is 7+m + {1, 0x06f,10, " JMP mv"}, // cycle count is 10+m + {3, 0x072,10, " RET/RET iw"}, // cycle count is 10+m + {2, 0x075, 7, " CALL cw"}, // cycle count is 7+m + {2, 0x079, 7, " CALL rv"}, // cycle count is 7+m + {1, 0x07c,10, " CALL mv"}, // cycle count is 10+m + {1, 0x081, 5, " PUSH mv"}, + {2, 0x086, 2, " PUSH rv"}, + {0, 0x088,24, " PUSHAd"}, + { 0, 0x08d, 0, "PUSHAd_LOOP "}, + {3, 0x091,24, " POPA"}, + { 0, 0x092, 0, "POPAd_LOOP "}, + {3, 0x097,24, " POPAD"}, + {2, 0x09b, 2, " PUSH segreg"}, + {2, 0x09d, 2, " PUSH i"}, + {3, 0x09f, 4, " POP rv"}, // number of cycles doesn't seem to match + {3, 0x0a2, 7, " POP SS"}, + {3, 0x0a7, 7, " POP ES/DS/FS/GS"}, + {3, 0x0ac, 5, " POP mv"}, + {9, 0x0b1, 5, " XCHG m,r"}, + {0, 0x0b6, 3, " XCHG eAX,rv XCHG r,r"}, + {1, 0x0b9, 2, " LEA rv,m"}, + {1, 0x0bb, 7, " LDS rv,m"}, // cycle count is 7/22 + {1, 0x0c2, 7, " LES rv,m"}, // cycle count is 7/22 + {1, 0x0c9, 7, " LSS rv,m"}, // cycle count is 7/22 + {1, 0x0d0, 7, " LFS/LGS rv,m"}, // cycle count is 7/22 + {0, 0x0d7, 2, " LAHF"}, + {0, 0x0d9, 3, " SAHF"}, + {0, 0x0dc, 5, " CLTS"}, + {0, 0x0e1, 0, " SALC"}, // don't know cycle count + { 0, 0x0e4, 0, "SALC_DONE "}, + {0, 0x0e5, 9, " RCL/RCR r,ib"}, + {0, 0x0e9, 9, " RCL/RCR r,CL"}, + { 0, 0x0ed, 0, "RCLRCR_R_COMM "}, // common to register ib and CL forms of RCL/RCR + { 0, 0x0f1, 0, "RCLRCR_R_LOOP "}, + {0, 0x0f9, 3, " ROL/ROR/SHL/SHR/SAR r,ib"}, + {0, 0x0fc, 3, " SHxD rv,rv,ib"}, + {0, 0x0ff, 3, " ROL/ROR/SHL/SHR/SAR r,CL"}, + {0, 0x102, 3, " SHxD rv,rv,CL"}, + {0, 0x105, 9, " rot r,1"}, + {1, 0x108,10, " RCL/RCR m,ib"}, + {1, 0x10c,10, " RCL/RCR m,CL"}, + { 0, 0x110, 0, "RCLRCR_M_COMM "}, // common to memory ib and CL forms of RCL/RCR + { 0, 0x115, 0, "RCLRCR_M_LOOP "}, + {1, 0x11e, 7, " ROL/ROR/SHL/SHR/SAR m,ib"}, + { 0, 0x120, 0, "ROSHSA_M_COMM "}, // common to memory ib and CL forms of ROL/ROR/SHL/SHR/SAR + {1, 0x124, 7, " SHxD mv,rv,ib"}, + { 0, 0x126, 0, "SHxD_M_COMM "}, // common to memory ib and CL forms of ROL/ROR/SHL/SHR/SAR + {1, 0x12a,10, " rot m,1"}, + {1, 0x12d, 7, " ROL/ROR/SHL/SHR/SAR m,CL"}, + {1, 0x12f, 7, " SHxD mv,rv,CL"}, + {0, 0x131, 3, " BT rv,rv"}, + {1, 0x134,12, " BT m,rv"}, + {0, 0x13f, 3, " BT rv,ib"}, + {1, 0x142, 6, " BT m,ib"}, + {0, 0x147, 6, " BTS/BTR/BTC rv,rv"}, + {9, 0x14d,13, " BTS/BTR/BTC m,rv"}, + {0, 0x15a, 6, " BTS/BTR/BTC rv,ib"}, + {9, 0x160, 8, " BTS/BTR/BTC m,ib"}, + {0, 0x168,10, " BSF rv,rv"}, // 10+3n + { 0, 0x169, 0, "BSF_COMMON "}, // common to register and memory forms of BSF + { 0, 0x171, 0, "BSF_DONE " }, + { 0, 0x172, 0, "BSF_LOOP "}, + {1, 0x177,10, " BSF rv,mv"}, // 10+3n + {0, 0x17a,10, " BSR rv,rv"}, // 10+3n + { 0, 0x17b, 0, "BSR_COMMON "}, // common to register and memory forms of BSR + { 0, 0x17f, 0, "BSR_LOOP "}, + { 0, 0x183, 0, "BSR_DONE " }, + {1, 0x184,10, " BSR rv,mv"}, // 10+3n + {0, 0x187, 4, " AAA/AAS"}, + {0, 0x18b, 4, " DAA/DAS"}, + {0, 0x18f,17, " AAM ib"}, + {0, 0x199,19, " AAD ib"}, + {0, 0x1a5, 9, " MUL/IMUL r"}, // cycle count is 9-14/9-22/9-38 + { 0, 0x1a7, 0, "iMUL_COMMON "}, // common to register and memory forms of MUL/IMUL rm + {1, 0x1af,12, " MUL/IMUL m"}, // cycle count is 12-17/12-25/12-41 + {0, 0x1b3, 9, " IMUL rv,rv"}, // cycle count is 9-22/9-38 + { 0, 0x1b5, 0, "IMUL2_COMMON "}, // common to register and memory forms of IMUL rv,rmv and IMUL rv,rmv,i + {1, 0x1bd,12, " IMUL rv,mv"}, // cycle count is 12-25/12-41 + {1, 0x1c1, 9, " IMUL rv,mv,i"}, // cycle count is 9-22/9-38 + {0, 0x1c4,12, " IMUL rv,rv,i"}, // cycle count is 12-25/12-41 + {0, 0x1c7,14, " DIV r "}, // cycle count is 14/22/38 + { 0, 0x1ca, 0, "DIV_COMMON " }, // common to register and memory forms of DIV + {1, 0x1cf,17, " DIV m"}, // cycle count is 17/25/41 + {0, 0x1d3,19, " IDIV r"}, // cycle count is 19/27/43 + { 0, 0x1d8, 0, "IDIV_COMMON " }, // common to register and memory forms of IDIV + {1, 0x1e1,22, " IDIV m"}, // cycle count is 22/30/46 + {0, 0x1e6, 2, " CWD / CDQ"}, + {0, 0x1e8, 3, " CBW / CWDE MOVZX/MOVSX r,r (16-bit?)"}, + {1, 0x1eb, 6, " MOVZX/MOVSX r,m (16-bit?)"}, + {0, 0x1f0, 3, " CBW / CWDE MOVZX/MOVSX r,r (32-bit?)"}, + {1, 0x1f3, 6, " MOVZX/MOVSX r,m (32-bit?)"}, + {0, 0x1f8, 7, " REP MOVS"}, + { 0, 0x1fd, 0, "REP_MOVS_NOT0 " }, + { 0, 0x201, 0, "REP_MOVS_LOOP " }, + { 0, 0x205, 0, "REP_MOVS_DONE " }, + { 0, 0x207, 0, "REP_MOVS_RPTI " }, + { 0, 0x208, 0, "RPTI "}, + {0, 0x211, 7, " MOVS"}, + {0, 0x218,12, " REP CMPS"}, + { 0, 0x21c, 0, "REP_CMPS_DONE " }, + { 0, 0x21d, 0, "REP_CMPS_LOOP " }, + { 0, 0x220, 0, "REP_CMPS_NOT0 " }, + {0, 0x22b,10, " CMPS"}, + {0, 0x235, 9, " REP SCAS"}, + { 0, 0x239, 0, "REP_SCAS_DONE " }, + { 0, 0x23a, 0, "REP_SCAS_LOOP " }, + { 0, 0x23d, 0, "REP_SCAS_NOT0 " }, + {0, 0x247, 7, " SCAS"}, + {0, 0x24e, 7, " REP LODS"}, + { 0, 0x24f, 0, "REP_LODS_DONE " }, + { 0, 0x250, 0, "REP_LODS_LOOP " }, + {0, 0x25a, 5, " LODS"}, + {0, 0x25f, 5, " XLATB"}, + {0, 0x263, 6, " REP STOS"}, + { 0, 0x264, 0, "REP_STOS_DONE " }, + { 0, 0x265, 0, "REP_STOS_LOOP " }, + {0, 0x26e, 4, " STOS"}, + {0, 0x272, 6, " p IN A,ib"}, // cycle count is 6/26 + {0, 0x274,12, " r IN A,ib"}, + { 0, 0x276, 0, "IN_IMM_NOCHK " }, + { 0, 0x278, 0, "IN_DONE " }, + {0, 0x279, 7, " p IN A,DX"}, // cycle count is 7/27 + {0, 0x27a,13, " r IN A,DX"}, + { 0, 0x27c, 0, "IN_DX_NOCHK " }, + {0, 0x27f, 9, " p INS"}, // cycle count is 9/29 + {0, 0x281,15, " r INS"}, + { 0, 0x284, 0, "INS_NOCHK " }, + {0, 0x28a,11, " p REP INS"}, + {0, 0x28b,17, " r REP INS"}, + { 0, 0x28d, 0, "REP_INS_NOCHK " }, + { 0, 0x290, 0, "REP_INS_DONE " }, + { 0, 0x291, 0, "REP_INS_LOOP " }, + { 0, 0x293, 0, "REP_INS_NOT0 " }, + {0, 0x29b, 4, " p OUT ib,A"}, // cycle count is 4/24 + {0, 0x29d,10, " r OUT ib,A"}, + { 0, 0x29f, 0, "OUT_IMM_NOCHK " }, + {0, 0x2a1, 5, " p OUT DX,A"}, // cycle count is 5/25 + {0, 0x2a2,11, " r OUT DX,A"}, + { 0, 0x2a4, 0, "OUT_DX_NOCHK " }, + {0, 0x2a7, 8, " p OUTS"}, // cycle count is 8/28 + {0, 0x2a9,14, " r OUTS"}, + { 0, 0x2ac, 0, "OUTS_NOCHK " }, + {0, 0x2b1,10, " p REP OUTS"}, + {0, 0x2b2,16, " r REP OUTS"}, + { 0, 0x2b4, 0, "REP_OUTS_NOCHK" }, + { 0, 0x2b7, 0, "REP_OUTS_DONE " }, + { 0, 0x2b8, 0, "REP_OUTS_LOOP " }, + { 0, 0x2ba, 0, "REP_OUTS_NOT0 " }, + { 0, 0x2c1, 0, "PORTIO_PROTCHK" }, + { 0, 0x2c4, 0, "IO_PERM_BITMAP" }, + { 0, 0x2d3, 0, "PORTIO_16BIT " }, + { 0, 0x2d4, 0, "PORTIO_ALLOWED" }, + {2, 0x2d6,17, " CALL cp"}, // cycle count is 17+m/34+m + {1, 0x2da,22, " CALL mp"}, // cycle count is 22+m/38+m + { 0, 0x2e2, 0, "CALL_FAR_RM " }, // common to cp and mp far CALLs in real mode + {0, 0x2e5,12, " JMP cp"}, // cycle count is 12+m/27+m/45+m/TS/TS + { 0, 0x2eb, 0, "JMP_FAR_RM " }, + { 0, 0x2ed, 0, "JMP_FAR_RM_1 " }, // Jumps to COUNTR:TMPG ? TMPB is previous CS limit (set by 2fb)? + { 0, 0x2f0, 0, "JMP_FAR_COMMON" }, + { 0, 0x2f1, 0, "JMP_FAR_DONE " }, + {1, 0x2f5,43, " JMP mp"}, // cycle count is 43+m/31+m/49+m/5+TS/5+TS + {3, 0x2fc,18, " RETF/RETF iw"}, // cycle count is 18+m/32+m/68 + {2, 0x304,10, " ENTER (16-bit?)"}, // cycle count is 10 (0), 12 (1), 15+4*(n-1) (n) + {2, 0x308,10, " ENTER (32-bit?)"}, // cycle count is 10 (0), 12 (1), 15+4*(n-1) (n) + { 0, 0x30c, 0, "ENTER_COMMON " }, + { 0, 0x316, 0, "ENTER_LOOP " }, + { 0, 0x31a, 0, "ENTER_LAST " }, + { 0, 0x31c, 0, "ENTER_LASTW " }, + { 0, 0x31d, 0, "ENTER_DONE " }, + {0, 0x31f, 4, " LEAVE (16-bit?)"}, + {0, 0x323, 4, " LEAVE (32-bit?)"}, + {0, 0x327, 5, " HLT"}, + { 0, 0x329, 0, "HLT_SHUTDOWN " }, + {1, 0x32e,11, " LIDT mw"}, + {1, 0x332,11, " LGDT mw"}, + { 0, 0x336, 0, "LIDTGDT_COMMON" }, + {0, 0x33d, 9, " SIDT mw"}, // Number of cycles doesn't seem to match? + {0, 0x340, 9, " SGDT mw"}, // Number of cycles doesn't seem to match? + { 0, 0x343, 0, "SIDTGDT_COMMON" }, + {1, 0x349,13, " LMSW mw"}, + {0, 0x34e,10, " LMSW rw"}, + { 0, 0x351, 0, "LMSW_COMMON " }, + {0, 0x358,10, " SMSW rw"}, + {1, 0x35a, 3, " SMSW mw"}, + {0, 0x35c,10, " MOV CR0,rd"}, + { 0, 0x366, 0, "PAGING_RM " }, + {0, 0x368, 4, " MOV CR2,rd"}, + {0, 0x36c, 5, " MOV CR3,rd"}, + {0, 0x371, 6, " MOV rd,CR0"}, + { 0, 0x373, 0, "STORE_CR " }, // Common code to "MOV rd,CRn" + {0, 0x377, 6, " MOV rd,CR2"}, + {0, 0x379, 6, " MOV rd,CR3"}, + {0, 0x37b,16, " MOV DR4/6,rd"}, + {0, 0x37f,16, " MOV DR5/7,rd"}, + { 0, 0x383, 0, "LD_DR4567_DONE" }, + { 0, 0x385, 0, "SELECT_DR_TR " }, + {0, 0x38a,22, " MOV DR0-3,rd"}, + {0, 0x391,12, " MOV TRn,rd"}, + { 0, 0x398, 0, "GENERAL_DETECT" }, // Do the breakpoint on TR/DR access if bit 13 of DR7 is set + { 0, 0x3a2, 0, "GD_HIT " }, // General detect condition has been triggered + {0, 0x3a6,22, " MOV rd,DR4/6"}, + {0, 0x3aa,22, " MOV rd,DR5/7"}, + {0, 0x3ae,22, " MOV rd,DR0-3"}, + {0, 0x3b6,12, " MOV rd,TRn"}, + {0, 0x3bd, 6, " WAIT"}, + { 0, 0x3be, 0, "WAIT_LOOP " }, + { 0, 0x3c1, 0, "WAIT_IRQT " }, // Continuation of WAIT loop after subroutine - check if IRQ is pending + { 0, 0x3c5, 0, "WAIT_ERRT " }, // Subroutine to handle && in error test + { 0, 0x3c8, 0, "WAIT_DONE " }, + { 0, 0x3cb, 0, "FPU_ERROR6 " }, + {0, 0x3cd, 0, " FENI/FDISI/FCLEX/FINIT/FSETPM/FRSTPM r"}, // FPU flag instructions (no memory access) - these need to reset prefetching for some reason? Same reason that CLI/STI do? + { 0, 0x3d1, 0, "FPU_FLAG_LOOP " }, + {0, 0x3d9, 0, " FSTCW/FSTSW mw"}, // Number of cycles doesn't seem to match? + {0, 0x3da, 0, " FSTSW AX/FNSTDW/FNSTSG r"}, + { 0, 0x3db, 0, "FPU_MISC_WAIT " }, + { 0, 0x3e2, 0, "FPU_MISC_CORE " }, + { 0, 0x3e8, 0, "FPU_MISC_WRITE" }, + { 0, 0x3eb, 0, "FPU_ERROR5 " }, // Unreachable? + {1, 0x3ed, 0, " FSTENV m"}, + {1, 0x3f0, 0, " FSAVE m"}, + { 0, 0x3f3, 0, "FSAVE_WAIT " }, // Common entry point to FSTENV and FSAVE - wait for FPU to be ready + { 0, 0x3fa, 0, "FSAVE_CORE " }, + { 0, 0x42f, 0, "FSAVE_COR_WAIT" }, + { 0, 0x42f, 0, "FSAVE_PM " }, // FSAVE protected mode helper + { 0, 0x436, 0, "FSAVE_REGFILE " }, // FSAVE subroutine to save register file (i.e. the part that isn't done in FSTENV) + { 0, 0x43c, 0, "FSAVE_LOOP " }, + { 0, 0x442, 0, "FSAVE_DONEFILE" }, + { 0, 0x444, 0, "FSAVE_NOWRITE " }, + { 0, 0x449, 0, "FSAVE_387 " }, //pla4 ?????1????<3E> 0000 10" }, + { 0, 0x451, 0, "FSAVE_287 " }, //pla4 ?????0????<3E> 0000 10" }, + { 0, 0x451, 0, "FSAVE_DONE " }, + {1, 0x459, 0, " FLDENV m"}, + {1, 0x45c, 0, " FRSTOR m"}, + { 0, 0x45f, 0, "FPU_ERROR4 " }, + { 0, 0x461, 0, "FRSTOR_WAIT " }, // Common entry point to FSTENV and FSAVE - wait for FPU to be ready + { 0, 0x466, 0, "FRSTOR_IRQT " }, + { 0, 0x46a, 0, "FRSTOR_ERRT " }, + { 0, 0x46e, 0, "FRSTOR_CORE " }, + { 0, 0x47b, 0, "FRSTOR_CORWAIT" }, + { 0, 0x49b, 0, "FRSTOR_PM " }, // FRSTOR protected mode helper + { 0, 0x4a7, 0, "FRSTOR_REGFILE" }, // FRSTOR subroutine to save register file (i.e. the part that isn't done in FLDENV) + { 0, 0x4ad, 0, "FRSTOR_LOOP " }, + { 0, 0x4b3, 0, "FRSTOR_DONEFIL" }, + { 0, 0x4b5, 0, "FRSTOR_387 " }, //pla4 ?????1????<3F> 0000 10" }, + { 0, 0x4ba, 0, "FRSTOR_DONE " }, + { 0, 0x4bb, 0, "FRSTOR_287 " }, //pla4 ?????0????<3F> 0000 10" }, + {0, 0x4c1, 0, " FP instructions that don't access memory"}, + { 0, 0x4c2, 0, "FPU_REG_WAIT " }, + { 0, 0x4c5, 0, "FPU_REG_IRQT " }, + { 0, 0x4c9, 0, "FPU_REG_ERRT " }, + { 0, 0x4cc, 0, "FPU_REG_CORE " }, + { 0, 0x4ce, 0, "FPU_REG_CORWAI" }, + { 0, 0x4d1, 0, "FPU_ERROR3 " }, + {1, 0x4d3, 0, " FBLD/FLD mt"}, + {1, 0x4d7, 0, " FADD/FMUL/FCOM/FCOMP/FSUB/FSUBR/FDIV/FDIVR/FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FLD/FILD md"}, + {1, 0x4db, 0, " FLD/FILD/FADD/FMUL/FCOM/FCOMP/FSUBR/FSUB/FDIVR/FDIV mq"}, + {1, 0x4df, 0, " FLDCW mw"}, + {1, 0x4e0, 0, " FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FILD mw"}, + { 0, 0x4e7, 0, "FPU_LD80_287 " }, + { 0, 0x4e8, 0, "FPU_LD3264_287" }, + { 0, 0x4ee, 0, "FPU_LD80_387 " }, + { 0, 0x4f0, 0, "FPU_LOAD_WAIT " }, + { 0, 0x4f4, 0, "FPU_LOAD_IRQT " }, + { 0, 0x4f8, 0, "FPU_LOAD_ERRT " }, + { 0, 0x4fc, 0, "FPU_LOAD_CORE " }, + { 0, 0x503, 0, "FPU_LOAD_CORWA" }, + { 0, 0x506, 0, "FPU_LOAD_LOOP " }, + { 0, 0x50c, 0, "FPU_LOAD_DONE " }, + { 0, 0x50e, 0, "FPU_LD80_DONE " }, + { 0, 0x514, 0, "FPU_ERROR2 " }, + { 0, 0x516, 0, "FLDCW " }, + { 0, 0x518, 0, "FLDCW_COR_WAIT" }, + { 0, 0x51c, 0, "FPU_LD3264_387" }, + { 0, 0x51f, 0, "FPU_LD3264_WAI" }, + { 0, 0x523, 0, "FPU_LD3264_IRQ" }, + { 0, 0x527, 0, "FPU_LD3264_ERR" }, + { 0, 0x52a, 0, "FPU_LD3264_COR" }, + { 0, 0x531, 0, "FPU_LD32 " }, + { 0, 0x533, 0, "FPU_LD32_WAIT " }, // Why wait after the data has been transferred? CPU bug? + { 0, 0x536, 0, "#NM " }, //pla4 ??????1???<3B><38><39><3C><3D> ??????01??<3B><38><39><3C><3D> ??????1?1?<34> 0000 10" }, coprocessor not available exception + {1, 0x538, 0, " FBSTP/FSTP mt"}, + {1, 0x53c, 0, " FST/FSTP/FIST/FISTP md"}, + {1, 0x540, 0, " FST/FSTP/FISTP mq"}, + {1, 0x544, 0, " FIST/FISTP mw"}, + { 0, 0x54b, 0, "FPU_ERROR ", }, + { 0, 0x54d, 0, "FPU_ST80_287 " }, + { 0, 0x54e, 0, "FPU_ST3264_287" }, + { 0, 0x554, 0, "FPU_ST80_387 " }, + { 0, 0x555, 0, "FPU_ST3264_387" }, + { 0, 0x556, 0, "FPU_STORE_WAIT" }, + { 0, 0x55a, 0, "FPU_STORE_IRQT" }, + { 0, 0x55e, 0, "FPU_STORE_ERRT" }, + { 0, 0x562, 0, "FPU_STORE_CORE" }, + { 0, 0x568, 0, "FPU_STORE_CORW" }, + { 0, 0x56f, 0, "FPU_STORE_LOOP" }, + { 0, 0x575, 0, "FPU_STORE_DONE" }, + { 0, 0x578, 0, "FPU_STORE_287 " }, + { 0, 0x57d, 0, "FPU_STORE_ABRT" }, + {0, 0x580, 2, " p MOV ES/DS/FS/GS,rw"}, + {0, 0x585, 2, " p MOV SS,rw"}, + { 0, 0x58a, 0, "PM_LD_DSESFSGS" }, // only called in protected mode, called before load of DS/ES/FS/GS happens + { 0, 0x58e, 0, "PM_LD_SS " }, + { 0, 0x592, 0, "NULL_SELECTOR " }, + { 0, 0x595, 0, "PM_LES " }, + { 0, 0x59a, 0, "PM_LSS " }, + { 0, 0x59f, 0, "PM_LDS " }, + { 0, 0x5a4, 0, "PM_LFS_LGS " }, + { 0, 0x5ac, 0, "JUMP_FAR_PM " }, + { 0, 0x5b3, 0, "JUMP_FAR_PM_GATE" }, + { 0, 0x5b8, 0, "CALL_FAR_PM_GATE" }, + { 0, 0x5bb, 0, "GENERAL_FAULTP" }, + { 0, 0x5bd, 0, "CALLGATE286 " }, + { 0, 0x5be, 0, "CALLGATE386 " }, + { 0, 0x5c4, 0, "LD_DES_SSFSGS " }, + { 0, 0x5c9, 0, "LD_DESCRIPTOR " }, + { 0, 0x5ce, 0, "LD_DESCRIPTOR2" }, + { 0, 0x5d3, 0, "PRESENT_TSS " }, // Available (<1F>) or Busy (<1E>) + { 0, 0x5d5, 0, "PROT_TESTS_PASSED" }, + { 0, 0x5d8, 0, "PROT_TESTS_CMN" }, + { 0, 0x5da, 0, "PROT_TESTS_PASSED2" }, + { 0, 0x5df, 0, "PROT_TESTS_P16" }, + { 0, 0x5e0, 0, "CALL_FAR_PM " }, + { 0, 0x5ec, 0, "MORE_PRIV16 " }, + { 0, 0x5f0, 0, "GENERAL_FAUL2P" }, + { 0, 0x5f2, 0, "PUSH_V86_SREGS" }, // Push(GS) code in https://www.felixcloutier.com/x86/intn:into:int3:int1 ? + { 0, 0x5fb, 0, "MORE_PRIVILEGE" }, // CALL MORE-PRIVILEGE case in PRM + { 0, 0x602, 0, "FOUND_STACK " }, // We have found the offset of the SS/eSP pair in the TSS + { 0, 0x60b, 0, "MORE_PRIV2 " }, + { 0, 0x613, 0, "MORE_PRIV3 " }, + { 0, 0x615, 0, "MORE_PRIV_INT " }, + { 0, 0x619, 0, "COPY_PARAMS " }, + { 0, 0x61e, 0, "COPY_PRMS_LOOP" }, + { 0, 0x622, 0, "COPY_PRMS_DONE" }, + { 0, 0x623, 0, "COPY_PRMS_SKIP" }, + { 0, 0x62b, 0, "NO_ERROR_CODE " }, + { 0, 0x633, 0, "MORE_PRIV_DONE" }, + { 0, 0x63b, 0, "ZERO_V86_SREGS" }, // GS := 0 code in https://www.felixcloutier.com/x86/intn:into:int3:int1 ? + { 0, 0x63f, 0, "IRETd_V86 " }, // Returns to? from? v86 mode? real mode? + { 0, 0x657, 0, "IRETd_V86_LOOP" }, + { 0, 0x65c, 0, "TASK_RETURN " }, // TASK-RETURN described in https ://www.felixcloutier.com/x86/iret:iretd:iretq ? + { 0, 0x671, 0, "LOAD_TASK_16B " }, + {3, 0x673,38, " p IRETd"}, // cycle count is 38/82/TS/60 + { 0, 0x67f, 0, "RETF_PM " }, + { 0, 0x686, 0, "RETF_OUTER_LEV" }, + { 0, 0x699, 0, "RETF_OL_ES " }, + { 0, 0x69d, 0, "RETF_OL_DS " }, + { 0, 0x6a1, 0, "RETF_OL_FS " }, + { 0, 0x6a5, 0, "RETF_OL_GS " }, + { 0, 0x6a8, 0, "ZERO_SLCTR_AR " }, + {1, 0x6aa,21, " p ARPL mw,rw"}, + { 0, 0x6b3, 0, "ARPL_FAILED " }, + {0, 0x6b6,20, " p ARPL rw,rw"}, + {1, 0x6be,27, " p LTR mw"}, + {0, 0x6c3,23, " p LTR rw"}, + { 0, 0x6c5, 0, "LTR_COMMON " }, + {1, 0x6cd, 2, " p STR mw"}, + {0, 0x6cf, 2, " p STR rw"}, + {1, 0x6d1,24, " p LLDT mw"}, + {0, 0x6d6,20, " p LLDT rw"}, + { 0, 0x6c8, 0, "LLDT_COMMON " }, + { 0, 0x6dd, 0, "LLDT_TEST_PASS" }, + {1, 0x6e0, 2, " p SLDT mw"}, + {0, 0x6e2, 2, " p SLDT rw"}, + {1, 0x6e4,16, " p LAR rv,mv"}, + {0, 0x6e7,15, " p LAR rv,rv"}, + {1, 0x6ea,21, " p LSL rv,mv"}, // cycle count is 21/26 + {0, 0x6ec,20, " p LSL rv,rv"}, // cycle count is 20/25 + { 0, 0x6ee, 0, "LSL_HELPER "}, + { 0, 0x6f5, 0, "LSL_GRANULARITY_COARSE" }, + { 0, 0x6fd, 0, "LSL_GRANULARITY_FINE" }, + {1, 0x700,11, " p VERR mw"}, + {0, 0x703,10, " p VERR rw"}, + {1, 0x706,16, " p VERW mw"}, + {0, 0x709,15, " p VERW rw"}, + { 0, 0x70c, 0, "LAR_LSL_VERRWM" }, + { 0, 0x70e, 0, "LAR_LSL_VERRWR" }, + { 0, 0x70f, 0, "LAR_LSL_VERRW " }, + { 0, 0x71a, 0, "LAR_VERRW_SUCCEEDED" }, //pla4 0????01011<30> 0????01100<30> 0????1011?<30><32> 0????10?0?<32> 0????10?1?<33> 0????1101?<30> 0????1?000<30> 0????1?01?<32> 0?????001?<30> 0?????010?<30> 0??????001<30> ?????1111?<32> ?????111??<30> 0000 10" }, + { 0, 0x71c, 0, "TASKGATE " }, + { 0, 0x71f, 0, "AVAIL_TSS " }, + { 0, 0x724, 0, "SAVE_TASK " }, + { 0, 0x72b, 0, "SAVE_TASK_16 " }, + { 0, 0x72e, 0, "SAVE_TASK_COMM" }, + { 0, 0x737, 0, "SAVE_TASK_LOOP" }, + { 0, 0x73f, 0, "CALL_SAVE_TASK" }, + { 0, 0x743, 0, "AVAIL_TSS_PR " }, + { 0, 0x749, 0, "SWITCH_TASK " }, + { 0, 0x750, 0, "LOAD_TASK " }, + { 0, 0x758, 0, "TR_BACKLINK_OK" }, + { 0, 0x75a, 0, "LOAD_TASK_32 " }, + { 0, 0x764, 0, "LOAD_TASK_16 " }, + { 0, 0x765, 0, "LOAD_TASK_16A " }, + { 0, 0x765, 0, "LOAD_TASK_COMM" }, // Common to both 16-bit and 32-bit LOAD_TASK + { 0, 0x773, 0, "LOAD_TASK_LOOP" }, + { 0, 0x787, 0, "LOAD_TASK_NOPG" }, + { 0, 0x78c, 0, "NOT_NESTED_TSK" }, + { 0, 0x792, 0, "SET_TSKSWTCHED" }, + { 0, 0x795, 0, "WRITE_BACK_CR0" }, + { 0, 0x798, 0, "TASK_FINAL_V86" }, + { 0, 0x798, 0, "TASK_FV86_LOOP" }, + { 0, 0x7ab, 0, "TASK_FINAL_PM " }, + { 0, 0x7d0, 0, "HANDLE_TS_BP " }, // Last phase of task switching - handle breakpoints + { 0, 0x7d4, 0, "ADJ_STACK_DONE" }, + { 0, 0x7d7, 0, "TSKF_NO_ERRCOD" }, + { 0, 0x7e3, 0, "ADJ_STACK_16 " }, + { 0, 0x7e5, 0, "NULL_SELECTOR2" }, + { 0, 0x7e8, 0, "AVAIL_TSS_NP " }, + { 0, 0x7eb, 0, "NO_DEBUG_BP " }, + { 0, 0x7ec, 0, "CLI_STI " }, + {0, 0x7ef, 2, " CLC/STC/CLD/STD/CMC"}, + {2, 0x7f2, 4, " p PUSHFd"}, + {0, 0x7f7, 3, " CLI/STI"}, // cycle count is 2 for STI? + {2, 0x7f9, 4, " r PUSHFd"}, + {3, 0x7fb, 5, " r POPFd"}, + {0, 0x7fd,37, " r INT ib"}, + {3, 0x7ff,22, " r IRETd"}, // cycle count is 22/38 + { 0, 0x801, 0, "OVERLONG_INST "}, //small pla 010100 01 ? 0011011" }, + {3, 0x803, 5, " p POPFd"}, + {0, 0x808,59, " p INT ib"}, // cycle count is 59/99/119/TS + { 0, 0x80a, 0, "IRET_REAL_MODE" }, + {0, 0x816,33, " INT 3"}, // cycle count is 33/59/99/119/TS + {1, 0x818,10, " BOUND rv,m2v"}, // cycle count in no-jump case + { 0, 0x822, 0, "#BR " }, //small pla ?????? 11 ? 0011010" }, bound range exceeded + { 0, 0x824, 0, "DIVIDE_ERROR " }, //small pla ?????? 11 ? 0011010" }, + {0, 0x827, 3, " INTO"}, // cycle count is 35/3/59/99/119/TS + { 0, 0x82a, 0, "NO_OVERFLOW " }, + { 0, 0x82b, 0, "#UD " }, // invalid opcode + { 0, 0x82d, 0, "HARDWARE_IRQ " }, //small pla 11010? 01 ? 0011011" }, + { 0, 0x836, 0, "NMI " }, //small pla ?0010? 01 ? 0011011" }, + { 0, 0x839, 0, "TRIPLE_FAULT " }, //small pla ?????1 00 ? 0000000" }, + { 0, 0x83a, 0, "TRIPLE_FT_WAIT" }, + { 0, 0x83f, 0, "#DF " }, //small pla ?????? 00 1 0100010" }, double fault + {0, 0x844, 0, "NO_PRIVILEGE " }, + {0, 0x849, 0, " unused?"}, + { 0, 0x857, 0, "ACCESS_VIOLATI" }, //small pla ?????? 00 ? 0010110" }, + { 0, 0x85b, 0, "#GP(0) " }, + { 0, 0x85d, 0, "#GP/#TS(I0,E0)" }, + { 0, 0x85e, 0, "#GP/#TS(SIGMA)" }, //pla4 ?????0011?<24> ?????01001<24> 0000 10" }, + { 0, 0x860, 0, "#GP(SIGMA) " }, + { 0, 0x862, 0, "#SS(0) " }, + { 0, 0x863, 0, "#SS(SIGMA) " }, + { 0, 0x865, 0, "#GP(I1,E0) " }, // #GP((TMP_TR & -4) | 2) general fault with EXT = 0, I = 1 => fault with gate descriptor in the IDT + { 0, 0x866, 0, "#GP(SIGMA | 2)" }, // I = 1 + { 0, 0x868, 0, "#TS(SIGMA) " }, // #TS(SIGMA) + { 0, 0x86a, 0, "#SS(I0,E0) " }, // #SS(TMP_TR & -4) + { 0, 0x86d, 0, "FAULT_SUPPRESS" }, + { 0, 0x86e, 0, "LAR_LSL_VERRW_NULL_SELECTOR" }, + { 0, 0x870, 0, "#NP(I0,E0) " }, // #NP(TMP_TR & -4) + { 0, 0x871, 0, "#NP(I1,E0) " }, // #NP((TMP_TR & -4)|2) + { 0, 0x873, 0, "NP_COMMON " }, // Common to both #NP with I=0 and I=1 + { 0, 0x874, 0, "FAULT_ERR_CODE" }, + { 0, 0x87b, 0, "EXT_BIT_DONE " }, + { 0, 0x882, 0, "STRING_CORRECT" }, + { 0, 0x889, 0, "STRCORR_DOWN " }, + { 0, 0x88a, 0, "STRCORR_LOOP " }, + { 0, 0x890, 0, "FAULT " }, + { 0, 0x893, 0, "FLAGS_OK " }, + { 0, 0x89a, 0, "RESUME_FLAG_OK" }, + { 0, 0x89e, 0, "INTERRUPT_X " }, + { 0, 0x89f, 0, "INTERRUPT " }, // Software or hardware interrupt (vector entries are 4 byte far pointers) + { 0, 0x8b0, 0, "INTERRUPT_PM " }, // Software or hardware interrupt in protected or v86 mode (vector entries are 8 byte gate descriptors) + { 0, 0x8ba, 0, "INTERRUPT_COMM" }, + { 0, 0x8bf, 0, "INTERRUPT_SW " }, + { 0, 0x8c2, 0, "INTGATE286 " }, + { 0, 0x8c3, 0, "TRAPGATE286 " }, + { 0, 0x8cb, 0, "INTGATE386 " }, + { 0, 0x8cc, 0, "TRAPGATE386 " }, + { 0, 0x8d5, 0, "TRAP_INT_GATE " }, // common to 286/386 trap/interrupt gates + { 0, 0x8d5, 0, "PUSH_INT_FRAME" }, // pushes flags, return address and error code + { 0, 0x8e3, 0, "TRAP_INT_DONE " }, // end of trap/interrupt gate code + { 0, 0x8e5, 0, "PUSH_ERRORCODE" }, // pushes the error code onto the stack for faults + { 0, 0x8e9, 0, "PAGE_FAULT " }, //small pla ?????? 00 0 1011010" }, + { 0, 0x8ea, 0, "PAGE_FAULTLOOP" }, + {0, 0x8f6, 0, " LOADALL386"}, // don't know cycle count + { 0, 0x902, 0, "LOADALL_LOOP1 " }, + { 0, 0x90b, 0, "LOADALL_LOOP2 " }, + { 0, 0x917, 0, "LOADALL_LOOP3 " }, + { 0, 0x91c, 0, "LOADALL_LOOP4 " }, + { 0, 0x932, 0, "LOADALL_FINAL " }, + { 0, 0x939, 0, "LOADALL_PAGING" }, + {0, 0x93c, 0, " ICEBP"}, // don't know cycle count + { 0, 0x93f, 0, "SINGLE_STEP " }, //small pla ???0?? 01 ? 0011011" }, single stepping via trap flag + { 0, 0x941, 0, "BREAKPOINT " }, //small pla ??11?? 01 ? 0011011" }, comes in via small pla when DR0-DR3 are hit? Also jumped to from microcode for task switch breakpoint + { 0, 0x943, 0, "BREAKPOINT_CMN" }, // Breakpoint code common to software breakpoints (ICEBP) and hardware/signal breakpoints (like debug register condition getting hit) + { 0, 0x94f, 0, "ICE_SINGLESTEP" }, // SINGLE_STEP handled by ICE + { 0, 0x953, 0, "ICE_PIN " }, //small pla ??011? 01 ? 0011011" }, Enter ICE mode via ICE# pin like SMI# pin? + { 0, 0x95a, 0, "ICE_PIN_LOOP " }, + { 0, 0x95e, 0, "STOREALL16 " }, + { 0, 0x961, 0, "STOREALL " }, + { 0, 0x95e, 0, "STOREALL_COMM " }, + { 0, 0x970, 0, "STOREALL_LOOP1" }, + { 0, 0x980, 0, "STOREALL_LOOP2" }, + { 0, 0x981, 0, "STOREALL_LOOPS" }, + { 0, 0x989, 0, "STOREALL_LOOP3" }, + { 0, 0x993, 0, "STOREALL_LOOP4" }, + { 0, 0x99a, 0, "STOREALL_L4_ST" }, + { 0, 0x9a6, 0, "BOOTUP " }, + { 0, 0x9a7, 0, "BOOTUP_LOOP1 " }, + { 0, 0x9ab, 0, "BOOTUP_LOOP2 " }, + { 0, 0x9af, 0, "BOOTUP_LOOP3 " }, + { 0, 0x9bc, 0, "BOOTUP_JUMP " }, // Jump to initial boot CS:IP (BASE=0xffff0000 LIMIT=0xffff):0x0000fff0 aka linear address 0xfffffff0 + {-1, -1, -1, ""}}; + +class Bitset +{ +public: + Word _mask; + Word _bits; + Word _output; +}; + +class Bitset1 +{ +public: + DWord _mask; + DWord _bits; + Word _output; +}; + +class Bitset4 +{ +public: + Word _mask; + Word _bits; + DWord _output; +}; + +class Program : public ProgramBase +{ +public: + void dorom1() + { + String input1 = File("rom1_input_new.txt", true).contents(); + String output1 = File("rom1_output_new.txt", true).contents(); + Array mask1(175); + Array bits1(175); + Array outputs1(175); + Array ored1(524288); + for (int r = 0; r < 175; ++r) { + int m = 0; + int b = 0; + for (int i = 0; i < 19; ++i) { + if (input1[r*21 + i] != '.') + m += 1 << i; + if (input1[r*21 + i] == '1') + b += 1 << i; + } + mask1[r] = m; + bits1[r] = b; + int o = 0; + for (int i = 0; i < 12; ++i) { + if (output1[r*14 + i] == '1') + o += 1 << (11 - i); + } + outputs1[r] = o; + } + for (int o = 0; o < 524288; ++o) { + int v = 0; + for (int row = 0; row < 175; ++row) { + if ((o & mask1[row]) == bits1[row]) + v |= outputs1[row]; + } + ored1[o] = v; + } + + for (int n = 0; n < 175; ++n) { + int o; + for (o = 0; o < 524288; ++o) { + int v = 0; + for (int row = 0; row < 175; ++row) { + if (row == n) + continue; + if ((o & mask1[row]) == bits1[row]) + v |= outputs1[row]; + } + if (v != ored1[o]) + break; + } + if (o == 524288) + console.write(decimal(n) + " was redundant.\n"); + } + + Array bitsets1(524288); + for (int x = 0; x < 0xfff; ++x) { + int nbitsets1 = 0; + for (int o = 0; o < 524288; ++o) { + if (ored1[o] == x) { + bitsets1[nbitsets1]._mask = 0x7ffff; + bitsets1[nbitsets1]._bits = o; + bitsets1[nbitsets1]._output = ored1[o]; + ++nbitsets1; + } + } + while (true) { + bool found = false; + //console.write(decimal(nbitsets1) + "\n"); + for (int o = nbitsets1 - 1; o >= 1; --o) { + for (int o1 = o - 1; o1 >= 0; --o1) { + if (bitsets1[o]._mask != bitsets1[o1]._mask || bitsets1[o]._output != bitsets1[o1]._output) + continue; + DWord b = bitsets1[o]._bits ^ bitsets1[o1]._bits; + if ((b & (b-1)) == 0) { + found = true; + bitsets1[o1]._mask &= ~b; + bitsets1[o1]._bits &= ~b; + for (int o2 = o; o2 < nbitsets1 - 1; ++o2) { + bitsets1[o2]._mask = bitsets1[o2 + 1]._mask; + bitsets1[o2]._bits = bitsets1[o2 + 1]._bits; + bitsets1[o2]._output = bitsets1[o2 + 1]._output; + } + --nbitsets1; + if (o == nbitsets1) + break; + } + } + } + + if (!found) + break; + } + + for (int o = 0; o < nbitsets1; ++o) { + for (int b = 0; b < 19; ++b) { + if ((bitsets1[o]._mask & (1 << b)) == 0) + console.write("?"); + else + if ((bitsets1[o]._bits & (1 << b)) == 0) + console.write("0"); + else + console.write("1"); + } + console.write(" "); + for (int b = 11; b >= 0; --b) { + if ((bitsets1[o]._output & (1 << b)) == 0) + console.write("0"); + else + console.write("1"); + } + console.write(" "); + console.write("\n"); + } + } + } + void dopla4() + { + String input4 = File("pla4_input_new.txt", true).contents(); + String output4 = File("pla4_output_new.txt", true).contents(); + Array mask4(160); + Array bits4(160); + Array outputs4(160); + Array ored4(65536); + for (int r = 0; r < 160; ++r) { + int m = 0; + int b = 0; + for (int i = 0; i < 16; ++i) { + if (input4[r*18 + i] != '.') + m += 1 << i; + if (input4[r*18 + i] == '1') + b += 1 << i; + } + mask4[r] = m; + bits4[r] = b; + int o = 0; + for (int i = 0; i < 18; ++i) { + if (output4[r*20 + i] == '1') + o += 1 << (17 - i); + } + outputs4[r] = o; + } + for (int o = 0; o < 65536; ++o) { + int v = 0; + for (int row = 0; row < 160; ++row) { + if ((o & mask4[row]) == bits4[row]) + v |= outputs4[row]; + } + ored4[o] = v; + } + + //for (int n = 0; n < 160; ++n) { + // int o; + // for (o = 0; o < 65536; ++o) { + // int v = 0; + // for (int row = 0; row < 160; ++row) { + // if (row == n) + // continue; + // if ((o & mask4[row]) == bits4[row]) + // v |= outputs4[row]; + // } + // if (v != ored4[o]) + // break; + // } + // if (o == 65536) + // console.write(decimal(n) + " was redundant.\n"); + //} + + Array bitsets4(65536); + for (int x = 0; x < 262144; ++x) { + int nbitsets4 = 0; + for (int o = 0; o < 65536; ++o) { + if (ored4[o] == x) { + bitsets4[nbitsets4]._mask = 0xffff; + bitsets4[nbitsets4]._bits = o; + bitsets4[nbitsets4]._output = ored4[o]; + ++nbitsets4; + } + } + while (true) { + bool found = false; + //console.write(decimal(nbitsets1) + "\n"); + for (int o = nbitsets4 - 1; o >= 1; --o) { + for (int o1 = o - 1; o1 >= 0; --o1) { + if (bitsets4[o]._mask != bitsets4[o1]._mask || bitsets4[o]._output != bitsets4[o1]._output) + continue; + DWord b = bitsets4[o]._bits ^ bitsets4[o1]._bits; + if ((b & (b-1)) == 0) { + found = true; + bitsets4[o1]._mask &= ~b; + bitsets4[o1]._bits &= ~b; + for (int o2 = o; o2 < nbitsets4 - 1; ++o2) { + bitsets4[o2]._mask = bitsets4[o2 + 1]._mask; + bitsets4[o2]._bits = bitsets4[o2 + 1]._bits; + bitsets4[o2]._output = bitsets4[o2 + 1]._output; + } + --nbitsets4; + if (o == nbitsets4) + break; + } + } + } + + if (!found) + break; + } + + for (int o = 0; o < nbitsets4; ++o) { + for (int b = 0; b < 16; ++b) { + if ((bitsets4[o]._mask & (1 << b)) == 0) + console.write("?"); + else + if ((bitsets4[o]._bits & (1 << b)) == 0) + console.write("0"); + else + console.write("1"); + } + console.write(" "); + for (int b = 17; b >= 0; --b) { + if ((bitsets4[o]._output & (1 << b)) == 0) + console.write("0"); + else + console.write("1"); + } + console.write("\n"); + } + } + } + + String printuop(uint64_t u) + { + static const char* chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&"; + String line; + if (u == 0) + return "====================================="; + for (int i = 0; i < 37; ++i) { + if ((u & (1LL << i)) != 0) { + line += codePoint(chars[i]); + } + else + line += " "; + } + return line; + } + + void run() { + dorom1(); +#if 0 + dopla4(); +#endif + + String inputL = File("bits_l.py", true).contents(); + String inputR = File("bits_r.py", true).contents(); + String outputL = File("bits_addr_l.py", true).contents(); + String outputR = File("bits_addr_r.py", true).contents(); + Array mask(368); + Array bits(368); + Array outputs(368); + Array ored(8192); + //Array oredL(8192); + //Array oredR(8192); + for (int row = 0; row < 368; ++row) { + mask[row] = 0; + bits[row] = 0; + outputs[row] = 0; + } + for (int row = 0; row < 368; ++row) { + String input = inputL; + String output = outputL; + int r = row; + if (row >= 184) { + input = inputR; + output = outputR; + r -= 184; + } + int m = 0; + int b = 0; + for (int i = 0; i < 13; ++i) { + if (input[r*58 + i*4 + 10] == '1' || input[r*58 + i*4 + 12] == '1') + m += 1 << (12 - i); + if (input[r*58 + i*4 + 12] == '1') + b += 1 << (12 - i); + } + mask[row] = m; + bits[row] = b; + int o = 0; + for (int i = 0; i < 16; ++i) { + if (output[r*38 + i*2 + 10] == '1') + o += 1 << i; + } + outputs[row] = o; + } + for (int o = 0; o < 8192; ++o) { + int v = 0; + for (int row = 0; row < 368; ++row) { + if ((o & mask[row]) == bits[row]) + v |= outputs[row]; + } + ored[o] = v; + if ((v & 0xfff) >= 2560) { + console.write("ored[" + hex(o, 4, false) + "] = " + hex(v, 4, false) + "\n"); + } + //int vL = 0; + //for (int row = 0; row < 184; ++row) { + // if ((o & mask[row]) == bits[row]) + // vL |= outputs[row]; + //} + //oredL[o] = vL; + //int vR = 0; + //for (int row = 184; row < 368; ++row) { + // if ((o & mask[row]) == bits[row]) + // vR |= outputs[row]; + //} + //oredR[o] = vR; + //ored[o] = vL | vR; + } + Array bitsets(8192); + + Array data(256*10*37); + + String s = File("Image (3).raw", true).contents(); + for (int row = 0; row < 37; ++row) { + for (int y = 0; y < 10; ++y) { + for (int x = 0; x < 256; ++x) { + data[row + (x+y*256)*37] = (s[row*256*10 + y*256 + (x^1)] == 0 ? 0x00 : 0xff); + } + } + } +#if 0 + for (int x = 0; x < 2560; ++x) { + bool empty = true; + for (int row = 0; row < 37; ++row) { + if (data[row + x*37] != 0) + empty = false; + } + if (empty) { + for (int row = 0; row < 37; ++row) { + data[row + x*37] = 0x80; + } + int yy = x/256; + int xx = (x & 0xff) ^1; + for (int i = 0; i < 8; ++i) + printf("%c", ((xx >> (7 - i)) & 1) + '0'); + printf(" "); + printf("%c\n", yy + 'A'); + } + } +#endif + + //for (int row = 0; row < 37; ++row) { + // String s = File("blobs\\blob_row_" + decimal(row, 2) + ".txt", true).contents(); + // int p = 0; + // for (int y = 0; y < 10; ++y) { + // for (int x = 0; x < 256; ++x) { + // //data[x+y*256+row*2560] = s[p]; + // //data[row + (x*10+y)*37] = s[p]; + // data[row + (x+y*256)*37] = (s[p] == '0' ? 0x00 : 0xff); + // ++p; + // } + // p += 2; + // } + //} + File("blob.raw").openWrite().write(data); + + //Array ent(37*37); + //for (int start = 0; start < 37; ++start) { + // for (int end = 0; end < start; ++end) { + // printf(" "); + // ent[end + start*37] = 0; + // } + // for (int end = start; end < 37; ++end) { + // uint64_t value[2560]; + // uint64_t count[2560]; + // int used = 0; + // for (int p = 0; p < 2560; ++p) { + // uint64_t v = 0; + // for (int bit = start; bit <= end; ++bit) + // if (data[p*37 + bit] != 0) + // v += (1 << (bit - start)); + // int found = -1; + // for (int search = 0; search < used; ++search) + // if (value[search] == v) { + // found = search; + // break; + // } + // if (found == -1) { + // found = used; + // value[found] = v; + // count[found] = 0; + // ++used; + // } + // ++count[found]; + // } + // double entropy = 0; + // for (int i = 0; i < used; ++i) { + // double probability = count[i]/2560.0; + // entropy -= probability*log(probability)/log(2); + // } + // double entropy_per_bit = entropy/(end + 1 - start); + // printf("%0.2f ",entropy_per_bit); + // ent[end + start*37] = static_cast(entropy_per_bit*0xff); + // } + // printf("\n"); + //} + //File("entropy.raw").openWrite().write(ent); +#if 0 + for (int x = 0; x < 2560 - 2; ++x) { + for (int r1p = 0; r1p < 37 - 7; ++r1p) { + for (int r2p = 0; r2p < 37 - 7; ++r2p) { + int dst[3]; + int src[3]; + for (int y = 0; y < 3; ++y) { + dst[y] = 0; + for (int b1 = 0; b1 < 7; ++b1) + if (data[(x + y)*37 + b1 + r1p] != 0) + dst[y] += (1 << b1); + src[y] = 0; + for (int b2 = 0; b2 < 7; ++b2) + if (data[(x + y)*37 + b2 + r2p] != 0) + src[y] += (1 << b2); + } + //if (dst[0] == src[1] && dst[1] == src[2] && dst[2] == src[0] && dst[0] != dst[1] && dst[1] != dst[2] && dst[2] != dst[0]) { + if (dst[0] == src[2] && dst[1] == src[0] && dst[2] == src[1] && dst[0] != dst[1] && dst[1] != dst[2] && dst[2] != dst[0]) { + printf("Potential XCHG at %03x offsets %i,%i regnums %02x,%02x,%02x\n",2559 - x - 2,r1p,r2p, dst[0], dst[1], dst[2]); + } + } + } + } +#endif + int usedS[64]; + int usedD[128]; + int usedA[64]; + int usedAJ[128]; + int usedBus[64]; + int usedOp[8]; + int usedSub[4]; + int lastS[64]; + int lastD[128]; + int lastA[64]; + int lastAJ[128]; + int lastBus[64]; + for (int i = 0; i < 64; ++i) { + usedS[i] = 0; + usedD[i] = 0; + usedD[i + 64] = 0; + usedA[i] = 0; + usedAJ[i] = 0; + usedAJ[i + 64] = 0; + usedBus[i] = 0; + } + for (int i = 0; i < 4; ++i) { + usedOp[i] = 0; + usedOp[i + 4] = 0; + usedSub[i] = 0; + } + + String regnames_source[64]; + for (int i = 0; i < 64; ++i) + regnames_source[i] = " "; //"[-" + hex(i,2,false) + "-]"; + String regnames_dest[128]; + for (int i = 0; i < 128; ++i) + regnames_dest[i] = " "; //"(-" + hex(i, 2, false) + "-)"; + String regnames_alu[128]; + for (int i = 0; i < 64; ++i) + regnames_alu[i] = " "; //"<-" + hex(i, 2, false) + "->"; + String alujump_names[128]; + for (int i = 0; i < 128; ++i) + alujump_names[i] = " "; //"{-" + hex(i, 2, false) + "-}"; + String busop_names[64]; + for (int i = 0; i < 64; ++i) + busop_names[i] = " "; //<" + hex(i, 2, false) + ">"; + String opnames[8]; + for (int i = 0; i < 8; ++i) + opnames[i] = " "; //[" + hex(i, 1, false) + "]"; + String subopnames[4]; + for (int i = 0; i < 4; ++i) + subopnames[i] = " "; //(" + hex(i, 1, false) + ")"; + String testnames[64]; + for (int i = 0; i < 64; ++i) + testnames[i] = "<" + hex(i, 2, false) + ">"; + + regnames_source[0x00] = "EAX "; // 3 AAA/AAS/DAA/DAS and REP STOS Could be EAX - STOS copies to OPR_W but that needs to know size anyway + regnames_dest [0x00] = "EAX "; // 3 + regnames_dest [0x40] = "AX "; // 2 AAA/AAS and FSTSW AX + regnames_alu [0x00] = "EAX "; // 1 902 + regnames_source[0x01] = "ECX "; // 4 rot/SHxD + // regnames_dest [0x01] = "ECX "; + // regnames_dest [0x41] = "CX "; + regnames_alu [0x01] = "ECX "; // 2 rot + regnames_source[0x02] = "EDX "; // 8 + regnames_dest [0x02] = "EDX "; // 1 BOOTUP + // regnames_dest [0x42] = "DX "; + regnames_alu [0x02] = "EDX "; + // regnames_source[0x03] = "EBX "; + // regnames_dest [0x03] = "EBX "; + // regnames_dest [0x43] = "BX "; + regnames_alu [0x03] = "EBX "; + regnames_source[0x04] = "ESP "; // 25 + regnames_dest [0x04] = "ESP "; // 2 + // regnames_dest [0x44] = "SP "; + regnames_alu [0x04] = "ESP "; // 1 60C + regnames_source[0x05] = "EBP "; // 4 ENTER/LEAVE + regnames_dest [0x05] = "EBP "; // 2 ENTER/LEAVE + regnames_dest [0x45] = "BP "; // 2 ENTER/LEAVE + regnames_alu [0x05] = "EBP "; + regnames_source[0x06] = "ESI "; // 10 [REP] MOVS/[REP] CMPS/[REP] LODS/[REP] OUTS + // regnames_dest [0x06] = "ESI "; + // regnames_dest [0x46] = "SI "; + regnames_alu [0x06] = "ESI "; // 2 + regnames_source[0x07] = "EDI "; // 19 PUSHAd(?)/[REP] MOVS/[REP] CMPS/[REP] SCAS/[REP] STOS/[REP] INS + // regnames_dest [0x07] = "EDI "; + // regnames_dest [0x47] = "DI "; + regnames_alu [0x07] = "EDI "; // 2 + regnames_source[0x08] = "EIP "; // 44 + regnames_dest [0x08] = "EIP "; // 3 RPTI, DR/TR, ??? - always used with [-16-] + regnames_dest [0x48] = "IP "; // 1 649 + regnames_alu [0x08] = "IMM8 "; // 10 JCXZ/LOOP/LOOPE/LOOPNE/Jcond/JMP/CALL/ENTER/VERR/VERW + regnames_source[0x09] = "EFLAGS"; // 22 LAHF , RPTI, + regnames_dest [0x09] = "EFLAGS"; // 10 + regnames_dest [0x49] = "FLAGS "; // 3 IRETd/POPFd/INT ib + regnames_alu [0x09] = "IMM "; // 12 + regnames_source[0x0A] = "CR0 "; // 30 MSW is the low 16 bits of CR0 + regnames_dest [0x0A] = "CR0 "; // 7 + // regnames_dest [0x4A] = " "; + // regnames_alu [0x0A] = " "; + regnames_source[0x0B] = "TMPB "; // 67 + regnames_dest [0x0B] = "TMPB "; // 125 + // regnames_dest [0x4B] = " "; + regnames_alu [0x0B] = "TMPB "; // 96 + regnames_source[0x0C] = "TMPC "; // 31 + regnames_dest [0x0C] = "TMPC "; // 73 + // regnames_dest [0x4C] = " "; + regnames_alu [0x0C] = "TMPC "; // 52 + regnames_source[0x0D] = "TMPD "; // 10 + regnames_dest [0x0D] = "TMPD "; // 44 + regnames_dest [0x4D] = "DESPTR"; // 7 LIDTGDT_COMMON/LD_SEGREG_PASS/PRESENT_TSS/PROT_TESTS_PASSED/PROT_TESTS_PASSED2/PASSED_0B_0D descriptor mentioned in dest of last SPTR + regnames_alu [0x0D] = "TMPD "; // 37 + regnames_source[0x0E] = "TMPE "; // 29 + regnames_dest [0x0E] = "TMPE "; // 22 + regnames_dest [0x4E] = "DESSDT"; // 6 LTR/? Either DESGDT or DESIDT depending on the Table Indictor bit in the selector? Which selector? SLCTR? source? + // regnames_alu [0x0E] = " "; + regnames_source[0x0F] = "TMPF "; // 9 Low 16 bits of TMPF are used for FP (opcode?). Bits 16-18 are used for error code + regnames_dest [0x0F] = "TMPF "; // 11 + // regnames_dest [0x4F] = " "; + // regnames_alu [0x0F] = " "; + regnames_source[0x10] = "FLAGSB"; // 8 + regnames_dest [0x10] = "FLAGSB"; // 14 + regnames_dest [0x50] = "AL "; // 5 SALC/DAA/DAS/AAM/AAD + // regnames_alu [0x10] = " "; + regnames_source[0x11] = "TMPH "; // 25 + regnames_dest [0x11] = "TMPH "; // 18 + // regnames_dest [0x51] = "CL "; + // regnames_alu [0x11] = " "; + regnames_source[0x12] = "TMPG "; // 43 + regnames_dest [0x12] = "TMPG "; // 32 + // regnames_dest [0x52] = "DL "; + // regnames_alu [0x12] = " "; + regnames_source[0x13] = "SLCTR2"; // 32 Related to SLCTR? + regnames_dest [0x13] = "SLCTR2"; // 11 + // regnames_dest [0x53] = "BL "; + // regnames_alu [0x13] = " "; + regnames_source[0x14] = "COUNTR"; // 63 + regnames_dest [0x14] = "MDTMP4"; // 11 Could this be the same as (-1D-)/MDTMP? Some routines outside of mul/div seem to use [-1D-]/(-14-) as a temp. Maybe (-1D-) has special powers? + regnames_dest [0x54] = "AH "; // 3 LAHF/AAM/AAD + regnames_alu [0x14] = "0x3ddc0c2c"; // 1 9B8 Expected result of built-in self-test (BIST) + regnames_source[0x15] = "PROTUN"; // 18 protection test unit + regnames_dest [0x15] = "PROTUN"; // 59 + // regnames_dest [0x55] = "CH "; + regnames_alu [0x15] = "0x0303"; // 1 9B5 + regnames_source[0x16] = "TMPeIP"; // 23 + regnames_dest [0x16] = "TMPeIP"; // 9 + // regnames_dest [0x56] = "DH "; + regnames_alu [0x16] = "0x37fd7"; // 5 + regnames_source[0x17] = "TMPeSP"; // 33 + regnames_dest [0x17] = "TMPeSP"; // 7 + // regnames_dest [0x57] = "BH "; + regnames_alu [0x17] = "0x4000"; // 7 + regnames_source[0x18] = "DR6 "; // 9 + regnames_dest [0x18] = "DR6 "; // 9 + regnames_dest [0x58] = "DESCSW"; // 5 Descriptor that uses base and limit from CS descriptor but is writeable + regnames_alu [0x18] = "~0x200"; // 1 790 + regnames_source[0x19] = "DR7 "; // 8 + regnames_dest [0x19] = "DR7 "; // 7 + regnames_dest [0x59] = "DESCOD"; // 23 Descriptor for eIP changes (DES_CS is only used for updating the CS descriptor) + regnames_alu [0x19] = "8 "; // 3 + regnames_source[0x1A] = "CSOPCD"; // 7 CSOPCD, TMPN and TMPO are only used by FSAVE. + regnames_dest [0x1A] = "CSOPCD"; // 6 + regnames_dest [0x5A] = "DESSTK"; // 24 Descriptor for stack reads/writes (DES_SS is only used for updating the stack descriptor) + regnames_alu [0x1A] = "0x40 "; // 2 + regnames_source[0x1B] = "FSVeIP"; // 2 + regnames_dest [0x1B] = "FSVeIP"; // 7 + // regnames_dest [0x5B] = " "; + regnames_alu [0x1B] = "0xf0000"; // 2 + regnames_source[0x1C] = "OPROFF"; // 12 + regnames_dest [0x1C] = "OPROFF"; // 6 + regnames_dest [0x5C] = "eSP "; // 39 + regnames_alu [0x1C] = "0x0d "; // 9 + regnames_source[0x1D] = "MDTMP "; // 15 quotient after division, product after multiplication? + regnames_dest [0x1D] = "MDTMP "; // 7 one of the multiplier inputs? + regnames_dest [0x5D] = "DES_OS"; // 37 strings, XLAT, - but used in "POP m" and SGDT with no ALU op - like IND_DS but "overrideable segment" (uses DS for bus operation unless a segment override is active, in which case use that segment) + regnames_alu [0x1D] = "0x5d "; // 4 + regnames_source[0x1E] = "SIGMA "; // 533 + // regnames_dest [0x1E] = " "; + regnames_dest [0x5E] = "DES_SR"; // 11 Like other IND_ registers but are written to when segment registers are updated + regnames_alu [0x1E] = "0x800000f8"; // 3 + regnames_source[0x1F] = "IMM "; // 36 + // regnames_dest [0x1F] = " "; + regnames_dest [0x5F] = "eIP "; // 9 + regnames_alu [0x1F] = "0x800000fc"; // 5 + + regnames_source[0x20] = "ES "; // 5 + regnames_dest [0x20] = "ES "; // 7 + regnames_dest [0x60] = "DES_ES"; // 33 + regnames_alu [0x20] = "0x70 "; // 2 + regnames_source[0x21] = "CS "; // 49 + regnames_dest [0x21] = "CS "; // 6 + regnames_dest [0x61] = "DES_CS"; // 25 + regnames_alu [0x21] = "0x73 "; // 1 9A9 + regnames_source[0x22] = "SS "; // 26 + regnames_dest [0x22] = "SS "; // 5 + regnames_dest [0x62] = "DES_SS"; // 8 + regnames_alu [0x22] = "0x1ff "; // 1 336 + regnames_source[0x23] = "DS "; // 6 + regnames_dest [0x23] = "DS "; // 6 + regnames_dest [0x63] = "DES_DS"; // 5 + regnames_alu [0x23] = "0x8200"; // 11 + regnames_source[0x24] = "FS "; // 4 + regnames_dest [0x24] = "FS "; // 4 + regnames_dest [0x64] = "DES_FS"; // 4 + regnames_alu [0x24] = "0x47 "; // 1 091 + regnames_source[0x25] = "GS "; // 8 + regnames_dest [0x25] = "GS "; // 4 + regnames_dest [0x65] = "DES_GS"; // 4 + regnames_alu [0x25] = "3 "; // 16 + regnames_source[0x26] = "LDTR "; // 6 + regnames_dest [0x26] = "LDTR "; // 4 + regnames_dest [0x66] = "DESLDT"; // 5 + regnames_alu [0x26] = "6 "; // 5 + // regnames_source[0x27] = " "; + // regnames_dest [0x27] = " "; + regnames_dest [0x67] = "DESGDT"; // 3 + regnames_alu [0x27] = "0xffff0000"; // 9 + regnames_source[0x28] = "eAX_AL"; // 15 AAM/AAD/MUL/IMUL/DIV/IDIV/CWD/CDQ/[REP] SCAS/XLATB/STOS/OUT + regnames_dest [0x28] = "eAX_AL"; // 7 MUL/IMUL/DIV/IDIV/[REP] LODS/XLATB/IN + regnames_dest [0x68] = "DESIDT"; // 5 + regnames_alu [0x28] = "0x60 "; // 2 + regnames_source[0x29] = "TR "; // 9 + regnames_dest [0x29] = "TR "; // 5 + regnames_dest [0x69] = "DES_TR"; // 28 + + regnames_alu [0x29] = "0x7ff "; // 3 + regnames_source[0x2A] = "eDX_AH"; // 6 SAHF/AAD/DIV/IDIV + regnames_dest [0x2A] = "eDX_AH"; // 4 MUL/IMUL/DIV/IDIV/CWD/CDQ + regnames_dest [0x6A] = "DESABS"; // 14 bus operation in which IND is placed on the address bus without any paging translation - used for halt/shutdown/interrupt acknowledge bus cycles and other debugging information placed on the address bus + regnames_alu [0x2A] = "9 "; // 4 + regnames_source[0x2B] = "CR2 "; // 1 378 Contains a value called Page Fault Linear Address (PFLA). When a page fault occurs, the address the program attempted to access is stored in the CR2 register. + regnames_dest [0x2B] = "CR2 "; // 4 + regnames_dest [0x6B] = "DES_IO"; // 33 used for access to IO ports DES_IO + regnames_alu [0x2B] = "0x29 "; // 9 LDCNTR in reset (002) + // regnames_source[0x2C] = " "; + // regnames_dest [0x2C] = " "; + regnames_dest [0x6C] = "DESERR"; // 1 ACCESS_VIOLATI - descriptor that caused the fault + regnames_alu [0x2C] = "7 "; // 13 + regnames_source[0x2D] = "OPR_R "; // 156 It's tempting to call both OPR_R and OPR_W just OPR, but they do seem to be separate: look at 07E - OPR_R is available here (used on uop after DLY in other instructions) and used at line 080 but OPR_W is overwritten with eIP... + regnames_dest [0x2D] = "OPR_W "; // 102 ...however, on line 083 OPR_R is never copied to OPR_W. Maybe "wr" writes from OPR_R? + // regnames_dest [0x6D] = " "; + regnames_alu [0x2D] = "0x0f "; // 5 + regnames_source[0x2E] = "IRF2 "; // 53 + // regnames_dest [0x2E] = " "; + // regnames_dest [0x6E] = " "; + regnames_alu [0x2E] = "0x65 "; // 3 + regnames_source[0x2F] = "BIST1 "; // 1 9B5 + // regnames_dest [0x2F] = " "; + // regnames_dest [0x6F] = " "; + regnames_alu [0x2F] = "0x1f "; // 2 + regnames_source[0x30] = "BIST2 "; // 1 9B7 + // regnames_dest [0x30] = " "; + // regnames_dest [0x70] = "DR0 "; + regnames_alu [0x30] = "1 "; // 43 + regnames_source[0x31] = "eCX "; // 11 + regnames_dest [0x31] = "eCX "; // 16 + // regnames_dest [0x71] = "DR1 "; + regnames_alu [0x31] = "2 "; // 13 + // regnames_source[0x32] = " "; + regnames_dest [0x32] = "COUNTR"; // 60 IRF index? Temp related to [-14-]? + // regnames_dest [0x72] = "DR2 "; + regnames_alu [0x32] = "0x10 "; // 11 + // regnames_source[0x33] = " "; + // regnames_dest [0x33] = " "; + // regnames_dest [0x73] = "DR3 "; + regnames_alu [0x33] = "4 "; // 16 + // regnames_source[0x34] = " "; + // regnames_dest [0x34] = " "; + // regnames_dest [0x74] = "TR4 "; + regnames_alu [0x34] = "-1 "; // 10 + regnames_source[0x35] = "SLCTR "; // 6 selector to load (pointer into LDT/GDT)? + regnames_dest [0x35] = "SLCTR "; // 33 selector to load (pointer into LDT/GDT)? + // regnames_dest [0x75] = "TR5 "; + regnames_alu [0x35] = "-2 "; // 3 + regnames_source[0x36] = "EA "; // 3 not eSI + regnames_dest [0x36] = "eSI "; // 11 + // regnames_dest [0x76] = "TR6 "; + regnames_alu [0x36] = "0xffff"; // 39 + // regnames_source[0x37] = "eDI "; + regnames_dest [0x37] = "eDI "; // 13 + // regnames_dest [0x77] = "TR7 "; + regnames_alu [0x37] = "-4 "; // 8 + regnames_source[0x38] = "0 "; // 106 + regnames_dest [0x38] = "FLAGSL"; // 1 0DA SAHF + regnames_dest [0x78] = "LATTTF"; // 1 PAGE_FAULT Related to paging linear address that triggered the fault + // regnames_alu [0x38] = " "; + regnames_source[0x39] = "IRF "; // 7 + regnames_dest [0x39] = "IRF "; // 38 Indirect access to Register File + regnames_dest [0x79] = "PGUNUS"; // 1 unused? Related to paging linear address that triggered the fault again (value ends up in CR2 anyway like LATTTF - could have had a different meaning here) + regnames_alu [0x39] = "WORDSZ"; // 25 + // regnames_source[0x3A] = " "; + regnames_dest [0x3A] = "COUNT5"; // 6 COUNTR except that all but low 5 bits are masked off RCL/RCR/ENTER_COMMON/CALL_FAR_PM_GATE + regnames_dest [0x7A] = "PFERRC"; // 2 PAGE_FAULT/unused? Related to paging page fault error code + regnames_alu [0x3A] = "NEGWSZ"; // 22 negative word size in bytes (-2 or -4) (0xfffffffe or 0xfffffffc) + regnames_source[0x3B] = "OPCODE"; // 8 As stored by FSAVE/FSTENV - 0 to 0x7ff + // regnames_dest [0x3B] = " "; + regnames_dest [0x7B] = "PDBR "; // 11 Page directory base register (aka CR3) - write to this to flush TLB cache + regnames_alu [0x3B] = "INCREM"; // 32 eSI/eDI increment for string instructions (+/- 1/2/4) + regnames_source[0x3C] = "SEGREG"; // 3 + regnames_dest [0x3C] = "SEGREG"; // 9 + // regnames_dest [0x7C] = " "; + regnames_alu [0x3C] = "BITS_V"; // 21 one less than word size in bits (15 or 31) + regnames_source[0x3D] = "DSTREG"; // 37 + regnames_dest [0x3D] = "DSTREG"; // 30 + regnames_dest [0x7D] = "PAGER5"; // 12 + regnames_alu [0x3D] = "DSTREG"; // 12 + regnames_source[0x3E] = "SRCREG"; // 21 + regnames_dest [0x3E] = "SRCREG"; // 22 + // regnames_dest [0x7E] = " "; + regnames_alu [0x3E] = "SRCREG"; // 7 + regnames_source[0x3F] = "-1 "; // 95 SALC + // regnames_dest [0x3F] = " "; + regnames_dest [0x7F] = " "; // 550 + regnames_alu [0x3F] = "0 "; + alujump_names[0x00] = "+-&|^ "; // 5 + alujump_names[0x01] = "++--~-"; // 2 + alujump_names[0x02] = "<<>>? "; // 13 + alujump_names[0x03] = "CMPTST"; // 5 + alujump_names[0x04] = "IMCS "; // 1 1BA IMUL Correct Sign. Corrects for sign regardless of opcode + alujump_names[0x05] = "SERECO"; // 4 BTS/BTR/BTC SEt, REset, COmplement according to which opcode used. Actual operation is either ALU1 OR ALU2, ALU1 AND NOT ALU2 or ALU1 XOR ALU2. There's a shift in there too? + alujump_names[0x06] = "SZ_EXT"; // 4 MOVZX/MOVSX/CBW/CWDE + alujump_names[0x07] = "SZ_EX2"; // 1 1AC MUL/IMUL rm - binary operation. Correct upper part of multiplication for sign in IMUL case. Not sure how this is different from SZ_EXT + alujump_names[0x08] = "AND "; // 84 ok + alujump_names[0x09] = "OR "; // 41 probably not SUB - used to clear (or set?) resume flag in RPTI? - AND NOT? Also used in JMP cp + alujump_names[0x0A] = "XOR "; // 13 + alujump_names[0x0B] = "SIGN "; // 4 probably not CMP - BT/BTS/BTR/BTC/CWD/CDQ/77a SIGMA is sign-extension of input + alujump_names[0x0C] = "ADD "; // 123 ok + alujump_names[0x0D] = "ADC "; // 2 Used in AAM and AAD + alujump_names[0x0E] = "SUB "; // 36 probably not ADC - SUB? + alujump_names[0x0F] = "CMP "; // 8 porbably not SBB - SUB? CMP? + alujump_names[0x10] = "SHIFT "; // 72 + alujump_names[0x11] = "BITTST"; // 11 BT/BTS/BTR/BTC/BSF - does a shift and copies the lowest bit into the carry flag? + alujump_names[0x12] = ">>< 0) in CLTS/HLT/LIDT/LGDT/LLDT/LMSW/CRn/DRn/TRn/LTR/LOADALL386, (PM && CPL > IOPL) in PORTIO_PROTCHK + alujump_names[0x73] = "LJMPVM"; // 6 IRETd (p)/??? long jump only in virtual 8086 mode + alujump_names[0x74] = "LJMPP "; // 17 long jump only in protected mode + alujump_names[0x75] = "ICEENT"; // 2 ICE_SINGLESTEP/ICE_PIN - send some signal to ICE? Always happens right before STOREALL - enter ICE mode + alujump_names[0x76] = "ICEEXT"; // 1 LOADALL386 - tell ICE that LOADALL completed successfully - exit ICE mode + // alujump_names[0x77] = " "; + alujump_names[0x78] = "LDBSRM"; // 14 SHRCNT = alu2 & BITS_V; initialise the barrel shift amount (right) with the value from the register mentioned in the ALU2 source? + alujump_names[0x79] = "LDBSLM"; // 5 SHLCNT = alu2 & BITS_V; + alujump_names[0x7A] = "LDBSRU"; // 26 SHRCNT = alu2 & 0x1f; BT/BTS/BTR/BTC/BSF/PORTIO_PROTCHK/MOV r<->DR/MOV r<->TR/FSAVE/FRSTOR/LSL initialise the barrel shift amount (right) with the value from the register mentioned in the ALU2 source? + alujump_names[0x7B] = "LDBSLU"; // 37 SHLCNT = alu2 & 0x1f; + alujump_names[0x7C] = "RETURN"; // 14 + alujump_names[0x7D] = "ICESIG"; // 10 HLT/FPU_FLAG*/HARDWARE_IRQ/TRIPLE_FAULT*/FAULT*/INTERRUPT/PAGE_FAULT*/SINGLE_STEP*/ICE_PIN* - send a signal to the ICE that something interesting is happening (*ICE has the opportunity to pause the microcode right after this) + alujump_names[0x7E] = "PAGEFT"; // 1 PAGE_FAULT - not sure if this notifies ICE or the paging unit or both or something else that page fault handling has started + alujump_names[0x7F] = " "; // 801 + + // busop_names[0x00] = " "; + // busop_names[0x01] = " "; + // busop_names[0x02] = " "; + // busop_names[0x03] = " "; + // busop_names[0x04] = "rd B"; + busop_names[0x05] = "rd W"; // 1 IRETd_HELPER4 + busop_names[0x06] = "rd "; // 1 0B1 XCHG rm,r + busop_names[0x07] = "rd D"; // 9 LSSFSGS_HELPER/LOAD_SEGR_HELP/RETF_HELPER3/LAR_LSL_VERRW2/INT_HELPER TODO: Figure out the difference between rd and RD . rd automatically asserts LOCK#? "LOCK# is also asserted automatically for an XCHG instruction, a descriptor update, interrupt acknowledge cycles, and a page table update" (HRM 3.5.1) + busop_names[0x08] = "CW B"; // 4 FSAVE_CORE/FPU_STORE_CORE Perform access/limit/paging checks for writes but don't actually do a write + // busop_names[0x09] = "CW W"; + busop_names[0x0A] = "CW "; // 4 RCL/RCR rm,CL / INS / ENTER_COMMON + // busop_names[0x0B] = "CW D"; + busop_names[0x0C] = "CR B"; // 4 FRSTOR_CORE/FPU_LD80_CORE Perform access/limit/paging checks for reads but don't actually do a read + // busop_names[0x0D] = "CR W"; + // busop_names[0x0E] = "CR "; + // busop_names[0x0F] = "CR D"; + // busop_names[0x10] = "WR B"; + busop_names[0x11] = "WR W"; // 41 + busop_names[0x12] = "WR "; // 49 + busop_names[0x13] = "WR D"; // 11 + // busop_names[0x14] = "RD B"; + busop_names[0x15] = "RD W"; // 43 + busop_names[0x16] = "RD "; // 101 + busop_names[0x17] = "RD D"; // 21 LGDT/PR_LD_SS/LLDT/LOADALL386/??? + // busop_names[0x18] = "wr B"; + busop_names[0x19] = "wr W"; // 5 The difference between wr* and WR* seems to be that WR* is used in combination with a copy to OPR_W whereas wr* is for writing back something that was just read, so the data is in OPR_R + busop_names[0x1A] = "wr "; // 24 + // busop_names[0x1B] = "wr D"; + busop_names[0x1C] = "PREF"; // 19 Start prefetch at IND? + busop_names[0x1D] = "IN+D"; // 70 PUSHAd, IRETd IND += IND_DELTA + // busop_names[0x1E] = " "; + busop_names[0x1F] = "IN+="; // 61 IND = IND + alu2 IND_DELTA = alu2 <-3F-> (0?), -2, -4, 0x0d, 0x5d, 1, 2, 3, 4, 7, 9, INCREM, NEGWSZ, TMPB, TMPC, WORDSZ + // busop_names[0x20] = " "; + // busop_names[0x21] = " "; + // busop_names[0x22] = " "; + // busop_names[0x23] = " "; + busop_names[0x24] = "IN=2"; // 25 IND = alu2 dest = IND_IO, IND_Rf, IND_TR, // Theory: {2C}-{39} all select parts/fields of a descriptor cache entry or selector in conjunction with IND_* sources/dests + busop_names[0x25] = "IND="; // 103 IND = source dest = n/a (LJUMP), (-58), INDIDT, INDSTK, INC_CS, IND_ES, IND_IO, IND_IP, IND_OS, IND_RF, IND_TR + busop_names[0x26] = "IN=+"; // 53 IND = source + alu2 IND_DELTA = alu2 dest = (-4E), (-58-), INDIDT, INDSTK, IND_ES, IND_IP, IND_OS, IND_RF, IND_TR + // busop_names[0x27] = " "; + busop_names[0x28] = "IACK"; // 2 Interrupt Acknowledge bus cycle HARDWARE_IRQ (asserts LOCK# like "rd") + // busop_names[0x29] = " "; + // busop_names[0x2A] = " "; + // busop_names[0x2B] = " "; + busop_names[0x2C] = "SBRM"; // 23 Set BASE in Real Mode (to segment << 4) dest = DS, ES, FS, GS, IND_CS, IND_DS, IND_ES, IND_FS, IND_GS, IND_SR, IND_SS, IRF, SS Also set LIMIT to 0xffff? Sets Access Rights? + busop_names[0x2D] = "SDEH"; // 11 dest = (-4D-), INDLDT, IND_CS, IND_SS, IND_TR, IRF LD_SEGREG_PASS/PRESENT_TSS/PROT_TESTS_PASSED/PROT_TESTS_PASSED2/CALL_UNPRIV/RETF_HELPERRET/LLDT_TEST_PASS/CALL_SAVE_TASK/SWITCH_TASK/PASSED_0B_0D set descriptor high dword (sets byte 3 of base, byte 2 (G/DB/-/A bits) of access, and byte 2 (bits 16-19) of limit) + busop_names[0x2E] = "SDES"; // 7 LD_SEGREG_PASS/PROT_TESTS_PASSED/PROT_TESTS_PASSED2/CALL_UNPRIV/CALL_SAVE_TASK/SWITCH_TASK uses alu2 (TMPB, TMPC, TMPD) set descriptor shifted dword (sets byte 3 (P/DPL/S/Type) bits of access, and bytes 0-2 of base) + busop_names[0x2F] = "SDEL"; // 30 segreg load/JMP_FAR_PM/CALL_FAR_PM/CALL_UNPRIV/TASK_RETURN/IRETd/RETF_HELPER3/LTR/LLDT/LOAD_TASK/TASK_FINAL_V86/TASK_FINAL_PM/TRAPGATE/INTGATE uses alu2 (mostly TMPC, one TMPD) set descriptor low dword (sets bytes 0-1 of limit) + busop_names[0x30] = "SPCR"; // 18 dest = (-7B-), (-7D-), IRF Store Page Cache Register? + busop_names[0x31] = "SAR "; // 21 select AR field of descriptor cache dest = ES, FS, GS, IND_CS, IND_ES, IRF, INDLDT, IND_GS, IND_FS, IND_DS, IND_SS, IND_ES, IND_TR, DS + busop_names[0x32] = "SBAS"; // 9 select BASE field of descriptor cache dest = DS, (-4D), IRF, IND_TR, IND_RF, IND_IR + busop_names[0x33] = "SLIM"; // 14 select LIMIT field of descriptor cache dest = (-4D-), IRF, IND_TR, IND_RF, IND_IP, IND_CS, IND_ES + busop_names[0x34] = "LPCR"; // 9 MOV rd,CR3/MOV rd,TRn/IRETd_HELPER4/unused?/pla/LOADALL386/DR_ICEBP_HELP2 dest = (-78-), (-79-), (-7A-), (-7B-), IRF Related to paging? - store CR3 to IND? Read special register? Used with TRn Load Page Cache Register into IRF2 + busop_names[0x35] = "LAR "; // 11 JMP cp/RETF_HELPER/RETF_HELPER_*/pla/EXCEPTION/LOADALL386/DR_ICEBP_HELP2 dest = (-15-), (-6C-), IND_CS, IND_DS, IND_ES, IND_FS, IND_GS, IND-SS, IND-TR, IRF load access rights from descriptor cache into IRF2 + busop_names[0x36] = "LBAS"; // 5 SIDT/SGDT/DR_ICEBP_HELP2 dest = INDGDT, INDIDT, IND_TR, IRF load base from descriptor cache into IRF2 + busop_names[0x37] = "LLIM"; // 9 FARJUMP/JMP mp/SIDT/SGDT/SOFTWARE INT/LOADALL386/pla/DR_ICEBP_HELP2 dest = INDGDT, INDIDT, IND_CS, IND_TR, IRF, n/a (LJUMP), (-3F-) load limit from descriptor cache into IRF2 + busop_names[0x38] = "TSDB"; // 3 TASK_RETURN/LOAD_TASK_16B/LOAD_TASK - task switch debug: some external signal that signifies that the address bus contains the old and new values of TR + busop_names[0x39] = "SPTR"; // 40 makes DESPTR correspond to dest + // busop_names[0x3A] = " "; + // busop_names[0x3B] = " "; + busop_names[0x3C] = "HLTS"; // 1 HLT_HELPER dest = (-7F-) - probably outputs HLT/SHUTDOWN signal to motherboard, then the actual waiting is done in the RPT (2) loop at 32b. + // busop_names[0x3D] = " "; + // busop_names[0x3E] = " "; + busop_names[0x3F] = " "; // 1504 + opnames[0] = "RNI"; // 162 RNI must be suppressed if it's in the delay slot - see 3a8 + opnames[1] = "RNi"; // 25 RNI but only if it's executed in the delay slot + opnames[2] = "RnI"; // 5 RNI but disable interrupts for the next instruction + // opnames[3] = " "; + // opnames[4] = " "; + opnames[5] = "FIO"; // 14 FP IO - FSAVE_REGFILE, FRSTOR_REGFILE, FPU_LOAD_CORE, FLDCW, FPU_STORE_CORE, FPU_STORE_287 (when on its own there is a [5] (2) on the line after) - precedes some (but not all) accesses to the FPU port 0x800000fc + opnames[6] = "RPT"; // 19 AAM/AAD/MUL/IMUL/DIV/IDIV/ARPL/ + opnames[7] = " "; // 2141 + subopnames[0] = "DLY"; // 559 Wait for bus operation to complete and update OPR_R if it was a read + subopnames[1] = "UNL"; // 182 Used after a read is complete (but not always immedidately) - to do with bus unlocking? + subopnames[2] = "WIO"; // 12 Used in HLT, FSAVE_REGFILE, FRSTOR_REGFILE, FPU_LOAD_CORE, FLDCW, FPU_STORE_CORE, FPU_STORE_287 (in conjunction with [5] except in HLT) - wait for IO? + subopnames[3] = " "; // 1613 + + // ************** + testnames[0x00] = "TST_SEL_NONSS"; // test non-SS selector for normal load + testnames[0x01] = "TST_SEL_CS"; // test CS selector for normal load + testnames[0x02] = "TST_SEL_RET"; // test selector for RETF + testnames[0x03] = "TST_SEL_RET_OL"; // test selector for RETF_OUTER_LEV + testnames[0x04] = "TST_PORTIO_BIT"; // test port IO permission bitmap bits + testnames[0x05] = "TST_SEL_ARPL"; // test selector for ARPL + testnames[0x06] = "TST_SEL_GDT"; // test that selector is non-null and points into GDT + testnames[0x07] = "TST_SEL_LLDT"; // test selector for LLDT + testnames[0x08] = "TST_SEL_LLVV"; // test selector for LAR/LSL/VERR/VERW + testnames[0x09] = "TST_SEL_MOREPR"; // test SS selector for MORE_PRIVILEGE + testnames[0x0A] = "TST_SEL_TASKGT"; // test TSS selector for TASKGATE + testnames[0x0B] = "TST_SEL_TASKFI"; // test DS/ES/FS/GS selector for TASK_FINAL_PM + testnames[0x0C] = "TST_SEL_SS"; // test SS selector for normal load (similar to TST_SEL_MOREPR but sets L for non-null selectors) + testnames[0x0D] = "TST_SEL_TR_TSF"; // test TR selector for TASK_FINAL + // testnames[0x0E] = " "; // unused + // testnames[0x0F] = " "; // unused + testnames[0x10] = "TST_DES_SIMPLE"; // test descriptor on load (default if not overridden) - descriptor must be present and (conforming code or met the access requirements for non-conforming code) + testnames[0x11] = "TST_DES_SS"; // test SS descriptor for load + testnames[0x12] = "TST_DES_JMP"; // test CS descriptor for jump + testnames[0x13] = "TST_DES_JGATE"; // test CS descriptor for jump gate + testnames[0x14] = "TST_DES_JGDEST"; // test CS descriptor for jump gate destination + testnames[0x15] = "TST_DES_CALL"; // test CS descriptor for call + testnames[0x16] = "TST_DES_CGATE"; // test CS descriptor for call gate + testnames[0x17] = "TST_DES_CGDEST"; // test CS descriptor for call gate destination + testnames[0x18] = "TST_DES_RETF"; // test CS descriptor for + testnames[0x19] = "TST_DES_RTOLSS"; // test SS descriptor for RETF_OUTER_LEV + testnames[0x1A] = "TST_DES_LDTTSK"; // test LDT descriptor for task switch + testnames[0x1B] = "TST_DES_LDT"; // test LDT descriptor for LLDT or v86 task switch + testnames[0x1C] = "TST_DES_MOREPR"; // test stack descriptor for MORE_PRIVILEGE (that is stored in CS) + testnames[0x1D] = "TST_DES_TSSTSG"; // test TSS descriptor for task gate (needs to be available) + testnames[0x1E] = "TST_DES_TSSTSR"; // test TSS descriptor for task return (needs to be busy) + testnames[0x1F] = "TST_DES_TSSLTR"; // test TSS descriptor for LTR (needs to be available and present) + testnames[0x20] = "TST_DES_GRANUL"; // test granularity of descriptor for LSL + testnames[0x21] = "TST_DES_INT_SW"; // test IDT entry descriptor for software interrupt (INT ib, INT 3, INTO) + testnames[0x22] = "TST_DES_INT_HW"; // test IDT entry descriptor for hardware interrutp (IRQ, NMI, fault) + // testnames[0x23] = " "; // unused + testnames[0x24] = "TST_ACCESS_VIO"; // test DESERR? in ACCESS_VIOLATI handler - this doesn't seem to be a descriptor or a selector. Some kind of error number? (goes from 0-9 and 24-26) + testnames[0x25] = "TST_DES_RTOLOS"; // test ordinary (DS/ES/FS/GS) descriptor for RETF_OUTER_LEV + testnames[0x26] = "TST_SEL_LES"; // test selector for LES + testnames[0x27] = "TST_SEL_LDS"; // test selector for LDS + testnames[0x28] = "TST_SEL_LFSLGS"; // test selector for LFS/LGS + // testnames[0x29] = " "; // unused + testnames[0x2A] = "JMP_GFAULT_INT"; // unconditional jump to #GP(I1,E0) with FAULT flag set + testnames[0x2B] = "READ_RPL"; // PORTIO_PROTCHK, ARPL, LOAD_TASK_COMM - seems like it reads the privilege level (RPL) from a selector (in PROTUN) into a 2-bit latch + testnames[0x2C] = "WRITE_RPL"; // MORE_PRIVILEGE - seems like it writes the privilege level from the latch to the low two bits of PROTUN + testnames[0x2D] = "SET_RPL_TO_CPL"; // JUMP_FAR_PM, CALL_FAR_PM, TRAP_INT_GATE - set PROTUN[1..0] = CPL? + testnames[0x2E] = "COPY_STACK_DPL"; // COPY_PARAMS, IRETd_V86, RETF_OUTER_LEV, TASK_FINAL_V86, TASK_FINAL_PM, FAULT, LOADALL, STOREALL - copy DPL from PROTUN to special stack descriptor DPL? (DESSTK.DPL = PROTUN[1..0]?) + testnames[0x2F] = "SET_FAULT"; // signal for the double/triple fault detection logic? (TST_ACCESS_VIO does not set this signal, presumably because the signal from the protection/limit checker is used instead.) Works with the contributory fault bit. + testnames[0x30] = "TST_DES_LAR"; // test descriptor for LAR + testnames[0x31] = "TST_DES_LSL"; // test descriptor for LSL + testnames[0x32] = "TST_DES_VERR"; // test descriptor for VERR + testnames[0x33] = "TST_DES_VERW"; // test descriptor for VERW + testnames[0x34] = "FPU_WAIT"; + // testnames[0x35] = " "; // unused + // testnames[0x36] = " "; // unused + // testnames[0x37] = " "; // unused + testnames[0x38] = "FPU_OTHER"; + testnames[0x39] = "FPU_LOAD_3264"; + // testnames[0x3A] = " "; // unused + testnames[0x3B] = "FPU_LOAD_80"; + testnames[0x3C] = "FPU_STORE_3264"; + testnames[0x3D] = "FPU_STORE_80"; + testnames[0x3E] = "FPU_FSAVE"; + testnames[0x3F] = "FPU_FRSTOR"; + + auto out = File("microcode_10.txt", true).openWrite(); + + String instructions[2560]; + int entryPointer = 0; + for (int i = 0; i < 2560; ++i) { + String s; + while (entryPoints[entryPointer]._u != -1 && entryPoints[entryPointer]._a <= i) { + if (entryPoints[entryPointer]._a == i) { + s = decimal(entryPoints[entryPointer]._u) + " " + /*decimal(entryPoints[entryPointer]._t, 2) + " " +*/ entryPoints[entryPointer]._s; + ++entryPointer; + break; + } + ++entryPointer; + } + instructions[i] = s; + } + uint64_t uops[2560]; + bool next1DNC = false; + bool nextDNC = false; + for (int xx = 0; xx < 2560; ++xx) { + int x = 2559 - xx; + //if (instructions[xx] != "") + if (nextDNC) + out.write("------------------------------------------|----------------------------------------------------------------------------------------------\n"); + nextDNC = next1DNC; + next1DNC = false; + int entryPointer = 0; + while (entryPoints[entryPointer]._u != -1 && entryPoints[entryPointer]._a <= xx) { + if (entryPoints[entryPointer]._a == xx) { + nextDNC = false; + break; + } + ++entryPointer; + } + int alu2 = 0; + for (int b = 0; b < 6; ++b) + if (data[x*37 + 36 - b] == 0xff) // alu source / jump offset = ABCDEF + alu2 += (32 >> b); + alu2 = 63 - alu2; + int dst = 0; + for (int b1 = 0; b1 < 7; ++b1) + if (data[x*37 + 36 - (b1 + 6)] == 0xff) // destination = GHIJKLM + dst += (64 >> b1); + dst = 127 - dst; + int src = 0; + for (int b2 = 0; b2 < 6; ++b2) + if (data[x*37 + 36 - (b2 + 13)] == 0xff) // source = NOPQRS + src += (32 >> b2); + src = 63 - src; + int alujump = 0; + for (int b0 = 0; b0 < 7; ++b0) + if (data[x*37 + 36 - (b0 + 19)] == 0xff) // alu operation / jump condition = TUVWXYZ + alujump += (64 >> b0); + alujump = 127 - alujump; + int opcode = 0; + for (int b = 0; b < 3; ++b) + if (data[x*37 + 36 - (b + 26)] == 0xff) // 012 + opcode += (4 >> b); + opcode = 7 - opcode; + int subcode = 0; + for (int b = 0; b < 2; ++b) + if (data[x*37 + 36 - (b + 29)] == 0xff) // 34 + subcode += (2 >> b); + subcode = 3 - subcode; + int buscode = 0; + for (int b = 0; b < 6; ++b) + if (data[x*37 + 36 - (b + 31)] == 0xff) // 56789& + buscode += (32 >> b); + buscode = 63 - buscode; + + String line = hex(xx,3,false) + " "; + uint64_t uop = 0; + for (int i = 0; i < 37; ++i) { + if (data[x*37 + 36 - i] == 0xff) + uop += 1LL << i; + } + line += printuop(uop); + uops[x] = uop; + + out.write(line + "| "); + if (uop == 0) { + out.write(" " + instructions[xx]); + out.write("\n"); + continue; + } + if (opcode == 0 || opcode == 2 || alujump == 0x5a || alujump == 0x7c || alujump == 0x71 || alujump == 0x4b) + next1DNC = true; + String op = opnames[opcode]; + String subop = subopnames[subcode]; + String busop = busop_names[buscode]; + + bool ljump = (alujump >= 0x70 && alujump <= 0x74); + bool sjump = (alujump >= 0x40 && alujump <= 0x5f); + bool tjump = (alujump >= 0x60 && alujump <= 0x6f); + bool haveDest = (dst != 0x7f); + bool haveNormalDest = ((dst < 0x58 && dst != 0x4d && dst != 0x4e) || dst == 0x5c || dst == 0x5f); + bool haveSrc = ((src != 0x3f) && !ljump); + bool haveAlu2 = ((alu2 != 0x3f ) && !(ljump || sjump || tjump)); + bool aluUnary = (alujump == 1 || alujump == 6 || alujump == 0x0b || alujump == 0x14 || alujump == 0x16 || alujump == 0x17 || alujump == 0x1a || alujump == 0x6a); + bool aluUnary2 = (alujump == 0x15 || alujump == 0x3e || (alujump >= 0x78 && alujump <= 0x7b)); + bool aluBinary = (alujump < 0x20 && !aluUnary && !aluUnary2 && alujump != 0x13); + bool busBinary = (buscode == 0x26); + bool busUnary = (buscode == 0x25 || buscode == 0x2c || buscode == 0x2d || (buscode >= 0x31 && buscode <= 0x33)); + bool busUnary2 = (buscode == 0x1f || buscode == 0x24 || buscode == 0x2d || buscode == 0x2e || buscode == 0x2f); + bool displaySrc = (aluUnary || aluBinary || busUnary || busBinary|| haveNormalDest); + bool displayDest = haveDest; + bool displayArrow = haveNormalDest; + bool displayAlu2 = (aluUnary2 || aluBinary || busUnary2 || busBinary); + //if (ljump && (displayAlu2 || displaySrc)) + // out.write("!!!"); + //if (sjump && displayAlu2) + // out.write("!!!"); + //if (haveDest && !displayDest) + // out.write("!!!"); + //if (haveSrc && !displaySrc && src != 0x2d) // OPR_R seems to appear on its own sometimes - some kind of bus release? + // out.write("!!!"); + //if (haveAlu2 && !displayAlu2) + // out.write("!!!"); + if (haveSrc && !displaySrc) // lines 085, 0b0, 719, 71b, 83c, 86f, 89b and 8ee set source to OPR_R but don't seem to use it. Also 78c sets source to TMP_TR but doesn't seem to use it. + displaySrc = true; + + if (displaySrc) + out.write(regnames_source[src]); + else + out.write(" "); + if (displayArrow) + out.write(" -> "); + else + out.write(" "); + if (displayDest) + out.write(regnames_dest[dst]); + else + out.write(" "); + + + //if (!haveDest && (!haveSrc || ljump)) { + // if (!ljump && aluBinary) + // out.write(String("-1 ") + " " + " "); + // else + // out.write(String(" ") + " " + " "); + //} + //else { + // if (!haveDest) + // out.write(regnames_source[src] + " " + " "); + // else + // out.write(regnames_source[src] + " -> " + regnames_dest[dst]); + // //if (dst == src) + // // out.write(" " + regnames[dst] + " reflexive"); + // ++usedD[dst]; + // ++usedS[src]; + // lastD[dst] = xx; + // lastS[src] = xx; + //} + out.write(" "); + + if (ljump) { + int p = alu2 + (src << 6); + String s = hex(p, 3, false) + " "; + int entryPointer = 0; + while (entryPoints[entryPointer]._u != -1 && entryPoints[entryPointer]._a <= p) { + if (entryPoints[entryPointer]._a == p) { + s = entryPoints[entryPointer]._s; + if (s.length() < 14) + s = s + (14 - s.length())*String(" "); + if (s.length() > 14) + s = s.subString(0, 14); + break; + } + ++entryPointer; + } + out.write(s); + } + else { + if (sjump) { + //if (alu2 != 0x3f) { + int jump = alu2; + int dest = xx + 1 + jump; + if (jump > 0x20) + dest -= 0x40; + String s = hex(dest, 3, false) + " "; + int entryPointer = 0; + while (entryPoints[entryPointer]._u != -1 && entryPoints[entryPointer]._a <= dest) { + if (entryPoints[entryPointer]._a == dest) { + s = entryPoints[entryPointer]._s; + if (s.length() < 14) + s = s + (14 - s.length())*String(" "); + if (s.length() > 14) + s = s.subString(0, 14); + break; + } + ++entryPointer; + } + + out.write(s); + //} + //else + // out.write(" "); + } + else { + if (tjump) { + String s = testnames[alu2]; + if (s.length() < 14) + s = s + (14 - s.length())*String(" "); + if (s.length() > 14) + s = s.subString(0, 14); + out.write(s); + } + else { + //if ((alujump & 0x40) == 0 || (alujump >= 0x60)) { + if (displayAlu2) { + //if (alu2 != 0x3f || alujump == 0x3e || alujump == 0x15 || (alujump >= 0x0c && alujump <= 0x10) || buscode == 0x1f || buscode == 0x24 || buscode == 0x26 || buscode == 0x2d || buscode == 0x2e) { // What other alujump commands have alu2==0x3f have a function? + //if (regnames_alu[alu2].length() > 6) + out.write(regnames_alu[alu2] + String(" ")*(14 - regnames_alu[alu2].length())); + //else + // out.write(regnames_alu[alu2] + "-> ALU2 "); + //++usedA[alu2]; + //lastA[alu2] = xx; + } + else + out.write(" "); + //} + } + } + } + //if ((alu2 + (src << 6)) == 0x5f2 || xx + 1 + alu2 == 0x5f2) + // out.write("0x5f2"); + //static const int unreachables[33] = { + // 0x54d, + // 0x5b3, + // 0x5b8, + // 0x5bd, + // 0x5d3, + // 0x686, + // 0x71f, + // 0x862, + // 0x86a, + // 0x4e7, + // 0x4ee, + // 0x554, + // 0x5d5, + // 0x5fb, + // 0x743, + // 0x7e5, + // 0x872, + // 0x8c2, + // 0x8cb, + // 0x449, + // 0x4b5, + // 0x5da, + // 0x71c, + // 0x7e8, + // 0x3eb, + // 0x451, + // 0x51c, + // 0x536, + // 0x6a8, + // 0x6b3, + // 0x6dd, + // 0x71a, + // 0x71d}; + //for (int i = 0; i < 33; ++i) { + // int jump = alu2; + // if (jump > 0x20) + // jump = xx + 1 + jump - 0x40; + // else + // jump = xx + 1 + jump; + + // if ((alu2 + (src << 6)) == unreachables[i]) + // out.write("**" + hex(unreachables[i], 3, true) + "**"); + // if (jump == unreachables[i]) + // out.write("**" + hex(unreachables[i], 3, true) + "++"); + // if ((alu2 + (src << 6)) == unreachables[i] - 1) + // out.write("**" + hex(unreachables[i] - 1, 3, true) + "--"); + // if (jump == unreachables[i] - 1) + // out.write("**" + hex(unreachables[i] - 1, 3, true) + "//"); + //} + + ++usedAJ[alujump]; + lastAJ[alujump] = xx; + ++usedBus[buscode]; + lastBus[buscode] = xx; + ++usedOp[opcode]; + ++usedSub[subcode]; + out.write(" " + alujump_names[alujump] + " " + op + " " + subop + " " + busop + " " + instructions[xx]); +#if 0 + //for (int row = 0; row < 368; ++row) { + // if ((outputs[row] & 0xfff) == 2559 - x) { + // for (int b = 12; b >= 0; --b) { + // if ((mask[row] & (1 << b)) == 0) + // console.write("?"); + // else { + // if ((bits[row] & (1 << b)) == 0) + // console.write("0"); + // else + // console.write("1"); + // } + // } + // console.write(" "); + // for (int b = 15; b >= 0; --b) { + // if ((outputs[row] & (1 << b)) == 0) + // console.write("0"); + // else + // console.write("1"); + // } + // console.write(" "); + // } + //} + int nbitsets = 0; + for (int o = 0; o < 8192; ++o) { + if ((ored[o] & 0xfff) == 2559 - x) { + bitsets[nbitsets]._mask = 0x1fff; + bitsets[nbitsets]._bits = o; + bitsets[nbitsets]._output = ored[o]; + ++nbitsets; + } + } + while (true) { + //if (x == 2559) { + // for (int o = 0; o < nbitsets; ++o) { + // for (int b = 12; b >= 0; --b) { + // if ((bitsets[o]._mask & (1 << b)) == 0) + // console.write("?"); + // else + // if ((bitsets[o]._bits & (1 << b)) == 0) + // console.write("0"); + // else + // console.write("1"); + // } + // console.write(" "); + // for (int b = 15; b >= 0; --b) { + // if ((bitsets[o]._output & (1 << b)) == 0) + // console.write("0"); + // else + // console.write("1"); + // } + // console.write(" "); + // } + // console.write("\n"); + //} + + bool found = false; + //for (int o = 0; o < nbitsets; ++o) { + // for (int o1 = 0; o1 < o; ++o1) { + // if (bitsets[o]._mask != bitsets[o1]._mask || bitsets[o]._output != bitsets[o1]._output) + // continue; + // Word b = bitsets[o]._bits ^ bitsets[o1]._bits; + // if ((b & (b-1)) == 0) { + // found = true; + // bitsets[o1]._mask &= ~b; + // bitsets[o1]._bits &= ~b; + // for (int o2 = o; o2 < nbitsets - 1; ++o2) { + // bitsets[o2]._mask = bitsets[o2 + 1]._mask; + // bitsets[o2]._bits = bitsets[o2 + 1]._bits; + // bitsets[o2]._output = bitsets[o2 + 1]._output; + // } + // --nbitsets; + // } + // } + //} + for (int o = nbitsets - 1; o >= 1; --o) { + for (int o1 = o - 1; o1 >= 0; --o1) { + if (bitsets[o]._mask != bitsets[o1]._mask || bitsets[o]._output != bitsets[o1]._output) + continue; + DWord b = bitsets[o]._bits ^ bitsets[o1]._bits; + if ((b & (b-1)) == 0) { + found = true; + bitsets[o1]._mask &= ~b; + bitsets[o1]._bits &= ~b; + for (int o2 = o; o2 < nbitsets - 1; ++o2) { + bitsets[o2]._mask = bitsets[o2 + 1]._mask; + bitsets[o2]._bits = bitsets[o2 + 1]._bits; + bitsets[o2]._output = bitsets[o2 + 1]._output; + } + --nbitsets; + if (o == nbitsets) + break; + } + } + } + + + if (!found) + break; + } + + for (int o = 0; o < nbitsets; ++o) { + for (int b = 12; b >= 0; --b) { + if ((bitsets[o]._mask & (1 << b)) == 0) + console.write("?"); + else + if ((bitsets[o]._bits & (1 << b)) == 0) + console.write("0"); + else + console.write("1"); + } + console.write(" "); + for (int b = 15; b >= 0; --b) { + if ((bitsets[o]._output & (1 << b)) == 0) + console.write("0"); + else + console.write("1"); + } + console.write(" "); + } +#endif + out.write("\n"); + + //printf("\n"); + } +#if 0 + std::sort(&uops[0], &uops[2560]); + int first = -1; + for (int i = 0; i < 2560; ++i) { + if (i == 2559 || uops[i] != uops[i + 1]) { + console.write(printuop(uops[i]) + " " + decimal(i - first, 2) + "\n"); + first = i; + } + } +#endif + +#if 0 + //printf("%i %i %i\n",countr2,countr1,countr0); + for (int i = 0; i < 64; ++i) { + if (usedS[i] == 0) + console.write(" // "); + else + console.write(" "); + console.write("regnames_source["+hex(i, 2)+"] = \"" + regnames_source[i] + "\";"); + if (usedS[i] != 0) + console.write(" // " + decimal(usedS[i])); + if (usedS[i] == 1) + console.write(" " + hex(lastS[i],3, false)); + console.write("\n"); + + if (usedD[i] == 0) + console.write(" // "); + else + console.write(" "); + console.write("regnames_dest ["+hex(i, 2)+"] = \"" + regnames_dest [i] + "\";"); + if (usedD[i] != 0) + console.write(" // " + decimal(usedD[i])); + if (usedD[i] == 1) + console.write(" " + hex(lastD[i], 3, false)); + console.write("\n"); + + if (usedD[i + 64] == 0) + console.write(" // "); + else + console.write(" "); + console.write("regnames_dest ["+hex(i+64, 2)+"] = \"" + regnames_dest[i+64] + "\";"); + if (usedD[i + 64] != 0) + console.write(" // " + decimal(usedD[i + 64])); + if (usedD[i + 64] == 1) + console.write(" " + hex(lastD[i + 64], 3, false)); + console.write("\n"); + + if (usedA[i] == 0) + console.write(" // "); + else + console.write(" "); + console.write("regnames_alu ["+hex(i, 2)+"] = \"" + regnames_alu [i] + "\";"); + if (usedA[i] != 0) + console.write(" // " + decimal(usedA[i])); + if (usedA[i] == 1) + console.write(" " + hex(lastA[i], 3, false)); + console.write("\n"); + } + for (int i = 0; i < 128; ++i) { + if (usedAJ[i] == 0) + console.write(" // "); + else + console.write(" "); + console.write("alujump_names["+hex(i, 2)+"] = \"" + alujump_names[i] + "\";"); + if (usedAJ[i] != 0) + console.write(" // " + decimal(usedAJ[i])); + if (usedAJ[i] == 1) + console.write(" " + hex(lastAJ[i], 3, false)); + console.write("\n"); + } + for (int i = 0; i < 64; ++i) { + if (usedBus[i] == 0) + console.write(" // "); + else + console.write(" "); + console.write("busop_names["+hex(i, 2)+"] = \"" + busop_names[i] + "\";"); + if (usedBus[i] != 0) + console.write(" // " + decimal(usedBus[i])); + if (usedBus[i] == 1) + console.write(" " + hex(lastBus[i], 3, false)); + console.write("\n"); + } + for (int i = 0; i < 8; ++i) { + if (usedOp[i] == 0) + console.write(" // "); + else + console.write(" "); + console.write("opnames["+hex(i, 1, false)+"] = \"" + opnames[i] + "\";"); + if (usedOp[i] != 0) + console.write(" // " + decimal(usedOp[i])); + console.write("\n"); + } + for (int i = 0; i < 4; ++i) { + if (usedSub[i] == 0) + console.write(" // "); + else + console.write(" "); + console.write("subopnames["+hex(i, 1, false)+"] = \"" + subopnames[i] + "\";"); + if (usedSub[i] != 0) + console.write(" // " + decimal(usedSub[i])); + console.write("\n"); + } + for (int row = 0; row < 368 + 160 + 175; ++row) { + //for (int b = 12; b >= 0; --b) { + for (int b = 0; b < 13; ++b) { + if ((mask[row] & (1 << b)) == 0) + console.write("?"); + else { + if ((bits[row] & (1 << b)) == 0) + console.write("0"); + else + console.write("1"); + } + } + console.write(" "); + for (int b = 15; b >= 0; --b) { + if ((outputs[row] & (1 << b)) == 0) + console.write("0"); + else + console.write("1"); + } + console.write("\n"); + } + + int max = 0; + for (int x = 0; x < 37 - 5; ++x) { + Array counts(64); + for (int y = 0; y < 64; ++y) + counts[y] = 0; + for (int u = 0; u < 2560; ++u) { + int v = 0; + for (int b = 0; b < 6; ++b) { + if (data[u*37 + x + 5 - b] == 0xff) + v += (32 >> b); + } + ++counts[v]; + if (counts[v] > max && v != 0) + max = counts[v]; + } + } + Array heat(64*(37 - 5)); + for (int x = 0; x < 37 - 5; ++x) { + Array counts(64); + for (int y = 0; y < 64; ++y) + counts[y] = 0; + for (int u = 0; u < 2560; ++u) { + int v = 0; + for (int b = 0; b < 6; ++b) { + if (data[u*37 + x + 5 - b] == 0xff) + v += (1 << b); //(32 >> b); + } + ++counts[v]; + } + for (int y = 0; y < 64; ++y) + heat[y + x*64] = clamp(1, counts[y]*255/max, 255); + } + File("heat.raw").openWrite().write(heat); + + for (int i = 0; i < 256; ++i) { + console.write(hex(i,2,false) + ":\n"); + for (int j = 0; j < 8; ++j) { + int o = (((i & 128) != 0) ? 2048 : 0) + + (((i & 64) != 0) ? 1024 : 0) + + (((j & 4) != 0) ? 512 : 0) + + (((j & 2) != 0) ? 256 : 0) + + (((j & 1) != 0) ? 128 : 0) + + (((i & 32) != 0) ? 64 : 0) + + (((i & 16) != 0) ? 32 : 0) + + (((i & 8) != 0) ? 16 : 0) + + (((i & 4) != 0) ? 8 : 0) + + (((i & 2) != 0) ? 4 : 0) + + (((i & 1) != 0) ? 1 : 0); + console.write(hex(ored[o], 4, false) + "\n"); + } + console.write("\n"); + } +#endif + } +}; diff --git a/80386/disassembler/386_microcode.sln b/80386/disassembler/386_microcode.sln new file mode 100644 index 0000000..a3902da --- /dev/null +++ b/80386/disassembler/386_microcode.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11222.15 d18.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "386_microcode", "386_microcode.vcxproj", "{DDFA81CB-4634-4A74-97C6-CA7894BAC9EB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "386_microcode_check", "..\386_microcode_check\386_microcode_check.vcxproj", "{26DF26EA-E6C3-445B-8720-D3D990844B85}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DDFA81CB-4634-4A74-97C6-CA7894BAC9EB}.Debug|x64.ActiveCfg = Debug|x64 + {DDFA81CB-4634-4A74-97C6-CA7894BAC9EB}.Debug|x64.Build.0 = Debug|x64 + {DDFA81CB-4634-4A74-97C6-CA7894BAC9EB}.Debug|x86.ActiveCfg = Debug|Win32 + {DDFA81CB-4634-4A74-97C6-CA7894BAC9EB}.Debug|x86.Build.0 = Debug|Win32 + {DDFA81CB-4634-4A74-97C6-CA7894BAC9EB}.Release|x64.ActiveCfg = Release|x64 + {DDFA81CB-4634-4A74-97C6-CA7894BAC9EB}.Release|x64.Build.0 = Release|x64 + {DDFA81CB-4634-4A74-97C6-CA7894BAC9EB}.Release|x86.ActiveCfg = Release|Win32 + {DDFA81CB-4634-4A74-97C6-CA7894BAC9EB}.Release|x86.Build.0 = Release|Win32 + {26DF26EA-E6C3-445B-8720-D3D990844B85}.Debug|x64.ActiveCfg = Debug|x64 + {26DF26EA-E6C3-445B-8720-D3D990844B85}.Debug|x64.Build.0 = Debug|x64 + {26DF26EA-E6C3-445B-8720-D3D990844B85}.Debug|x86.ActiveCfg = Debug|Win32 + {26DF26EA-E6C3-445B-8720-D3D990844B85}.Debug|x86.Build.0 = Debug|Win32 + {26DF26EA-E6C3-445B-8720-D3D990844B85}.Release|x64.ActiveCfg = Release|x64 + {26DF26EA-E6C3-445B-8720-D3D990844B85}.Release|x64.Build.0 = Release|x64 + {26DF26EA-E6C3-445B-8720-D3D990844B85}.Release|x86.ActiveCfg = Release|Win32 + {26DF26EA-E6C3-445B-8720-D3D990844B85}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BCB27D51-7571-4EA3-91B9-E23B9620E9F6} + EndGlobalSection +EndGlobal diff --git a/80386/disassembler/386_microcode.vcxproj b/80386/disassembler/386_microcode.vcxproj new file mode 100644 index 0000000..4f1e7c8 --- /dev/null +++ b/80386/disassembler/386_microcode.vcxproj @@ -0,0 +1,138 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {ddfa81cb-4634-4a74-97c6-ca7894bac9eb} + My386microcode + 10.0 + + + + Application + true + v145 + Unicode + + + Application + false + v145 + true + Unicode + + + Application + true + v145 + Unicode + + + Application + false + v145 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/80386/disassembler/386_microcode.vcxproj.filters b/80386/disassembler/386_microcode.vcxproj.filters new file mode 100644 index 0000000..b97da0e --- /dev/null +++ b/80386/disassembler/386_microcode.vcxproj.filters @@ -0,0 +1,25 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + + diff --git a/80386/disassembler/include/alfe.natvis b/80386/disassembler/include/alfe.natvis new file mode 100644 index 0000000..0509247 --- /dev/null +++ b/80386/disassembler/include/alfe.natvis @@ -0,0 +1,413 @@ + + + + + + { (_length <= 8 ? (const unsigned char*)(this) : _start),[_length] } + + Small + External + Owning + _length + 8 + ((Array<unsigned char>::Body<Array<unsigned char>::AppendableBaseBody>*)(_array._body))->_allocated + _length + ((Array<unsigned char>::Body<Array<unsigned char>::AppendableBaseBody>*)(_array._body))->_count + (_length <= 8 ? (const unsigned char*)(this) : _start),[_length] + _array._body + + + + {_file,na}({_startLine,d},{_startColumn,d})-({_endLine,d},{_endColumn,d}) + (no span) + + + { _body,na } + + _body + + + + {_key} => {_value} + + + {numerator,d}/{denominator,d} + {numerator,d} + + + ConfigFile {_file} {_values._body,view(count)} values {_types._body,view(count)} types + + _file + _values + _types + + + + {_type} {_any} {_span} + + _type + _any + _span + + + + {_structure} . {_identifier} + + _structure + _identifier + + + + name {_name,na} default {_default} + + _name + _default + + + + Structure {_values._body,view(count)} + + _values + + + + Bitmap {_size} {_stride} + + _body + + + + + + + + ConstHandle refcount={_count,d} + + + Handle refcount={_count,d} + + + span={_span} + + _span + (ConstHandle::Body*)this,nd + + + + + {_parent,na}\{_name,sb} + + _parent + _name + + + + {_drive,d}: + + + == + + + = + + + += + + + -= + + + *= + + + /= + + + %= + + + <<= + + + >>= + + + &= + + + |= + + + ~= + + + ^= + + + Funco + + + & + + + | + + + ~ + + + ! + + + != + + + < + + + > + + + <= + + + >= + + + << + + + >> + + + + + + + - + + + * + + + / + + + % + + + ^ + + + () + + + [] + + + ++ + + + -- + + + {_t} + + _t + + + + int {_t} + + _t + + + + Word {_t} + + _t + + + + String {_t} + + _t + + + + Array {_size,d} {((int)this) + 16,x} + + + _size + ($T1*)(((char*)this) + 16) + + + + + {_size,d} + + _size,d + + + + Array {_size,d} {((int)this) + 12,x} + + + _size + ($T1*)(((char*)this) + 12) + + + + + Array {_size,d} {((int)this) + 16,x} + + + _size + (double*)(((char*)this) + 16) + + + + + size={_size,d} allocated={_allocated,d} + + + _allocated + ($T1*)(((char*)this) + 16) + + + + + size={_size,d} allocated={_allocated,d} + + + + _size + + + p,na + + ++p + + + _size,d + _allocated,d + (Handle::Body*)this,nd + + + + size={_size,d} allocated={_allocated,d} + + + + _size + + + p,na + + ++p + + + _size,d + _allocated,d + (Handle::Body*)this,nd + + + + FFTWArray {_n,d} + + + _n + ($T1*)_data + + + + + {_count,d} + + + _count + &_first + _next + _value + + (Handle::Body*)this,nd + + + + {_node->_value} + + _node->_value + + + + LValue<{_inner}> + + _inner + + + + Identifier {_name} {_span} + + _name + (ParseTreeObject::Body*)this,nd + + + + Identifier operator{_op} {_span} + + _op + _span + + + + StructuredType {_name}, {_members._body,view(count)} members + + _names + _members + + + + Integer + + + Double + + + Boolean + + + Rational + + + Word + + + Byte + + + String + + + {_contained}[{_indexer}] + + + {_n,d} + + + Reference {_c,na} + + _c + (Handle::Body*)this,nd + + + + {_left} . {_right} + + _left + _right + (ParseTreeObject::Body*)this,nd + + + + {_function}({_arguments}) + + diff --git a/80386/disassembler/include/alfe/allocator.h b/80386/disassembler/include/alfe/allocator.h new file mode 100644 index 0000000..805656d --- /dev/null +++ b/80386/disassembler/include/alfe/allocator.h @@ -0,0 +1,208 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_ALLOCATOR_H +#define INCLUDED_ALLOCATOR_H + +#include + +// This class allocates and frees memory. +// +// malloc() and free() have a severe problem for this application - they assume +// that a block, once allocated, cannot be moved. This causes a high degree of +// fragmentation in the common case that we allocate a large number of blocks +// and then remove most of them, since the remainder will cause most of the +// memory pages to remain committed. +// +// However, many of our blocks are quite easy to move, given just a pointer to +// it, because we know where all pointers that point to it are, and we know +// that no other threads will be accessing it. Also, the blocks of interest +// come in a small number of sizes (~20 in practice). This means it is +// practical to use a separate compacting heap for each block size, and keep +// these heaps compacted by moving the last block into the gap whenever a block +// is deallocated. +// +// These heaps grow in chunks of at least 1Mb and at least one block. Chunks +// need not be contiguous in memory, allowing the heaps to be interspersed. +template class Allocator : Uncopyable +{ +public: + Allocator() + { + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + _granularity = systemInfo.dwAllocationGranularity; + } + + void setProcessor(FractalProcessor* processor) { _processor = processor; } + + // A heap for a particular size of block. This is implemented using + // VirtualAlloc() and VirtualFree() instead of HeapAlloc() and HeapFree() + // because the latter set of functions never release address space. + class Heap + { + // A Chunk is a unit of allocation of address space. + class ChunkHeader + { + public: + ChunkHeader* _previous; + }; + + // Each block holds one object. BlockHeaders always start on a word + // boundary, so the least significant bits will always be 0. Hence we + // can re-use the least significant bit for a deleted flag. + class BlockHeader + { + public: + BlockHeader* _previous; + }; + + public: + // We need a default constructor to be able to put a Heap in a + // std::map. However, default-constructed Heaps are never actually + // used. + Heap() { } + + Heap(FractalProcessor* processor, Allocator* allocator, int size) + : _blockSize(size + _blockHeaderSize), + _chunk(0), + _freeBytes(0), + _block(0), + _processor(processor), + _allocator(allocator) + { + // We avoid allocating chunks less than 1Mb, but we also round up + // to a full number of chunks to avoid wasting space. + _chunkSize = ((0x100000 - _chunkHeaderSize) / _blockSize + 1) + * _blockSize + _chunkHeaderSize; + + // Round up to the granularity. With 64Kb granularity, we allocate + // 1Mb+64Kb for all grid sizes up to 512*512 for 4-byte blocks and + // 32*32 for 56-byte blocks. This means we rarely allocate chunks + // of any other size, which helps keep the address space + // defragmented. + _chunkSize = _allocator->align(_chunkSize); + + // This is the number of spare bytes at the end of each chunk, due + // to alignment requirements. + _slackBytes = (_chunkSize - _chunkHeaderSize) % _blockSize; + } + + // Allocates a new block and returns a pointer to it. + template T* allocate() + { + BlockHeader* newBlock; + if (_blockSize > _freeBytes) { + // Allocate a new chunk. We'll let VirtualAlloc choose where to + // put it. + ChunkHeader* chunk = reinterpret_cast( + VirtualAlloc(NULL, _chunkSize, MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE)); + IF_ZERO_CHECK_THROW_LAST_ERROR(chunk); + if (chunk == 0) + return 0; + _processor->tracker()->adjustMemory(_chunkSize); + chunk->_previous = _chunk; + _chunk = chunk; + _freeBytes = _chunkSize - _chunkHeaderSize; + newBlock = reinterpret_cast( + reinterpret_cast(chunk) + _chunkHeaderSize); + } + else { + // Allocate out of the current chunk. + newBlock = reinterpret_cast( + reinterpret_cast(_block) + _blockSize); + } + _freeBytes -= _blockSize; + newBlock->_previous = _block; + _block = newBlock; + return object(); + } + + // Deallocates the block at p. To avoid memory fragmentation and keep + // memory usage to a minimum, the object highest in memory is moved to + // p with a call to T::moveFrom(). + template void deallocate(T* p) + { + BlockHeader* block = reinterpret_cast( + reinterpret_cast(p) - _blockHeaderSize); + if (block != _block) { + T* old = object(); + p->moveFrom(_processor, old); + } + _block = _block->_previous; + _freeBytes += _blockSize; + if (_freeBytes == _chunkSize - _chunkHeaderSize) { + // We have an entirely empty chunk. Free it. + ChunkHeader* oldChunk = _chunk; + _chunk = _chunk->_previous; + VirtualFree(oldChunk, 0, MEM_RELEASE); + _freeBytes = _slackBytes; + _processor->tracker()->adjustMemory( + -static_cast(_chunkSize)); + } + } + + private: + template T* object() const + { + return reinterpret_cast( + reinterpret_cast(_block) + _blockHeaderSize); + } + + // Size of a block header. + static const size_t _blockHeaderSize = 4; + + // Size of a chunk header. + static const size_t _chunkHeaderSize = 4; + + // Size of a block. + size_t _blockSize; + + // Size of a chunk. + size_t _chunkSize; + + // Pointer to the chunk containing the most recently allocated block. + ChunkHeader* _chunk; + + // Pointer to the most recently allocated block. + BlockHeader* _block; + + // Number of bytes free in the current chunk. + size_t _freeBytes; + + // Number of bytes free in a full chunk. + size_t _slackBytes; + + FractalProcessor* _processor; + + Allocator* _allocator; + }; + + // Return a the heap that should be used for allocating blocks of size + // "size". + Heap* heapForSize(int size) + { + std::map::iterator i = _heaps.find(size); + if (i != _heaps.end()) + return &i->second; + _heaps[size] = Heap(_processor, this, size); + return &_heaps[size]; + } + + // Round a value up to the allocation granularity + size_t align(size_t value) + { + return (value + _granularity - 1) & ~(_granularity - 1); + } + +private: + // Allocation granularity. We always allocate multiples of this size, and + // allocations are aligned to this size. + size_t _granularity; + + std::map _heaps; + FractalProcessor* _processor; +}; + + +#endif // INCLUDED_ALLOCATOR_H diff --git a/80386/disassembler/include/alfe/any.h b/80386/disassembler/include/alfe/any.h new file mode 100644 index 0000000..4759f27 --- /dev/null +++ b/80386/disassembler/include/alfe/any.h @@ -0,0 +1,53 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_ANY_H +#define INCLUDED_ANY_H + +class Any : private Handle +{ +public: + Any() { } + template::value + && sizeof(T) == sizeof(ConstHandle))>* = nullptr> Any(const T& t) + : Handle(create>(t)) { } + template::value + && sizeof(T) == sizeof(ConstHandle)>* = nullptr> Any(const T& t) + { + set(reinterpret_cast( + reinterpret_cast(&t))->_body); + } + bool operator==(const Any& other) const + { + return Handle::operator==(other); + } + bool operator!=(const Any& other) const { return !(*this == other); } + template class Body : public Handle::Body + { + public: + Body(const T& t) : _t(t) { } + T value() const { return _t; } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + if (o == 0) + return false; + return _t == o->_t; + } + private: + T _t; + }; + template::value + && sizeof(T) == sizeof(ConstHandle))>* = nullptr> T value() const + { + return as>()->value(); + } + template::value + && sizeof(T) == sizeof(ConstHandle)>* = nullptr> T value() const + { + ConstHandle h; + h.set(_body); + return *reinterpret_cast(reinterpret_cast(&h)); + } +}; + +#endif // INCLUDED_ANY_H diff --git a/80386/disassembler/include/alfe/array.h b/80386/disassembler/include/alfe/array.h new file mode 100644 index 0000000..d0f800a --- /dev/null +++ b/80386/disassembler/include/alfe/array.h @@ -0,0 +1,697 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_ARRAY_H +#define INCLUDED_ARRAY_H + +#include "alfe/bitwise.h" + +// List is not quite a value type, since adding an element to a list will +// affect copies of the list. +template class List : private Handle +{ + class Body : public Handle::Body + { + class Node + { + public: + template Node(Args&&... args) + : _value(std::forward(args)...), _next(0) { } + Node* next() const { return _next; } + void setNext(Node* next) { _next = next; } + const T& value() const { return _value; } + private: + T _value; + Node* _next; + friend class Body; + friend class List; + }; + public: + template Body(Args&&... args) + : _first(std::forward(args)...), _last(&_first), _count(1) { } + ~Body() + { + Node* n = _first.next(); + while (n != 0) { + Node* nn = n->next(); + delete n; + n = nn; + } + } + template T* add(Args&&... args) + { + _last->setNext(new Node(std::forward(args)...)); + _last = _last->next(); + ++_count; + return &_last->_value; + } + int count() const { return _count; } + const Node* start() const { return &_first; } + private: + Node _first; + Node* _last; + int _count; + + friend class List; + friend class List::Iterator; + }; +public: + List() { } + template T* add(Args&&... args) + { + if (!valid()) { + *this = List(create(std::forward(args)...)); + return &body()->_first._value; + } + return body()->add(std::forward(args)...); + } + int count() const + { + if (valid()) + return body()->count(); + return 0; + } + bool operator==(List other) const + { + Iterator l = begin(); + Iterator r = other.begin(); + while (l != end() && r != other.end()) { + if (*l != *r) + return false; + ++l; + ++r; + } + return l == end() && r == other.end(); + } +private: + List(const Handle& other) : Handle(other) { } + Body* body() { return as(); } + const Body* body() const { return as(); } +public: + class Iterator + { + public: + const T& operator*() const { return _node->value(); } + const T* operator->() const { return &_node->value(); } + const Iterator& operator++() { _node = _node->next(); return *this; } + bool operator==(const Iterator& other) { return _node == other._node; } + bool operator!=(const Iterator& other) { return !operator==(other); } + bool end() const { return _node == 0; } + private: + const typename Body::Node* _node; + + Iterator(const typename Body::Node* node) : _node(node) { } + + friend class List; + }; + Iterator begin() const + { + if (valid()) + return Iterator(body()->start()); + return end(); + } + Iterator end() const { return Iterator(0); } +}; + +template class Array; + +template::AppendableBaseBody> + class AppendableArray; + +// Array is not quite a value type, since changing an element in one array will +// affect copies of the same array unless a deep copy is made with copy(). +template class Array : private Handle +{ +public: + // "allocate" is number of Ts to allocate space for. + // "construct" is number of Ts to actually construct. + template static + C create(int allocate, int construct) + { + return create(allocate, construct, 0); + } + template static + C create(int allocate, int construct, int extraBytes, Args&&... args) + { + void* buffer = operator new(Body::headSize() + allocate*sizeof(T) + + extraBytes); + Body* b; + try { + b = new(buffer) Body(std::forward(args)...); + try { + b->constructTail(construct); + } + catch (...) { + b->destruct(); + throw; + } + } + catch (...) { + operator delete(buffer); + throw; + } + return C(b, false); + } + + // This class combines an H and an array of Ts in a single memory block. + // Also known as the "struct hack". T must be default-constructable. + template class Body : public H + { + // HT is never actually used directly - it's just used to figure out + // the length and the address of the first T. + // class HT : public Body { public: T _t; }; + public: + static int headSize() { return sizeof(HT) - sizeof(T); } + + T* pointer() { return &static_cast*>(this)->_t; } + const T* pointer() const + { + return &static_cast*>(this)->_t; + } + T& operator[](int i) { return pointer()[i]; } + const T& operator[](int i) const { return pointer()[i]; } + + void destroy() const + { + this->preDestroy(); + destruct(); + operator delete(const_cast(static_cast(this))); + } + + int size() const { return _size; } + // Be careful to avoid calling setSize() with a size argument greater + // than the "allocate" size passed to create(). + void setSize(int size) + { + if (size > _size) + constructTail(size); + else + destructTail(size); + } + + template void constructT(Args&&... args) + { + new(static_cast(&(*this)[_size])) + T(std::forward(args)...); + ++_size; + } + + class Iterator + //: public std::iterator + { + public: + using difference_type = ptrdiff_t; + using value_type = T; + //typename std::iterator:: + //difference_type; + + Iterator() : _p(0) { } + T& operator[](difference_type n) const { return _p[n]; } + T& operator*() const { return *_p; } + T* operator->() { return _p; } + const Iterator& operator++() { ++_p; return *this; } + const Iterator& operator--() { --_p; return *this; } + Iterator operator++(int) { Iterator r = *this; ++_p; return r; } + Iterator operator--(int) { Iterator r = *this; --_p; return r; } + const Iterator& operator+=(difference_type n) { _p += n; return *this; } + const Iterator& operator-=(difference_type n) { _p -= n; return *this; } + Iterator operator+(difference_type n) const + { + Iterator r = *this; + r += n; + return r; + } + Iterator operator-(difference_type n) const + { + Iterator r = *this; + r -= n; + return r; + } + friend inline Iterator operator+(difference_type n, const Iterator& a) + { + return a + n; + } + friend inline Iterator operator-(difference_type n, const Iterator& a) + { + return a - n; + } + bool operator==(const Iterator& other) const + { + return _p == other._p; + } + bool operator!=(const Iterator& other) const + { + return _p != other._p; + } + bool operator<(const Iterator& other) const + { + return _p < other._p; + } + bool operator>(const Iterator& other) const + { + return _p > other._p; + } + bool operator<=(const Iterator& other) const + { + return _p <= other._p; + } + bool operator>=(const Iterator& other) const + { + return _p >= other._p; + } + ptrdiff_t operator-(const Iterator& other) const + { + return _p - other._p; + } + private: + T* _p; + Iterator(T* p) : _p(p) { } + friend class Body; + }; + + class ConstIterator + //: public std::iterator + { + using difference_type = ptrdiff_t; + using value_type = T; + //typename std::iterator:: + //difference_type; + public: + ConstIterator() : _p(0) { } + const T& operator[](difference_type n) const { return _p[n]; } + const T& operator*() const { return *_p; } + const T* operator->() const { return _p; } + const ConstIterator& operator++() { ++_p; return *this; } + const ConstIterator& operator--() { --_p; return *this; } + ConstIterator operator++(int) + { + ConstIterator r = *this; + ++_p; + return r; + } + ConstIterator operator--(int) + { + ConstIterator r = *this; + --_p; + return r; + } + const ConstIterator& operator+=(difference_type n) + { + _p += n; + return *this; + } + const ConstIterator& operator-=(difference_type n) + { + _p -= n; + return *this; + } + const ConstIterator& operator+(difference_type n) const + { + ConstIterator r = *this; + r += n; + return r; + } + const ConstIterator& operator-(difference_type n) const + { + ConstIterator r = *this; + r -= n; + return r; + } + friend inline Iterator operator+(difference_type n, + const ConstIterator& a) + { + return a + n; + } + friend inline Iterator operator-(difference_type n, + const ConstIterator& a) + { + return a - n; + } + bool operator==(const ConstIterator& other) const + { + return _p == other._p; + } + bool operator!=(const ConstIterator& other) const + { + return _p != other._p; + } + bool operator<(const ConstIterator& other) const + { + return _p < other._p; + } + bool operator>(const ConstIterator& other) const + { + return _p > other._p; + } + bool operator<=(const ConstIterator& other) const + { + return _p <= other._p; + } + bool operator>=(const ConstIterator& other) const + { + return _p >= other._p; + } + ptrdiff_t operator-(const ConstIterator& other) const + { + return other._p - _p; + } + private: + const T* _p; + ConstIterator(const T* p) : _p(p) { } + friend class Body; + }; + + ConstIterator begin() const { return ConstIterator(&((*this)[0])); } + ConstIterator end() const { return ConstIterator(&((*this)[size()])); } + Iterator begin() { return Iterator(&((*this)[0])); } + Iterator end() { return Iterator(&((*this)[size()])); } + + void justSetSize(int size) const { _size = size; } + + private: + void constructTail(int size) + { + int oldSize = _size; + try { + while (_size < size) + constructT(); + } + catch (...) { + destructTail(oldSize); + throw; + } + } + void destructTail(int size) const + { + for (; _size > size; --_size) + (&(*this)[_size - 1])->~T(); + } + void destruct() const + { + destructTail(0); + this->~Body(); + } + + mutable int _size; // Needs to be mutable so destroy() can be const. + + // Only constructor is private to prevent inheritance, composition and + // stack allocation. All instances are constructed via the placement + // new call in create(). + template Body(Args&&... args) + : H(std::forward(args)...), _size(0) { } + + // HashTable and Set keep all elements constructed, and use _size to + // keep track of the number of actual entries in the table. + template friend class HashTable; + template friend class Set; + friend class Array; + }; + + template class HT : public Body { public: T _t; }; + + class AppendableBaseBody : public Handle::Body + { + public: + int _allocated; + }; + Array() { } + Array(const List& list) + { + int n = list.count(); + if (n != 0) { + *this = Array(create<>(n, 0)); + for (auto p : list) + body()->constructT(p); + } + } + Array(const AppendableArray& a) { *this = Handle(a); } + explicit Array(int n) + { + if (n != 0) + *this = Array(create<>(n, n)); + } + void allocate(int n) { *this = Array(n); } + void ensure(int n) { if (count() < n) allocate(n); } + bool operator==(const Array& other) const + { + int n = count(); + if (n != other.count()) + return false; + for (int i = 0; i < n; ++i) + if ((*this)[i] != other[i]) + return false; + return true; + } + template bool operator==(const AppendableArray& other) const + { + int n = count(); + if (n != other.count()) + return false; + for (int i = 0; i < n; ++i) + if ((*this)[i] != other[i]) + return false; + return true; + } + bool operator!=(const Array& other) const { return !operator==(other); } + template bool operator!=(const AppendableArray& other) const + { + return !operator==(other); + } + T& operator[](int i) { return (*body())[i]; } + const T& operator[](int i) const { return (*body())[i]; } + int count() const { return body() == 0 ? 0 : body()->size(); } + Array copy() const + { + Array r(create<>(count(), 0)); + for (int i = 0; i < count(); ++i) + r.body()->constructT((*this)[i]); + return r; + } + + typedef typename Body<>::Iterator Iterator; + typedef typename Body<>::ConstIterator ConstIterator; + ConstIterator begin() const + { + if (body() != 0) + return body()->begin(); + return typename Body<>::ConstIterator(); + } + ConstIterator end() const + { + if (body() != 0) + return body()->end(); + return typename Body<>::ConstIterator(); + } + Iterator begin() + { + if (body() != 0) + return body()->begin(); + return typename Body<>::Iterator(); + } + Iterator end() + { + if (body() != 0) + return body()->end(); + return typename Body<>::Iterator(); + } + +private: + Array(const Handle& other) : Handle(other) { } + Body<>* body() { return as>(); } + const Body<>* body() const { return as>(); } + template friend class AppendableArray; +}; + +// AppendableArray is not quite a value type, since changing an element in one +// array will affect copies of the same array unless a deep copy is made with +// copy(). Appending to an array may cause it to become a deep copy, if more +// storage space was needed. +template class AppendableArray : private Handle +{ +protected: + typedef typename Array::template Body Body; +public: + AppendableArray() { } + AppendableArray(const Handle& other) : Handle(other) { } + AppendableArray(const List& list) : AppendableArray(list.count()) + { + for (auto p : list) + body()->constructT(p); + } + explicit AppendableArray(int n) + { + // The 8 bytes is the observed malloc overhead on both GCC and VC, + // 32-bit and 64-bit (though not VC with debug heap). The idea is that + // we allocate actual memory blocks that are powers of 2 bytes to + // minimize fragmentation, and allocate as many objects as we can in + // that space so as to make the best use of it. + int overhead = Body::headSize() + 8; + int s = n*sizeof(T) + overhead; + s = roundUpToPowerOf2(s) - overhead; + int count = s/sizeof(T); + int extra = s%sizeof(T); + AppendableArray b = + Array::template create(count, 0, extra); + b.body()->_allocated = count; + *this = b; + } + void allocate(int n) + { + if (allocated() < n) { + AppendableArray a(n); + if (count() > 0) + a.addUnchecked(body()->pointer(), count()); + *this = a; + } + } + void append(const T& value) { append(&value, 1); } + void append(const Array& other) + { + if (other.count() > 0) + append(&other[0], other.count()); + } + template void append(const AppendableArray& other) + { + if (other.count() > 0) + append(&other[0], other.count()); + } + void append(const T* data, int length) + { + if (allocated() < count() + length) { + AppendableArray a(count() + length); + if (count() > 0) + a.addUnchecked(body()->pointer(), count()); + a.addUnchecked(data, length); + *this = a; + } + else { + int oldCount = count(); + try { + addUnchecked(data, length); + } + catch (...) { + body()->setSize(oldCount); + throw; + } + } + } + void unappend(int elements = 1) { body()->setSize(count() - elements); } + // Like append but with default construction instead of copying. + void expand(int length) + { + if (allocated() < count() + length) { + AppendableArray a(count() + length); + if (count() > 0) + a.addUnchecked(body()->pointer(), count()); + a.expandUnchecked(length); + *this = a; + } + else { + int oldCount = count(); + try { + expandUnchecked(length); + } + catch (...) { + body()->setSize(oldCount); + throw; + } + } + } + void ensure(int n) + { + if (n > count()) + expand(n - count()); + } + void clear() + { + if (count() > 0) + body()->setSize(0); + } + + bool operator==(const Array& other) const + { + int n = count(); + if (n != other.count()) + return false; + for (int i = 0; i < n; ++i) + if ((*this)[i] != other[i]) + return false; + return true; + } + template bool operator==(const AppendableArray& other) const + { + int n = count(); + if (n != other.count()) + return false; + for (int i = 0; i < n; ++i) + if ((*this)[i] != other[i]) + return false; + return true; + } + + bool operator!=(const Array& other) const { return !operator==(other); } + template bool operator!=(const AppendableArray& other) const + { + return !operator==(other); + } + T& operator[](int i) { return (*body())[i]; } + const T& operator[](int i) const { return (*body())[i]; } + int count() const { return body() == 0 ? 0 : body()->size(); } + int allocated() const { return body() == 0 ? 0 : body()->_allocated; } + AppendableArray copy() const + { + AppendableArray r(count()); + r.addUnchecked(&(*this)[0], count()); + return r; + } + + typedef typename Body::Iterator Iterator; + Iterator begin() const + { + if (body() != 0) + return body()->begin(); + return Body::Iterator(); + } + Iterator end() const + { + if (body() != 0) + return body()->end(); + return Body::Iterator(); + } + Iterator begin() + { + if (body() != 0) + return body()->begin(); + return Body::Iterator(); + } + Iterator end() + { + if (body() != 0) + return body()->end(); + return Body::Iterator(); + } + +private: + void addUnchecked(const T* start, int c) + { + for (int i = 0; i < c; ++i) { + body()->constructT(*start); + ++start; + } + } + void expandUnchecked(int c) + { + for (int i = 0; i < c; ++i) + body()->constructT(); + } + Body* body() { return as(); } + const Body* body() const { return as(); } + + // For access to body(). + template friend class HashTable; + template friend class Set; + + // For conversion to Handle + template friend class Array; +}; + +#endif // INCLUDED_ARRAY_H diff --git a/80386/disassembler/include/alfe/array_functions.h b/80386/disassembler/include/alfe/array_functions.h new file mode 100644 index 0000000..b3eaa52 --- /dev/null +++ b/80386/disassembler/include/alfe/array_functions.h @@ -0,0 +1,59 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_ARRAY_FUNCTIONS_H +#define INCLUDED_ARRAY_FUNCTIONS_H + +#include "alfe/function.h" + +class IndexArray : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + auto l = i->value>(); + ++i; + Value r = *i; + if (r.type() != IntegerType()) { + span.throwError("Evaluating arrays with a non-integer indexer " + "has not been implemented."); + } + int rr = r.value(); + if (rr < 0 || rr >= l.count()) { + span.throwError("Array access out of bounds: " + decimal(rr) + + " is not in the range 0 to " + l.count() + "."); + } + auto x = l.begin(); + while (rr > 0) { + ++x; + --rr; + } + return *x; + } + Identifier identifier() const { return OperatorIndex(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + ArrayType l(*i); + if (!l.valid()) + return false; + ++i; + Type indexType(*i); + return indexType.canConvertTo(l.indexer()); + } + List parameterTycos() const + { + List r; + r.add(ArrayTemplate()); + r.add(Type()); + return r; + } + }; +}; + +#endif // INCLUDED_ARRAY_FUNCTIONS_H diff --git a/80386/disassembler/include/alfe/assert.h b/80386/disassembler/include/alfe/assert.h new file mode 100644 index 0000000..baff22c --- /dev/null +++ b/80386/disassembler/include/alfe/assert.h @@ -0,0 +1,46 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_ASSERT_H +#define INCLUDED_ASSERT_H + +// TODO: Posix port +// TODO: _CrtDbgBreak() is a VC-ism: port to other Windows compilers +// TODO: Use console instead of MessageBox() for console applications? + +#ifdef _WIN32 +#include +#else +#include +#endif + +#ifdef _WIN32 +void alert(String message, HWND hWnd = NULL) +{ + alerting = true; + MessageBox(hWnd, NullTerminatedWideString(message), L"Error", + MB_OK | MB_ICONERROR | MB_TASKMODAL); + alerting = false; +} +#endif + +void assert(bool success, String message = "" +#ifdef _WIN32 + , HWND hWnd = NULL +#endif + ) +{ + if (!success) { + String output("Assertion failed"); + if (!message.empty()) + output += ": " + message; +#ifdef _WIN32 + alert(output, hWnd); + _CrtDbgBreak(); +#else + console.write(output + "\n"); + raise(SIGABRT); +#endif + } +} + +#endif // INCLUDED_ASSERT_H diff --git a/80386/disassembler/include/alfe/audio.h b/80386/disassembler/include/alfe/audio.h new file mode 100644 index 0000000..95bfc29 --- /dev/null +++ b/80386/disassembler/include/alfe/audio.h @@ -0,0 +1,457 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_AUDIO_H +#define INCLUDED_AUDIO_H + +// TODO: Posix port + +#include "alfe/thread.h" +#include +#include +#include +#include +#include "alfe/com.h" +#include "alfe\pipes.h" + +template class AudioSink : public Sink +{ +protected: + AudioSink(int samplesPerSecond, int channels) + : _channels(channels) + { + ZeroMemory(&_format, sizeof(WAVEFORMATEX)); + _format.wFormatTag = WAVE_FORMAT_PCM; + _format.nChannels = channels; + _format.nSamplesPerSec = samplesPerSecond; + int nBlockAlign = channels*sizeof(Sample); + _format.nAvgBytesPerSec = samplesPerSecond*nBlockAlign; + _format.nBlockAlign = nBlockAlign; + _format.wBitsPerSample = sizeof(Sample)*8; + _format.cbSize = 0; + } + WAVEFORMATEX _format; + int _channels; +}; + +template class DirectSoundSink : public AudioSink +{ + class ProcessingThread : public ThreadTask + { + public: + ProcessingThread() : _sink(0) { } + ~ProcessingThread() { cancel(); _sink->_event.signal(); } + void setSink(DirectSoundSink* sink) { _sink = sink; restart(); } + + void run() + { + while (true) { + _sink->_event.wait(); + if (cancelling()) + return; + _sink->fillNextHalfBuffer(); + } + } + private: + DirectSoundSink* _sink; + }; + +public: + // A smaller buffer would probably be preferred but the DirectSound + // implementation in Vista fails with small buffers - see + // http://www.reenigne.org/blog/what-happened-to-directsound/ . + // TODO: Could try instead using a timer and IDirectSoundBuffer::GetCurrentPosition(). + // TODO: Change samplesPerBuffer parameter to secondsPerBuffer? + DirectSoundSink(HWND hWnd, int samplesPerSecond = 44100, + int samplesPerBuffer = 4096, int channels = 1) + : AudioSink(samplesPerSecond, channels), + _hWnd(hWnd) + { + IF_ERROR_THROW(DirectSoundCreate8(NULL, &_directSound, NULL)); + + // Set priority cooperative level + IF_ERROR_THROW( + _directSound->SetCooperativeLevel(hWnd, DSSCL_PRIORITY)); + + _bytesPerSample = sizeof(Sample); + + // Set primary buffer format + { + COMPointer spDSBPrimary; + + DSBUFFERDESC dsbd; + ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); + dsbd.dwSize = sizeof(DSBUFFERDESC); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = NULL; + + IF_ERROR_THROW(_directSound->CreateSoundBuffer( + &dsbd, + &spDSBPrimary, + NULL)); + + IF_ERROR_THROW(spDSBPrimary->SetFormat(&_format)); + } + + // Set background thread priority + _thread.setPriority(THREAD_PRIORITY_TIME_CRITICAL); + SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); + + int bufferBytes = _format.nBlockAlign*samplesPerBuffer; + + DSBUFFERDESC dsbd = {0}; + dsbd.dwSize = sizeof(DSBUFFERDESC); + dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE | + DSBCAPS_CTRLPOSITIONNOTIFY; + dsbd.dwBufferBytes = bufferBytes; + dsbd.guid3DAlgorithm = GUID_NULL; + dsbd.lpwfxFormat = &_format; + + IF_ERROR_THROW(_directSound-> + CreateSoundBuffer(&dsbd, &_directSoundBuffer, NULL)); + + COMPointer + spDSN(_directSoundBuffer, &IID_IDirectSoundNotify); + + int midpoint = bufferBytes/2; + midpoint -= midpoint % 2; + + DSBPOSITIONNOTIFY aPosNotify[2]; + _starts[0] = 0; + _lengths[0] = midpoint; + _starts[1] = midpoint; + _lengths[1] = bufferBytes - midpoint; + aPosNotify[0].dwOffset = midpoint - 1; + aPosNotify[0].hEventNotify = _event; + aPosNotify[1].dwOffset = bufferBytes - 1; + aPosNotify[1].hEventNotify = _event; + IF_ERROR_THROW(spDSN->SetNotificationPositions(2, aPosNotify)); + + _next = 0; + _thread.setSink(this); + + IF_ERROR_THROW(_directSoundBuffer->SetCurrentPosition(0)); + } + void play() + { + fillNextHalfBuffer(); + fillNextHalfBuffer(); + IF_ERROR_THROW(_directSoundBuffer->Play(0, 0, DSBPLAY_LOOPING)); + } + + void fillNextHalfBuffer() + { + void* pDSLockedBuffer; + void* pDSLockedBuffer2; + DWORD dwDSLockedBufferSize; + DWORD dwDSLockedBufferSize2; + + IF_ERROR_THROW(_directSoundBuffer->Lock( + _starts[_next], + _lengths[_next], + &pDSLockedBuffer, + &dwDSLockedBufferSize, + &pDSLockedBuffer2, + &dwDSLockedBufferSize2, + 0L)); + + fillBuffer(pDSLockedBuffer, dwDSLockedBufferSize); + fillBuffer(pDSLockedBuffer2, dwDSLockedBufferSize2); + + // Unlock the DirectSound buffer + IF_ERROR_THROW(_directSoundBuffer->Unlock( + pDSLockedBuffer, + dwDSLockedBufferSize, + NULL, + 0)); + + _next = 1 - _next; + } + + void consume(int n) { _consumeEvent.wait(); } + + ~DirectSoundSink() { _directSoundBuffer->Stop(); } + void wait() { _finish.wait(); } + +private: + void fillBuffer(void* data, int length) + { + Accessor r = reader(length); + length /= _bytesPerSample; + Sample* sample = reinterpret_cast(data); + for (int i = 0; i < length; ++i) + *(sample++) = r.item(); + read(length); + _consumeEvent.signal(); + if (finite() && remaining() <= 0) + _finish.signal(); + } + + COMPointer _directSound; + ProcessingThread _thread; + + COMPointer _directSoundBuffer; + DWORD _dwNotifySize; + DWORD _starts[2]; + DWORD _lengths[2]; + int _next; + HWND _hWnd; + UINT _msg; + LPARAM _lparam; + WPARAM _wparam; + int _bytesPerSample; + Event _event; + Event _consumeEvent; + Event _finish; + + friend class ProcessingThread; +}; + +template class XAudio2Sink : public AudioSink +{ + class Callback : public IXAudio2VoiceCallback + { + public: + void setSink(XAudio2Sink* sink) { _sink = sink; } + virtual void __stdcall OnVoiceProcessingPassStart(UINT32) { } + virtual void __stdcall OnVoiceProcessingPassEnd() { } + virtual void __stdcall OnStreamEnd() { } + virtual void __stdcall OnBufferStart(void*) { } + virtual void __stdcall OnBufferEnd(void*) { _sink->bufferEnded(); } + virtual void __stdcall OnLoopEnd(void*) { } + virtual void __stdcall OnVoiceError(void*, HRESULT) { } + private: + XAudio2Sink* _sink; + }; + + class ProcessingThread : public ThreadTask + { + public: + ProcessingThread() : _sink(0) { } + ~ProcessingThread() { cancel(); _sink->_event.signal(); } + void setSink(XAudio2Sink* sink) { _sink = sink; restart(); } + + void threadProc() + { + while (true) { + _sink->_event.wait(); + if (cancelling()) + return; + _sink->fillNextBuffer(); + } + } + private: + XAudio2Sink* _sink; + }; + +public: + XAudio2Sink(int samplesPerSecond = 44100, int samplesPerBuffer = 512, + int channels = 1) + : AudioSink(samplesPerSecond, channels), + _next(0) + { + _callback.setSink(this); + _thread.setSink(this); + + IF_ERROR_THROW(XAudio2Create(&_xAudio2, 0)); + + IF_ERROR_THROW( + _xAudio2->CreateMasteringVoice(&_xAudio2MasteringVoice)); + + IF_ERROR_THROW( + _xAudio2->CreateSourceVoice( + &_xAudio2SourceVoice, + &_format, + 0, // Flags + 1.0f, // MaxFrequencyRatio + &_callback)); + + _samplesPerBuffer = samplesPerBuffer; + _data.allocate(_samplesPerBuffer*2); + _bytesPerBuffer = _format.nBlockAlign*_samplesPerBuffer; + } + void play() + { + fillNextBuffer(); + fillNextBuffer(); + IF_ERROR_THROW(_xAudio2SourceVoice->Start(0)); + } + void wait() { _finish.wait(); } +private: + void bufferEnded() { _event.signal(); } + void fillNextBuffer() + { + do { + XAUDIO2_VOICE_STATE state; + _xAudio2SourceVoice->GetState(&state); + if (state.BuffersQueued == 2) + break; + signed short* sample; + if (_next == 0) + sample = &_data[0]; + else + sample = &_data[_samplesPerBuffer]; + XAUDIO2_BUFFER buffer = {0}; + buffer.AudioBytes = _bytesPerBuffer; + buffer.pAudioData = reinterpret_cast(sample); + Accessor r = reader(_samplesPerBuffer); + for (int i = 0; i < _samplesPerBuffer; ++i) + *(sample++) = r.item(); + read(_samplesPerBuffer); + _consumeEvent.signal(); + IF_ERROR_THROW(_xAudio2SourceVoice->SubmitSourceBuffer(&buffer)); + _next = 1 - _next; + if (finite() && remaining() <= 0) + _finish.signal(); + } while (true); + } + + void consume(int n) { _consumeEvent.wait(); } + + COMPointer _xAudio2; + IXAudio2MasteringVoice* _xAudio2MasteringVoice; + IXAudio2SourceVoice* _xAudio2SourceVoice; + Callback _callback; + ProcessingThread _thread; + Event _event; + int _next; + Array _data; + int _samplesPerBuffer; + int _bytesPerBuffer; + Event _consumeEvent; + Event _finish; + + friend class ProcessingThread; + friend class Callback; +}; + +template class WaveOutSink : public AudioSink +{ +public: + WaveOutSink(int samplesPerSecond = 44100, + int samplesPerBufferChannel = 512, int channels = 1) + : AudioSink(samplesPerSecond, channels) + { + IF_FALSE_THROW(waveOutOpen(&_device, WAVE_MAPPER, &_format, + reinterpret_cast(waveOutProc), + reinterpret_cast(this), CALLBACK_FUNCTION) + == MMSYSERR_NOERROR); + + _samplesPerBuffer = samplesPerBufferChannel * channels; + _data.allocate(_samplesPerBuffer * 2); + + for (int i = 0; i < 2; ++i) { + ZeroMemory(&_headers[i], sizeof(WAVEHDR)); + _headers[i].lpData = + reinterpret_cast(&_data[i*_samplesPerBuffer]); + _headers[i].dwBufferLength = _samplesPerBuffer*sizeof(Sample); + } + _header = 0; + _ending = false; + } + void play() + { + playBuffer(); + playBuffer(); + } + ~WaveOutSink() + { + waveOutReset(_device); + waveOutClose(_device); + } + void consume(int n) { _consumeEvent.wait(); } + void wait() { _finish.wait(); } +private: + static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, + DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) + { + if (uMsg == WOM_DONE) + reinterpret_cast(dwInstance)->nextBlock(); + } + void nextBlock() + { + IF_FALSE_THROW(waveOutUnprepareHeader(_device, &_headers[_header], + sizeof(WAVEHDR)) == MMSYSERR_NOERROR); + if (!_ending) + playBuffer(); + } + void playBuffer() + { + Sample* p = &_data[_header*_samplesPerBuffer]; + Accessor r = reader(_samplesPerBuffer); + for (int i = 0; i < _samplesPerBuffer; ++i) + *(p++) = r.item(); + read(_samplesPerBuffer); + IF_FALSE_THROW(waveOutPrepareHeader(_device, &_headers[_header], + sizeof(WAVEHDR)) == MMSYSERR_NOERROR); + IF_FALSE_THROW(waveOutWrite(_device, &_headers[_header], + sizeof(WAVEHDR)) == MMSYSERR_NOERROR); + if (finite() && remaining() <= 0) + _finish.signal(); + _header = 1 - _header; + } + int _samplesPerBuffer; + Event _consumeEvent; + HWAVEOUT _device; + WAVEHDR _headers[2]; + int _header; + Array _data; + bool _ending; + Event _finish; +}; + +template class WaveFileSink : public AudioSink +{ +public: + WaveFileSink(File file, int samplesPerSecond = 44100, int channels = 1, + int samplesPerBufferChannel = 1024) + : AudioSink(samplesPerSecond, channels), + _samplesPerBuffer(samplesPerBufferChannel * channels), + _bytes(0), + _stream(file.openWrite()) + { + // TODO: make endian-neutral. Posix port. + _stream.write("RIFF", 4); + DWORD t = 36; + _stream.write(&t, 4); + _stream.write("WAVE", 4); + _stream.write("fmt ", 4); + t = 16; + _stream.write(&t, 4); + _stream.write(&_format, 16); + _stream.write("data", 4); + t = 0; + _stream.write(&t, 4); + } + void play() + { + do { + consume(_samplesPerBuffer); + } while (!finite() || remaining() > 0); + } + void consume(int n) + { + if (finite() && n > remaining()) + n = remaining(); + if (n > 0) { + Accessor r = reader(n); + r.items(WriteTo(&_stream), 0, n); + _bytes += n*sizeof(Sample); + read(n); + } + if (finite() && remaining() <= 0) { + _stream.seek(4); + DWORD t = _bytes + 36; + _stream.write(&t, 4); + _stream.seek(40); + t = _bytes; + _stream.write(&t, 4); + } + } +private: + int _samplesPerBuffer; + FileStream _stream; + int _bytes; +}; + +#endif // INCLUDED_AUDIO_H diff --git a/80386/disassembler/include/alfe/avi.h b/80386/disassembler/include/alfe/avi.h new file mode 100644 index 0000000..0fed8ab --- /dev/null +++ b/80386/disassembler/include/alfe/avi.h @@ -0,0 +1,332 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_AVI_H +#define INCLUDED_AVI_H + +#include "alfe/com.h" +#include "alfe/bitmap.h" +#include "alfe/rational.h" +#include + +String aviErrorMessage(HRESULT hr) +{ + switch (hr) { + case AVIERR_UNSUPPORTED: return "Unsupported"; + case AVIERR_BADFORMAT: return "Bad format"; + case AVIERR_MEMORY: return "Out of memory"; + case AVIERR_INTERNAL: return "Internal error"; + case AVIERR_BADFLAGS: return "Bad flags"; + case AVIERR_BADPARAM: return "Bad parameters"; + case AVIERR_BADSIZE: return "Bad size"; + case AVIERR_BADHANDLE: return "Bad AVIFile handle"; + case AVIERR_FILEREAD: return "File read error"; + case AVIERR_FILEWRITE: return "File write error"; + case AVIERR_FILEOPEN: return "File open error"; + case AVIERR_COMPRESSOR: return "Compressor error"; + case AVIERR_NOCOMPRESSOR: return "Compressor not available"; + case AVIERR_READONLY: return "File marked read-only"; + case AVIERR_NODATA: return "No data"; + case AVIERR_BUFFERTOOSMALL: return "Buffer too small"; + case AVIERR_CANTCOMPRESS: return "Can't compress"; + case AVIERR_USERABORT: return "Aborted by user"; + } + return "Error code: " + hex(hr, 8); +} + +#define IF_AVI_ERROR_THROW(expr) CODE_MACRO( \ + HRESULT hrMacro = (expr); \ + IF_TRUE_THROW(FAILED(hrMacro), Exception(aviErrorMessage(hrMacro))); \ +) + +class AVIFileInitializer : Uncopyable +{ +public: + AVIFileInitializer() { AVIFileInit(); } + ~AVIFileInitializer() { AVIFileExit(); } +}; + +class AVIFile : Uncopyable +{ +public: + AVIFile(File file) + { + NullTerminatedWideString inputPathWide(file.path()); + IF_AVI_ERROR_THROW( + AVIFileOpen(&_aviFile, inputPathWide, OF_READ, NULL)); + } + ~AVIFile() { AVIFileRelease(_aviFile); } + void getStream(IAVIStream** aviStream, DWORD fccType, LONG lParam) + { + IF_AVI_ERROR_THROW(_aviFile->GetStream(aviStream, fccType, lParam)); + } + //AVIFILEINFO aviFileInfo; + //ZeroMemory(&aviFileInfo, sizeof(AVIFILEINFO)); + //IF_AVI_ERROR_THROW(aviFile->Info(&aviFileInfo, sizeof(AVIFILEINFO))); + //int width = aviFileInfo.dwWidth; + //int height = aviFileInfo.dwHeight; +private: + IAVIFile* _aviFile; +}; + +class AVIStream +{ +public: + AVIStream(AVIFile* aviFile, DWORD fccType = streamtypeVIDEO, + LONG lParam = 0) + { + aviFile->getStream(&_aviStream, fccType, lParam); + ZeroMemory(&_aviStreamInfo, sizeof(AVISTREAMINFO)); + IF_AVI_ERROR_THROW(_aviStream->Info(&_aviStreamInfo, + sizeof(AVISTREAMINFO))); + + if (_aviStreamInfo.fccType != streamtypeVIDEO) + throw Exception("Not a video stream"); + + LONG cbFormat = 0; + _aviStream->ReadFormat(_frame, 0, &cbFormat); + _formatBuffer.ensure(cbFormat); + IF_AVI_ERROR_THROW(_aviStream->ReadFormat(_frame, &_formatBuffer[0], + &cbFormat)); + _bitmapInfoHeader = + *reinterpret_cast(&_formatBuffer[0]); + } + PGETFRAME getFrameOpen() + { + BITMAPINFOHEADER header = _bitmapInfoHeader; + header.biSize = sizeof(BITMAPINFOHEADER); + header.biCompression = BI_RGB; + header.biBitCount = 24; + return AVIStreamGetFrameOpen(_aviStream, &header); + } + BITMAPINFOHEADER bitmapInfoHeader() { return _bitmapInfoHeader; } + int frames() { return _aviStreamInfo.dwLength; } +private: + COMPointer _aviStream; + AVISTREAMINFO _aviStreamInfo; + BITMAPINFOHEADER _bitmapInfoHeader; + PCMWAVEFORMAT _pcmWaveFormat; + LONG _frame; + //Array _buffer; + Array _formatBuffer; +}; + +class GetFrame : Uncopyable +{ +public: + GetFrame(AVIStream* aviStream) : _getFrame(aviStream->getFrameOpen()) + { + _bitmapInfoHeader = aviStream->bitmapInfoHeader(); + _frames = aviStream->frames(); + _frame = 0; + } + Bitmap getFrame(Bitmap bitmap) + { + int height = _bitmapInfoHeader.biHeight; + if (height < 0) + height = -height; + //if (_bitmapInfoHeader.biCompression != BI_RGB) + // throw Exception("Don't know how to decode this pixel type yet"); + Vector s(_bitmapInfoHeader.biWidth, height); + //_buffer.ensure(s.x * s.y * _bitmapInfoHeader.biBitCount / 8); + bitmap.ensure(s); + //LONG lBytes; + //LONG lSamples; + //IF_AVI_ERROR_THROW(_aviStream->Read(_frame, 1, &_buffer[0], + // s.x * s.y * 4, &lBytes, &lSamples)); + //if (lBytes > s.x * s.y * 4) + // throw Exception("Frame too large"); + //if (lSamples != 1) + // throw Exception("Didn't get 1 frame"); + + Byte* sl = static_cast(_getFrame->GetFrame(_frame)) + + sizeof(BITMAPINFOHEADER); + + if (_bitmapInfoHeader.biBitCount == 24) { + //auto sl = &_buffer[0]; + int ss = _bitmapInfoHeader.biWidth * 3; + if (_bitmapInfoHeader.biHeight > 0) { + sl += ss * (s.y - 1); + ss = -ss; + } + auto dl = bitmap.data(); + for (int y = 0; y < s.y; ++y) { + auto p = reinterpret_cast(sl); + auto d = reinterpret_cast(dl); + for (int x = 0; x < s.x; ++x) { + *d = *p; + ++p; + ++d; + } + sl += ss; + dl += bitmap.stride(); + } + } + else { + if (_bitmapInfoHeader.biBitCount != 32) { + throw Exception( + "Don't know how to decode this pixel size yet"); + } + //auto sl = &_buffer[0]; + int ss = _bitmapInfoHeader.biWidth * 4; + if (_bitmapInfoHeader.biHeight > 0) { + sl += ss * (s.y - 1); + ss = -ss; + } + auto dl = bitmap.data(); + for (int y = 0; y < s.y; ++y) { + auto p = reinterpret_cast(sl); + auto d = reinterpret_cast(dl); + for (int x = 0; x < s.x; ++x) { + DWORD v = *p; + *d = SRGB((v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff); + ++p; + ++d; + } + sl += ss; + dl += bitmap.stride(); + } + } + ++_frame; + return bitmap; + } + bool atEnd() { return _frame == _frames; } + ~GetFrame() { AVIStreamGetFrameClose(_getFrame); } +private: + PGETFRAME _getFrame; + BITMAPINFOHEADER _bitmapInfoHeader; + int _frames; + int _frame; +}; + +class AVIOptions +{ +public: + AVIOptions(HWND hParent, IAVIStream** videoStream) + : _hParent(hParent), _videoStream(videoStream) + { + ZeroMemory(&_opts, sizeof(_opts)); + _opts.fccHandler = mmioFOURCC('u', 'l', 'r', 'g'); + _opts.dwFlags = AVICOMPRESSF_VALID; + _opts.cbParms = 0; // 4; + } + void showOptions() + { + _aopts[0] = &_opts; + IF_FALSE_THROW( + AVISaveOptions(_hParent, 0, 1, _videoStream, _aopts) == TRUE); + } + AVICOMPRESSOPTIONS* options() { return _aopts[0]; } + ~AVIOptions() { AVISaveOptionsFree(1, _aopts); } +private: + AVICOMPRESSOPTIONS _opts; + AVICOMPRESSOPTIONS* _aopts[1]; + HWND _hParent; + IAVIStream** _videoStream; +}; + +class AVIWriter +{ +public: + AVIWriter(File file, Vector size, Rational frameRate, + /*const WAVEFORMATEX* waveFormatEx,*/ + HWND hParent) + { + BITMAPINFO bi; + ZeroMemory(&bi, sizeof(bi)); + BITMAPINFOHEADER& bih = bi.bmiHeader; + bih.biSize = sizeof(bih); + bih.biWidth = size.x; + bih.biHeight = size.y; + bih.biPlanes = 1; + bih.biBitCount = 24; + bih.biCompression = BI_RGB; + _bytesPerLine = (bih.biWidth * bih.biBitCount / 8 + 3) & -4; + bih.biSizeImage = _bytesPerLine * size.y; + bih.biXPelsPerMeter = 10000; + bih.biYPelsPerMeter = 10000; + bih.biClrUsed = 0; + bih.biClrImportant = 0; + + HDC hdcScreen = GetDC(0); + _hdc = CreateCompatibleDC(hdcScreen); + ReleaseDC(0, hdcScreen); + + _hBitmap = CreateDIBSection(_hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, + &_bits, NULL, NULL); + IF_ZERO_THROW(_hBitmap); + IF_ZERO_THROW(GetObject(_hBitmap, sizeof(_dibSection), &_dibSection)); + + NullTerminatedWideString w(file.path()); + IF_AVI_ERROR_THROW( + AVIFileOpen(&_pfile, w, OF_WRITE | OF_CREATE, NULL)); + //if (waveFormatEx == NULL) + // ZeroMemory(&_waveFormatEx, sizeof(WAVEFORMATEX)); + //else + // CopyMemory(&_waveFormatEx, waveFormatEx, sizeof(WAVEFORMATEX)); + //_audioStream = 0; + _frames = 0; + //_samples = 0; + + AVISTREAMINFO strhdr; + ZeroMemory(&strhdr, sizeof(strhdr)); + strhdr.fccType = streamtypeVIDEO; + strhdr.fccHandler = 0; + strhdr.dwRate = frameRate.numerator; + strhdr.dwScale = frameRate.denominator; + strhdr.dwSuggestedBufferSize = _dibSection.dsBmih.biSizeImage; + SetRect(&strhdr.rcFrame, 0, 0, _dibSection.dsBmih.biWidth, + _dibSection.dsBmih.biHeight); + IF_AVI_ERROR_THROW( + AVIFileCreateStream(_pfile, &_videoStream, &strhdr)); + + { + AVIOptions options(hParent, &_videoStream); + options.showOptions(); + IF_AVI_ERROR_THROW(AVIMakeCompressedStream(&_compressedStream, + _videoStream, options.options(), NULL)); + } + IF_AVI_ERROR_THROW(AVIStreamSetFormat(_compressedStream, 0, + &_dibSection.dsBmih, _dibSection.dsBmih.biSize + + _dibSection.dsBmih.biClrUsed * sizeof(RGBQUAD))); + } + ~AVIWriter() + { + //if (_audioStream != 0) + // AVIStreamRelease(_audioStream); + if (_compressedStream != 0) + AVIStreamRelease(_compressedStream); + if (_videoStream != 0) + AVIStreamRelease(_videoStream); + if (_pfile != 0) + AVIFileRelease(_pfile); + + DeleteDC(_hdc); + DeleteObject(_hBitmap); + } + + void AddAviFrame() + { + IF_AVI_ERROR_THROW(AVIStreamWrite(_compressedStream, _frames, 1, + _dibSection.dsBm.bmBits, _dibSection.dsBmih.biSizeImage, + AVIIF_KEYFRAME, NULL, NULL)); + ++_frames; + } + Byte* bits() { return static_cast(_bits); } + int stride() { return _bytesPerLine; } + +private: + IAVIFile* _pfile; + //WAVEFORMATEX _waveFormatEx; + //IAVIStream* _audioStream; + IAVIStream* _videoStream; + IAVIStream* _compressedStream; + int _frames; + //int _samples; + HDC _hdc; + HBITMAP _hBitmap; + void* _bits; + DIBSECTION _dibSection; + int _bytesPerLine; +}; + +#endif // INCLUDED_AVI_H diff --git a/80386/disassembler/include/alfe/bitmap.h b/80386/disassembler/include/alfe/bitmap.h new file mode 100644 index 0000000..7992e84 --- /dev/null +++ b/80386/disassembler/include/alfe/bitmap.h @@ -0,0 +1,202 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_BITMAP_H +#define INCLUDED_BITMAP_H + +#include "alfe/colour_space.h" +#include "alfe/vectors.h" + +template class Bitmap; + +template class BitmapFileFormat : public Handle +{ +public: + Bitmap load(const File& file) const + { + return body()->load(file); + } + void save(Bitmap& bitmap, const File& file) const + { + return body()->save(bitmap, file); + } +protected: + class Body : public Handle::Body + { + public: + virtual void save(Bitmap& bitmap, const File& file) const = 0; + virtual Bitmap load(const File& file) const = 0; + }; + BitmapFileFormat(const Handle& handle) : Handle(handle) { } + Body* body() { return as(); } + const Body* body() const { return as(); } +private: + friend class Bitmap; +}; + +template class RawFileFormatTemplate; +typedef RawFileFormatTemplate RawFileFormat; + +template class RawFileFormatTemplate : public BitmapFileFormat +{ +public: + RawFileFormatTemplate(Vector size) + : BitmapFileFormat(this->create(size)) { } +private: + class Body : public BitmapFileFormat::Body + { + public: + Body(Vector size) : _size(size) { } + // The bitmap needs to be 8-bit sRGB data for this to work. + virtual void save(Bitmap& bitmap, const File& file) const + { + FileStream stream = file.openWrite(); + Byte* data = bitmap.data(); + int stride = bitmap.stride(); + Vector size = bitmap.size(); + for (int y = 0; y < size.y; ++y) { + stream.write(static_cast(data), size.x*sizeof(T)); + data += stride; + } + } + // This will put 8-bit sRGB data in the bitmap. + virtual Bitmap load(const File& file) const + { + FileStream stream = file.openRead(); + Bitmap bitmap(_size); + Byte* data = bitmap.data(); + int stride = bitmap.stride(); + for (int y = 0; y < _size.y; ++y) { + stream.read(static_cast(data), _size.x*sizeof(T)); + data += stride; + } + return bitmap; + } + private: + Vector _size; + }; +}; + +// A Bitmap is a value class encapsulating a 2D image. Its width, height, +// stride and pixel format are immutable but the pixels themselves are not. +template class Bitmap : private Array +{ +public: + Bitmap() : _size(0, 0) { } + Bitmap(Vector size) + { + _stride = size.x*sizeof(Pixel); + _size = size; + this->allocate(size.x*size.y); + _topLeft = reinterpret_cast(&Array::operator[](0)); + } + void ensure(Vector s) + { + if (size().x < s.x || size().y < s.y) + *this = Bitmap(Vector(max(size().x, s.x), max(size().y, s.y))); + } + + // Convert from one pixel format to another. + template void convert( + Bitmap& target, Converter converter) + { + Byte* row = data(); + Byte* targetRow = target.data(); + for (int y = 0; y < _size.y; ++y) { + Pixel* p = reinterpret_cast(row); + TargetPixel* tp = reinterpret_cast(targetRow); + for (int x = 0; x < _size.x; ++x) { + *tp = converter.convert(*p); + ++p; + ++tp; + } + row += _stride; + targetRow += target.stride(); + } + } + + void load(const BitmapFileFormat& format, const File& file) + { + *this = format.load(file); + } + + void save(const BitmapFileFormat& format, const File& file) + { + format.save(*this, file); + } + Byte* data() { return _topLeft; } + const Byte* data() const { return _topLeft; } + int stride() const { return _stride; } + Vector size() const { return _size; } + bool valid() const { return _size.x != 0; } + Pixel* row(int y) + { + return reinterpret_cast(_topLeft + y*_stride); + } + Pixel& operator[](Vector position) { return row(position.y)[position.x]; } + + // A sub-bitmap of a bitmap is a pointer into the same set of data, so + // drawing on a subBitmap will also draw on the parent bitmap, and any + // other overlapping sub-bitmaps. This can be used in conjunction with + // fill() to draw rectangles. To avoid this behavior, use + // subBitmap().clone(). + Bitmap subBitmap(Vector topLeft, Vector size) + { + return Bitmap(*this, + _topLeft + topLeft.x*sizeof(Pixel) + topLeft.y*_stride, size, + _stride); + } + + Bitmap clone() const + { + Bitmap c(_size); + copyTo(c); + return c; + } + + void fill(const Pixel& pixel) + { + Byte* row = data(); + for (int y = 0; y < _size.y; ++y) { + Pixel* p = reinterpret_cast(row); + for (int x = 0; x < _size.x; ++x) { + *p = pixel; + ++p; + } + row += _stride; + } + } + + // Copy with pixel format conversion but no resizing. Bitmaps must be the + // same dimensions. + template void copyFrom(const Bitmap& other) + { + Byte* row = data(); + const Byte* otherRow = other.data(); + for (int y = 0; y < _size.y; ++y) { + Pixel* p = reinterpret_cast(row); + const OtherPixel* op = + reinterpret_cast(otherRow); + for (int x = 0; x < _size.x; ++x) { + *p = *op; + ++p; + ++op; + } + row += _stride; + otherRow += other._stride; + } + } + template void copyTo(Bitmap& other) const + { + other.copyFrom(*this); + } + +private: + Bitmap(Array array, Byte* topLeft, Vector size, int stride) + : Array(array), _topLeft(topLeft), _size(size), _stride(stride) { } + + Vector _size; + Byte* _topLeft; + int _stride; +}; + +#endif // INCLUDED_BITMAP_H diff --git a/80386/disassembler/include/alfe/bitmap_png.h b/80386/disassembler/include/alfe/bitmap_png.h new file mode 100644 index 0000000..fafa4e0 --- /dev/null +++ b/80386/disassembler/include/alfe/bitmap_png.h @@ -0,0 +1,280 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_BITMAP_PNG_H +#define INCLUDED_BITMAP_PNG_H + +#include +#include "alfe/bitmap.h" + +// Currently T needs to be DWORD (0x00RRGGBB) or SRGB (0xRR, 0xGG, 0xBB). +template class PNGFileFormat : public BitmapFileFormat +{ +public: + PNGFileFormat() : BitmapFileFormat(Handle::create()) { } +private: + class Body : public BitmapFileFormat::Body + { + public: + virtual void save(Bitmap& bitmap, const File& file) const + { + FileStream stream = file.openWrite(); + PNGWrite write(&stream); + write.write(bitmap); + } + virtual Bitmap load(const File& file) const + { + FileStream stream = file.openRead(); + Array header(8); + stream.read(&header[0], 8); + if (png_sig_cmp(&header[0], 0, 8)) + throw Exception(file.path() + " is not a .png file"); + return PNGRead(&stream).read(); + } + private: + static void userReadData(png_structp png_ptr, png_bytep data, + png_size_t length) + { + FileStream* stream = + static_cast(png_get_io_ptr(png_ptr)); + stream->read(static_cast(data), static_cast(length)); + } + static void userWriteData(png_structp png_ptr, png_bytep data, + png_size_t length) + { + FileStream* stream = + static_cast(png_get_io_ptr(png_ptr)); + stream->write(static_cast(data), static_cast(length)); + } + static void userFlushData(png_structp png_ptr) { } + static void userErrorFunction(png_structp png_ptr, + png_const_charp error_msg) + { + FileStream* stream = + static_cast(png_get_error_ptr(png_ptr)); + throw Exception("Error reading: " + stream->file().path() + ": " + + error_msg); + } + static void userWarningFunction(png_structp png_ptr, + png_const_charp error_msg) + { + FileStream* stream = + static_cast(png_get_error_ptr(png_ptr)); + throw Exception("Error reading: " + stream->file().path() + ": " + + error_msg); + } + + class PNGRead + { + public: + PNGRead(FileStream* stream) : _stream(stream) + { + _png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + static_cast(stream), userErrorFunction, + userWarningFunction); + if (_png_ptr == 0) + throw Exception("Error creating PNG read structure"); + } + Bitmap read() + { + _info_ptr = png_create_info_struct(_png_ptr); + if (_info_ptr == 0) + throw Exception("Error creating PNG info structure"); + png_set_read_fn(_png_ptr, static_cast(_stream), + userReadData); + png_set_sig_bytes(_png_ptr, 8); + png_read_png(_png_ptr, _info_ptr, + PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_SHIFT, 0); + _row_pointers = png_get_rows(_png_ptr, _info_ptr); + Vector size(png_get_image_width(_png_ptr, _info_ptr), + png_get_image_height(_png_ptr, _info_ptr)); + Bitmap bitmap(size); + doCopy(bitmap, png_get_channels(_png_ptr, _info_ptr)); + return bitmap; + } + ~PNGRead() + { + png_destroy_read_struct(&_png_ptr, &_info_ptr, 0); + } + private: + template void doCopy(Bitmap bitmap, int channels) + { + throw Exception(); + } + template<> void doCopy(Bitmap bitmap, int channels) + { + Byte* data = bitmap.data(); + int stride = bitmap.stride(); + Vector size = bitmap.size(); + switch (channels) { + case 1: + for (int y = 0; y < size.y; ++y) { + auto o = reinterpret_cast(data); + auto i = _row_pointers[y]; + for (int x = 0; x < size.x; ++x) { + *o = SRGB(*i, *i, *i); + ++i; + ++o; + } + data += stride; + } + break; + case 2: + for (int y = 0; y < size.y; ++y) { + auto o = reinterpret_cast(data); + auto i = _row_pointers[y]; + for (int x = 0; x < size.x; ++x) { + *o = SRGB(*i, *i, *i); + i += 2; + ++o; + } + data += stride; + } + break; + case 3: + for (int y = 0; y < size.y; ++y) { + memcpy(reinterpret_cast(data), + _row_pointers[y], size.x*3); + data += stride; + } + break; + case 4: + for (int y = 0; y < size.y; ++y) { + auto o = reinterpret_cast(data); + auto i = _row_pointers[y]; + for (int x = 0; x < size.x; ++x) { + *o = SRGB(i[0], i[1], i[2]); + i += 4; + ++o; + } + data += stride; + } + break; + } + } + template<> void doCopy(Bitmap bitmap, int channels) + { + Byte* data = bitmap.data(); + int stride = bitmap.stride(); + Vector size = bitmap.size(); + switch (channels) { + case 1: + for (int y = 0; y < size.y; ++y) { + auto o = reinterpret_cast(data); + auto i = _row_pointers[y]; + for (int x = 0; x < size.x; ++x) { + *o = ((*i)*0x010101) | 0xff000000; + ++i; + ++o; + } + data += stride; + } + break; + case 2: + for (int y = 0; y < size.y; ++y) { + auto o = reinterpret_cast(data); + auto i = _row_pointers[y]; + for (int x = 0; x < size.x; ++x) { + *o = ((*i)*0x010101) | (i[1] << 24); + i += 2; + ++o; + } + data += stride; + } + break; + case 3: + for (int y = 0; y < size.y; ++y) { + auto o = reinterpret_cast(data); + auto i = _row_pointers[y]; + for (int x = 0; x < size.x; ++x) { + *o = (i[0] << 16) | (i[1] << 8) | i[2] | + 0xff000000; + i += 3; + ++o; + } + data += stride; + } + break; + case 4: + for (int y = 0; y < size.y; ++y) { + auto o = reinterpret_cast(data); + auto i = _row_pointers[y]; + for (int x = 0; x < size.x; ++x) { + *o = (i[0] << 16) | (i[1] << 8) | i[2] | + (i[3] << 24); + i += 4; + ++o; + } + data += stride; + } + break; + } + } + + png_structp _png_ptr; + png_infop _info_ptr; + png_bytep* _row_pointers; + FileStream* _stream; + }; + + class PNGWrite + { + public: + PNGWrite(FileStream* stream) : _stream(stream) + { + _png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + static_cast(stream), userErrorFunction, + userWarningFunction); + if (_png_ptr == 0) + throw Exception("Error creating PNG write structure"); + } + void write(Bitmap& bitmap) + { + _info_ptr = png_create_info_struct(_png_ptr); + if (_info_ptr == 0) + throw Exception("Error creating PNG info structure"); + png_set_write_fn(_png_ptr, static_cast(_stream), + userWriteData, userFlushData); + Vector size = bitmap.size(); + png_set_IHDR(_png_ptr, _info_ptr, size.x, size.y, 8, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + Array rows(size.y); + Byte* data = bitmap.data(); + int stride = bitmap.stride(); + for (int y = 0; y < size.y; ++y) { + rows[y] = data; + data += stride; + } + png_set_rows(_png_ptr, _info_ptr, + static_cast(&rows[0])); + doWrite(); + } + ~PNGWrite() + { + png_destroy_write_struct(&_png_ptr, &_info_ptr); + } + private: + template void doWrite() + { + throw Exception(); + } + template<> void doWrite() + { + png_write_png(_png_ptr, _info_ptr, PNG_TRANSFORM_IDENTITY, + NULL); + } + template<> void doWrite() + { + png_write_png(_png_ptr, _info_ptr, + PNG_TRANSFORM_BGR | PNG_TRANSFORM_STRIP_FILLER_AFTER, + NULL); + } + png_structp _png_ptr; + png_infop _info_ptr; + png_bytep* _row_pointers; + FileStream* _stream; + }; + }; +}; + +#endif // INCLUDED_BITMAP_PNG_H diff --git a/80386/disassembler/include/alfe/bitwise.h b/80386/disassembler/include/alfe/bitwise.h new file mode 100644 index 0000000..82757b0 --- /dev/null +++ b/80386/disassembler/include/alfe/bitwise.h @@ -0,0 +1,34 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_BITWISE_H +#define INCLUDED_BITWISE_H + +#ifdef _MSC_VER +#include +#endif + +int roundUpToPowerOf2(int n) +{ +#ifdef _MSC_VER + unsigned long k; + _BitScanReverse(&k, n); + if ((n & (n - 1)) != 0) + ++k; + return 1 << k; +#elif defined __GNUC__ + int k = (sizeof(int)*8 - 1) - __builtin_clz(n); + if ((n & (n - 1)) != 0) + ++k; + return 1 << k; +#else + --n; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + return n + 1; +#endif +} + +#endif // INCLUDED_BITWISE_H diff --git a/80386/disassembler/include/alfe/body_with_handle.txt b/80386/disassembler/include/alfe/body_with_handle.txt new file mode 100644 index 0000000..8a5b91d --- /dev/null +++ b/80386/disassembler/include/alfe/body_with_handle.txt @@ -0,0 +1,269 @@ +New: + +class String : private Handle + class Body : public Handle::Body + // vtable pointer from Handle::Body + // int _count from Handle::Body + int _used; + class BodyWithArray + // vtable pointer from Handle::Body + // int _count from Handle::Body + // int _used from Body + // int _size from BodyWithArray + // Body* _body from Handle + Byte* _data; + int _length; + +String is 12 bytes +OwningBody is 12 bytes+ +1 allocation overhead +1 dereference to get to data + +Array : private Handle + class BodyWithArray + // vtable pointer from Handle::Body + // int _count from Body + // int _size from BodyWithArray + // Body* _body from Handle + +AppendableArray : private Handle + class BodyWithArray + // vtable pointer from Handle::Body + // int _count from Handle::Body + // int _size from BodyWithArray + // Body* _body from Handle + int _allocated; + + +Current: + +class String + class Buffer : private Handle + // Body* _body from Handle + class Body : public Handle::Body + // vtable pointer from Handle::Body + // int _count from Handle::Body + const Byte* _data; + class OwningBody : public Body + // vtable pointer from Handle::Body + // int _count from Handle::Body + // const Byte* _data from Body + int _allocated; + int _used; + Buffer _buffer; + int _start; + int _length; + +String is 12 bytes +OwningBody is 16 bytes +2 allocation overheads +2 dereferences to get to data + + + + + +VS: + +Debug: + +32-bit: + Alignment: 0x08 bytes + Overhead: 0x2c bytes +64-bit: + Alignment: 0x10 bytes + Overhead: 0x3c bytes + +Release: + +32-bit: + Alignment: 0x08 bytes + Overhead: 0x08 bytes + + +64-bit: + Alignment: 0x10 bytes + Overhead: 0x08 bytes + Minimum total: 0x20 bytes (but sometimes 0x10?) + + + +GCC: + +32-bit: + Alignment: 0x08 bytes + Overhead: 0x04 bytes + Minimum total: 0x10 bytes + +64-bit: + Alignment: 0x10 bytes + Overhead: 0x08 bytes + Minimum total: 0x20 bytes + + + +So, let's assume 0x10 byte alignment and 0x08 byte overhead +Our overhead is 0x10 bytes on 32-bit and 0x14 bytes on 64-bit + We will allocate blocks of sizes: + +32-bit: + Absolute malloc-arg usable + 0x10 0x08 - + 0x20 0x18 0x08 + 0x40 0x38 0x28 + 0x80 0x78 0x68 +Start with 8 bytes. Each time, double and add 0x18 bytes + +64-bit: + Absolute malloc-arg usable + 0x10 0x08 - + 0x20 0x18 0x04 + 0x40 0x38 0x24 + 0x80 0x78 0x64 +Start with 4 bytes. Each time, double and add 0x1c bytes + +Start with 0x10, keep doubling until there's enough space + raw_size *= 2; + array_size = raw_size - (8 + sizeof(H)); + array_count = array_size / sizeof(T); + +Given number of items allocated (_allocated): + x = _allocated*2*sizeof(T) + headSize()+8 + x = round_to_power_of_2(x) + new_allocated = (x - headSize()+8)/sizeof(T) + + + + + + + //public: + // Buffer(const char* data) : Handle(new LiteralBody(data)) { } + // Buffer(int length) : Handle(new OwningBody(length)) { } + // int end() const + // { + // if (!valid()) + // return -1; + // return body()->end(); + // } + // void expand(const ::Byte* data, int length) + // { + // body()->expand(data, length); + // } + // void expand(int length) { body()->expand(length); } + // const ::Byte* data() const + // { + // if (!valid()) + // return 0; + // return body()->constData(); + // } + // ::Byte* data() + // { + // if (!valid()) + // return 0; + // return body()->data(); + // } + //private: + // class Body : public Handle::Body + // { + // public: + // virtual int end() const = 0; + // virtual void expand(const ::Byte* data, int length) = 0; + // virtual void expand(int length) = 0; + // const ::Byte* constData() const { return _data; } + // ::Byte* data() { return const_cast< ::Byte*>(_data); } + // protected: + // const ::Byte* _data; + // }; + // Body* body() { return as(); } + // const Body* body() const { return as(); } + // class OwningBody : public Body + // { + // public: + // OwningBody(int n) + // { + // _allocated = n; + // _used = 0; + // Body::_data = static_cast< ::Byte*>(operator new(n)); + // } + // ~OwningBody() + // { + // operator delete(data()); + // } + // int end() const { return _used; } + // void expand(const ::Byte* source, int length) + // { + // expand(length); + // memcpy(data() + _used - length, source, length); + // } + // void expand(int length) + // { + // int allocate = _allocated; + // while (allocate < _used + length) + // allocate *= 2; + // if (_allocated < allocate) { + // const ::Byte* newData = + // static_cast(operator new(allocate)); + // swap(Body::_data, newData); + // memcpy(data(), newData, _used); + // operator delete(const_cast< ::Byte*>(newData)); + // _allocated = allocate; + // } + // _used += length; + // } + // private: + // int _allocated; + // int _used; + // }; + + // class LiteralBody : public Body + // { + // public: + // LiteralBody(const char* data) + // { + // Body::_data = reinterpret_cast(data); + // } + // int end() const { return -1; } + // void expand(const ::Byte* data, int length) { throw Exception(); } + // void expand(int length) { throw Exception(); } + // }; + private: + + + + +Currently, Arrays are Uncopyable. +One reason to switch to using BodyWithArray is that Array can be copyable. + However, they will copy by reference rather than by value. +Another reason is so that we can cheaply make slices of arrays like we do bitmaps + Let's not do this just now, since we don't have a use for it. + + +Currently, an AppendableArray can be used whereever an Array is expected. + However, if we put _allocated in the Body then this will no longer be true, since there will be a different offset to the data + +Solutions: + Have AppendableArray and Array be completely different types, one not convertable to the other + This is actually fine - we don't rely on this behavior anywhere + Have _allocated in the Handle rather than the body (as in the current implementation) + This is fine too because if _allocated changes then the body pointer will change too + +String is basically an AppendableArray + but with the other way around - the BodyWithArray's size() gives the number of allocated items, not the number used + We can do this because String only holds Bytes, which don't have constructors + Why did we do this again? + Because we're storing _length in the String (for non-owning and small strings) so we don't need it in the Body + But the body needs to know the first and last unused storage location separately from _length, so we might as well just use AppendableArray + +String is lightweight - copied around and passed/returned a lot, so we want to minimize sizeof(String) and not keep _allocated there + It would be nice to be able to implement String in terms of AppendableArray so let's put _allocated in the Body + + + +https://msdn.microsoft.com/en-us/library/jj620914.aspx + + + + + + diff --git a/80386/disassembler/include/alfe/boolean_functions.h b/80386/disassembler/include/alfe/boolean_functions.h new file mode 100644 index 0000000..b079617 --- /dev/null +++ b/80386/disassembler/include/alfe/boolean_functions.h @@ -0,0 +1,26 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_BOOLEAN_FUNCTIONS_H +#define INCLUDED_BOOLEAN_FUNCTIONS_H + +#include "alfe/function.h" + +class LogicalNotBoolean : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + return Value(!arguments.begin()->value()); + } + Identifier identifier() const { return OperatorNot(); } + FunctionType type() const + { + return FunctionType(BooleanType(), BooleanType()); + } + }; +}; + +#endif // INCLUDED_BOOLEAN_FUNCTIONS_H diff --git a/80386/disassembler/include/alfe/cga.h b/80386/disassembler/include/alfe/cga.h new file mode 100644 index 0000000..2064ad5 --- /dev/null +++ b/80386/disassembler/include/alfe/cga.h @@ -0,0 +1,2256 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_CGA_H +#define INCLUDED_CGA_H + +#include "alfe/user.h" +#include "alfe/ntsc_decode.h" +#include "alfe/scanlines.h" +#include "alfe/wrap.h" +#include "alfe/timer.h" +#include "alfe/bitmap_png.h" +#include "alfe/thread.h" + +#ifdef COLOURS_3BIT +static const SRGB rgbiPalette[16] = { + SRGB(0x00, 0x00, 0x00), SRGB(0x00, 0x00, 0xff), + SRGB(0x00, 0xff, 0x00), SRGB(0x00, 0xff, 0xff), + SRGB(0xff, 0x00, 0x00), SRGB(0xff, 0x00, 0xff), + SRGB(0xff, 0xff, 0x00), SRGB(0xff, 0xff, 0xff), + SRGB(0x00, 0x00, 0x00), SRGB(0x00, 0x00, 0xff), + SRGB(0x00, 0xff, 0x00), SRGB(0x00, 0xff, 0xff), + SRGB(0xff, 0x00, 0x00), SRGB(0xff, 0x00, 0xff), + SRGB(0xff, 0xff, 0x00), SRGB(0xff, 0xff, 0xff)}; +#else +static const SRGB rgbiPalette[16] = { + SRGB(0x00, 0x00, 0x00), SRGB(0x00, 0x00, 0xaa), + SRGB(0x00, 0xaa, 0x00), SRGB(0x00, 0xaa, 0xaa), + SRGB(0xaa, 0x00, 0x00), SRGB(0xaa, 0x00, 0xaa), + SRGB(0xaa, 0x55, 0x00), SRGB(0xaa, 0xaa, 0xaa), + SRGB(0x55, 0x55, 0x55), SRGB(0x55, 0x55, 0xff), + SRGB(0x55, 0xff, 0x55), SRGB(0x55, 0xff, 0xff), + SRGB(0xff, 0x55, 0x55), SRGB(0xff, 0x55, 0xff), + SRGB(0xff, 0xff, 0x55), SRGB(0xff, 0xff, 0xff)}; +#endif + +class CGASequencer +{ +public: + CGASequencer() + { + static Byte palettes[] = { + 0, 2, 4, 6, 0, 10, 12, 14, 0, 3, 5, 7, 0, 11, 13, 15, + 0, 3, 4, 7, 0, 11, 12, 15, 0, 3, 4, 7, 0, 11, 12, 15}; + memcpy(_palettes, palettes, 32); + } + void setROM(File rom) { _cgaROM = rom.contents(); } + const Byte* romData() { return &_cgaROM[0x300*8]; } + +// +HRES +GRPH gives a0 cded ghih in startup phase 0 odd Except all start at same pixel, so output byte depends on more than 4 bytes of input data +// +HRES +GRPH gives abcb efgf ij in other phase 1 even <- use this one for compatibility with -HRES modes +// with 1bpp +HRES, odd bits are ignored (76543210 = -0-1-2-3) + +// Can we do all the graphics modes with tables? +// 1bpp: 16 pixel positions * 2 colours * 16 palettes = 512 UInt64 elements (4kB) +// 2bpp: 8 pixel positions * 4 colours * 128 palettes = 4096 UInt64 element (32kB) +// Pixel positions * colour is same for 1bpp and 2bpp so we could use 2bpp code for 1bpp as well (excluding table initialization) +// Would need to do some profiling to see if it's actually faster or if it uses too much cache +// Usually we'd only care about one palette row = 256 bytes +// Or do it bytewise? + + + // renders a 1 character by 1 scanline region of CGA VRAM data into RGBI + // data. + // cursor is cursor output pin from CRTC + // cursorBlink counts from 0..3 then repeats, changes every 8 frames (low + // bit cursor, high bit blink) + // mode bit 6 is phase + // input bits 0-7 are first/character byte + // input bits 8-15 are second/attribute byte + // input bits 24-31 are previous (latched) attribute byte + UInt64 process(UInt32 input, UInt8 mode, UInt8 palette, int scanline, + bool cursor, int cursorBlink) + { + if ((mode & 8) == 0) + return 0; + Character c; + UInt64 r = 0; + int x; + Byte* pal; + UInt64 fg; + UInt64 bg; + + switch (mode & 0x53) { + case 0x00: + case 0x40: + // 40-column text mode + c = getCharacter(input, mode, scanline, cursor, cursorBlink); + fg = (c.attribute & 0x0f) * 0x11; + bg = (c.attribute >> 4) * 0x11; + for (x = 0; x < 8; ++x) + r += ((c.bits & (0x80 >> x)) != 0 ? fg : bg) << (x*8); + break; + case 0x01: + case 0x41: + // 80-column text mode + c = getCharacter(input, mode, scanline, cursor, cursorBlink); + fg = c.attribute & 0x0f; + bg = c.attribute >> 4; + for (x = 0; x < 8; ++x) + r += ((c.bits & (0x80 >> x)) != 0 ? fg : bg) << (x*4); + break; + case 0x02: + case 0x42: + // 2bpp graphics mode + pal = &_palettes[((palette & 0x30) >> 2) + ((mode & 4) << 2)]; + *pal = palette & 0xf; + for (int x = 0; x < 4; ++x) { + r += static_cast( + pal[(input >> (6 - x*2)) & 3] * 0x11) << (x*8); + } + for (int x = 0; x < 4; ++x) { + r += static_cast( + pal[(input >> (14 - x*2)) & 3] * 0x11) << (32 + x*8); + } + break; + case 0x03: + // Improper: +HRES 2bpp graphics mode + pal = &_palettes[((palette & 0x30) >> 2) + ((mode & 4) << 2)]; + *pal = palette & 0xf; + for (int x = 0; x < 4; ++x) { + r += static_cast( + pal[(input >> (6 - x*2)) & 3]) << (x*4); + } + for (int x = 0; x < 4; ++x) { + r += static_cast( + pal[(input >> (14 - x*2)) & 3]) << (16 + x*4); + } + break; + case 0x43: + // Improper: +HRES 2bpp graphics mode + pal = &_palettes[((palette & 0x30) >> 2) + ((mode & 4) << 2)]; + *pal = palette & 0xf; + // The attribute byte is not latched for odd hchars, so the + // second column uses the previously latched value. + for (int x = 0; x < 4; ++x) { + r += static_cast( + pal[(input >> (6 - x*2)) & 3]) << (x*4); + } + for (int x = 0; x < 4; ++x) { + r += static_cast( + pal[(input >> (30 - x*2)) & 3]) << (16 + x*4); + } + break; + case 0x10: + case 0x50: + // Improper: 40-column text mode with 1bpp graphics overlay + c = getCharacter(input, mode, scanline, cursor, cursorBlink); + fg = (c.attribute & 0x0f) * 0x11; + bg = (c.attribute >> 4) * 0x11; + for (x = 0; x < 8; ++x) + r += ((c.bits & (128 >> x)) != 0 ? fg : bg) << (x*8); + // Shift register loaded from attribute latch before attribute + // latch loaded from VRAM, so the second column uses the + // previously latched value. + for (int x = 0; x < 8; ++x) { + if ((input & (0x80 >> x)) == 0) + r &= ~(static_cast(0x0f) << (x*4)); + } + for (int x = 0; x < 8; ++x) { + if ((input & (0x80000000 >> x)) == 0) + r &= ~(static_cast(0x0f) << (32 + x*4)); + } + break; + case 0x11: + case 0x51: + // Improper: 80-column text mode with +HRES 1bpp graphics mode + c = getCharacter(input, mode, scanline, cursor, cursorBlink); + fg = c.attribute & 0x0f; + bg = c.attribute >> 4; + for (x = 0; x < 8; ++x) + r += ((c.bits & (128 >> x)) != 0 ? fg : bg) << (x*4); + // Shift register loaded from attribute latch before attribute + // latch loaded from VRAM, so the second column uses the + // previously latched value on both odd and even hchars. + for (int x = 0; x < 4; ++x) { + if ((input & (0x40 >> (x*2))) == 0) + r &= ~(static_cast(0x0f) << (x*4)); + } + for (int x = 0; x < 4; ++x) { + if ((input & (0x40000000 >> (x*2))) == 0) + r &= ~(static_cast(0x0f) << (16 + x*4)); + } + break; + case 0x12: + case 0x52: + // 1bpp graphics mode + for (int x = 0; x < 8; ++x) { + if ((input & (0x80 >> x)) != 0) + r += static_cast(palette & 0x0f) << (x*4); + } + for (int x = 0; x < 8; ++x) { + if ((input & (0x8000 >> x)) != 0) + r += static_cast(palette & 0x0f) << (32 + x*4); + } + break; + case 0x13: + // Improper: +HRES 1bpp graphics mode + // Only the even bits have an effect. + for (int x = 0; x < 4; ++x) { + if ((input & (0x40 >> (x*2))) != 0) + r += static_cast(palette & 0x0f) << (x*4); + } + for (int x = 0; x < 4; ++x) { + if ((input & (0x4000 >> (x*2))) != 0) + r += static_cast(palette & 0x0f) << (16 + x*4); + } + break; + case 0x53: + // Improper: +HRES 1bpp graphics mode + // Only the even bits have an effect. + // The attribute byte is not latched for odd hchars, so the + // second column uses the previously latched value. + for (int x = 0; x < 4; ++x) { + if ((input & (0x40 >> (x*2))) != 0) + r += static_cast(palette & 0x0f) << (x*4); + } + for (int x = 0; x < 4; ++x) { + if ((input & (0x40000000 >> (x*2))) != 0) + r += static_cast(palette & 0x0f) << (16 + x*4); + } + break; + } + return r; + } +private: + struct Character + { + int bits; + int attribute; + }; + + Character getCharacter(UInt16 input, UInt8 mode, int scanline, bool cursor, + int cursorBlink) + { + Character c; + c.bits = romData()[(input & 0xff)*8 + (scanline & 7)]; + c.attribute = input >> 8; + if (cursor && ((cursorBlink & 1) != 0)) + c.bits = 0xff; + else { + if ((mode & 0x20) != 0 && (c.attribute & 0x80) != 0 && + (cursorBlink & 2) != 0 && !cursor) + c.bits = 0; + } + if ((mode & 0x20) != 0) + c.attribute &= 0x7f; + return c; + } + + String _cgaROM; + Byte _palettes[32]; +}; + +class CGAComposite +{ +public: + CGAComposite() : _newCGA(false), _bw(false) { } + void initChroma() + { + double maxV = 0; + for (int x = 0; x < 1024; ++x) + maxV = max(maxV, tableValue(x)); + double vBlack = tableValue(0); + double vWhite = tableValue(1023); + maxV = max(maxV, (vWhite - vBlack)*4/3 + vBlack); + + // v p q f + // + // 0 0 + // tableValue(0) 0.416 0 + // tableValue(1023) 1.46 1 + // maxV 255 >= 4/3 + + // p = n*v + m + // 0.416 = n*vBlack + m + // 1.46 = n*vWhite + m + // 0.416*vWhite = n*vBlack*vWhite + m*vWhite + // 1.46*vBlack = n*vBlack*vWhite + m*vBlack + // 0.416*vWhite - 1.46*vBlack = m*(vWhite - vBlack) + double m = (0.416*vWhite - 1.46*vBlack)/(vWhite - vBlack); + double n = (1.46 - m)/vWhite; + + // q = v*a + b + // q = p*c = (n*v + m)*c = n*c*v + m*c + // a = n*c, b = m*c + // 255 = (n*maxV + m)*c + double c = 255.0/(n*maxV + m); + double a = n*c; + double b = m*c; + for (int x = 0; x < 1024; ++x) + _table[x] = byteClamp(tableValue(x)*a + b); + _black = vBlack*a + b; + _white = vWhite*a + b; + + // v p + // + // tableValue(0) 0.291 + // tableValue(0x1df) 1.04 + if (!_newCGA) { + double vGrey = tableValue((0x77 << 2) + 3); + m = (0.291*vGrey - 1.04*vBlack)/(vGrey - vBlack); + n = (1.04 - m)/vGrey; + a = n*c; + b = m*c; + } + + for (int x = 0; x < 0x77*4; ++x) { + double q; + if ((x & 0x10) != 0) { + // Sync + q = 0; + } + else { + if ((x & 0x20) != 0) { + // Burst + q = tableValue((0x66 << 2) + (x & 3))*a + b; + } + else { + // Blank + q = tableValue(x & 3)*a + b; + } + } + _syncTable[x] = byteClamp(q); + } + } + Byte simulateCGA(int left, int right, int phase) + { + if ((left | right) < 16) + return _table[((left & 15) << 6) + ((right & 15) << 2) + phase]; + return _syncTable[(left << 2) + phase]; + } + Byte simulateHalfCGA(int left, Byte right, int phase) + { + int b = _table[((left & 15) << 6) + phase]; + int w = _table[((left & 15) << 6) + 0x3c + phase]; + int bb = _table[phase]; + int ww = _table[0x3fc + phase]; + return (right - bb)*(w - b)/(ww - bb) + b; + } + Byte simulateRightHalfCGA(Byte left, int right, int phase) + { + int b = _table[((right & 15) << 2) + phase]; + int w = _table[0x3c0 + ((right & 15) << 2) + phase]; + int bb = _table[phase]; + int ww = _table[0x3fc + phase]; + return (left - bb)*(w - b)/(ww - bb) + b; + } + void simulateLine(const Byte* rgbi, Byte* ntsc, int length, int phase) + { + for (int x = 0; x < length; ++x) { + phase = (phase + 1) & 3; + int left = *rgbi; + ++rgbi; + int right = *rgbi; + *ntsc = simulateCGA(left, right, phase); + ++ntsc; + } + } + void decode(int pixels, int* s) + { + int rgbi[4]; + rgbi[0] = pixels & 15; + rgbi[1] = (pixels >> 4) & 15; + rgbi[2] = (pixels >> 8) & 15; + rgbi[3] = (pixels >> 12) & 15; + for (int t = 0; t < 4; ++t) + s[t] = simulateCGA(rgbi[t], rgbi[(t+1)&3], t); + } + + void setNewCGA(bool newCGA) + { + if (newCGA == _newCGA) + return; + _newCGA = newCGA; + initChroma(); + } + bool getNewCGA() { return _newCGA; } + + void setBW(bool bw) + { + if (bw == _bw) + return; + _bw = bw; + initChroma(); + } + + // A real monitor will figure out appropriate black and white levels from + // the sync and blanking levels. However, CGA voltages are somewhat outside + // of NTSC spec, so there is a lot of variation between monitors in terms + // of black and white levels. We return the actual CGA black and white + // levels here so that emulated output devices can make sensible defaults + // (setting black and white levels to sRGB (0, 0, 0) and (255, 255, 255) + // respectively). + double black() { return _black; } + double white() { return _white; } +private: + double tableValue(int x) + { + static unsigned char chromaData[256] = { + 2, 2, 2, 2, 114,174, 4, 3, 2, 1,133,135, 2,113,150, 4, + 133, 2, 1, 99, 151,152, 2, 1, 3, 2, 96,136, 151,152,151,152, + 2, 56, 62, 4, 111,250,118, 4, 0, 51,207,137, 1,171,209, 5, + 140, 50, 54,100, 133,202, 57, 4, 2, 50,153,149, 128,198,198,135, + 32, 1, 36, 81, 147,158, 1, 42, 33, 1,210,254, 34,109,169, 77, + 177, 2, 0,165, 189,154, 3, 44, 33, 0, 91,197, 178,142,144,192, + 4, 2, 61, 67, 117,151,112, 83, 4, 0,249,255, 3,107,249,117, + 147, 1, 50,162, 143,141, 52, 54, 3, 0,145,206, 124,123,192,193, + 72, 78, 2, 0, 159,208, 4, 0, 53, 58,164,159, 37,159,171, 1, + 248,117, 4, 98, 212,218, 5, 2, 54, 59, 93,121, 176,181,134,130, + 1, 61, 31, 0, 160,255, 34, 1, 1, 58,197,166, 0,177,194, 2, + 162,111, 34, 96, 205,253, 32, 1, 1, 57,123,125, 119,188,150,112, + 78, 4, 0, 75, 166,180, 20, 38, 78, 1,143,246, 42,113,156, 37, + 252, 4, 1,188, 175,129, 1, 37, 118, 4, 88,249, 202,150,145,200, + 61, 59, 60, 60, 228,252,117, 77, 60, 58,248,251, 81,212,254,107, + 198, 59, 58,169, 250,251, 81, 80, 100, 58,154,250, 251,252,252,252 + }; + static double intensity[4] = { + 77.175381, 88.654656, 166.564623, 174.228438}; + int phase = x & 3; + int right = (x >> 2) & 15; + int left = (x >> 6) & 15; + int rc = right; + int lc = left; + if (_bw) { + rc = (right & 8) | ((right & 7) != 0 ? 7 : 0); + lc = (left & 8) | ((left & 7) != 0 ? 7 : 0); + } + double c = chromaData[((lc & 7) << 5) | ((rc & 7) << 2) | phase]; + double i = intensity[(left >> 3) | ((right >> 2) & 2)]; + if (!_newCGA) + return c + i; + double r = intensity[((left >> 2) & 1) | ((right >> 1) & 2)]; + double g = intensity[((left >> 1) & 1) | (right & 2)]; + double b = intensity[(left & 1) | ((right << 1) & 1)]; + return (c/0.72)*0.29 + (i/0.28)*0.32 + (r/0.28)*0.1 + (g/0.28)*0.22 + + (b/0.28)*0.07; + } + + bool _newCGA; + bool _bw; + Byte _table[1024]; + Byte _syncTable[0x77*4]; + double _black; + double _white; +}; + +// The CGAData structure encapsulates the state of the (extended) CGA's VRAM +// over a period of time (e.g. one CRT frame which contains several palette +// register updates). The structure is a binary tree of arrays of changes. A +// change consists of updates to a consecutive seqeuence of (VRAM or register) +// addresses. The two sides of the binary tree each span the same number of +// hdots, and that number is always a power of 2. +class CGAData : Uncopyable +{ +public: + CGAData() : _total(1) { reset(); } + void reset() + { + _root.reset(); + _endAddress = 0; + } + // Output RGBI values: + // 0-15: normal active data + // 16-54: blanking + // bit 0: CRT hsync + // bit 1: CRT vsync + // bit 2: composite sync (CRT hsync ^ CRT vsync) + // bit 3: colour burst + // bit 4: CRTC hsync + // bit 5: CRTC vsync + // bit 6: CRTC hsync | CRTC vsync + // Only the following blanking values actually occur: + // 0x50: CRTC hsync + // 0x55: CRT hsync (composite sync) + // 0x58: Colour burst (suppressed during CRTC vsync) + // 0x60: CRTC vsync + // 0x66: CRT vsync (composite sync) + // 0x70: CRTC hsync + CRTC vsync + // 0x73: CRT hsync + CRT vsync (no composite sync) + // 0x75: CRT hsync + CRTC vsync (composite sync) + // 0x76: CRTC hsync + CRT vsync (composite sync) + void output(int t, int n, Byte* rgbi, CGASequencer* sequencer, int phase) + { + Lock lock(&_mutex); + + State state; + state._n = n; + state._rgbi = rgbi; + state._t = t; + state._addresses = _endAddress - registerLogCharactersPerBank; + state._data.allocate(state._addresses); + state._sequencer = sequencer; + state._phase = phase != 0 ? 0x40 : 0; + for (const auto& c : _root._changes) + c.getData(&state._data, 0, registerLogCharactersPerBank, + state._addresses, 0); + state.reset(); + if (_root._right != 0) + _root._right->output(0, 0, _total, &state); + state.runTo(t + n); + } + enum { + registerLogCharactersPerBank = -26, // log(characters per bank)/log(2) + registerScanlinesRepeat, + registerHorizontalTotalHigh, + registerHorizontalDisplayedHigh, + registerHorizontalSyncPositionHigh, + registerVerticalTotalHigh, + registerVerticalDisplayedHigh, + registerVerticalSyncPositionHigh, + registerMode, // port 0x3d8 + registerPalette, // port 0x3d9 + registerHorizontalTotal, // CRTC register 0x00 + registerHorizontalDisplayed, // CRTC register 0x01 + registerHorizontalSyncPosition, // CRTC register 0x02 + registerHorizontalSyncWidth, // CRTC register 0x03 + registerVerticalTotal, // CRTC register 0x04 + registerVerticalTotalAdjust, // CRTC register 0x05 + registerVerticalDisplayed, // CRTC register 0x06 + registerVerticalSyncPosition, // CRTC register 0x07 + registerInterlaceMode, // CRTC register 0x08 + registerMaximumScanline, // CRTC register 0x09 + registerCursorStart, // CRTC register 0x0a + registerCursorEnd, // CRTC register 0x0b + registerStartAddressHigh, // CRTC register 0x0c + registerStartAddressLow, // CRTC register 0x0d + registerCursorAddressHigh, // CRTC register 0x0e + registerCursorAddressLow // CRTC register 0x0f + }; // 0 onwards: VRAM + void change(int t, int address, Byte data) + { + change(t, address, 1, &data); + } + void change(int t, int address, int count, const Byte* data) + { + Lock lock(&_mutex); + changeNoLock(t, address, count, data); + } + void remove(int t, int address, int count = 1) + { + Lock lock(&_mutex); + _root.remove(t, address, count, 0, _total); + } + void setTotals(int total, int pllWidth, int pllHeight) + { + Lock lock(&_mutex); + if (_root._right != 0) + _root._right->resize(_total, total); + _total = total; + _pllWidth = pllWidth; + _pllHeight = pllHeight; + } + int getTotal() + { + Lock lock(&_mutex); + return _total; + } + int getPLLWidth() { return _pllWidth; } + int getPLLHeight() { return _pllHeight; } + void save(File file) + { + Lock lock(&_mutex); + AppendableArray data; + data.append(reinterpret_cast("CGAD"), 4); + DWord version = 0; + data.append(reinterpret_cast(&version), 4); + DWord total = _total; + data.append(reinterpret_cast(&total), 4); + DWord pllWidth = _pllWidth; + data.append(reinterpret_cast(&pllWidth), 4); + DWord pllHeight = _pllHeight; + data.append(reinterpret_cast(&pllHeight), 4); + _root.save(&data, 0, 0, _total); + file.openWrite().write(data); + } + void load(File file) + { + Lock lock(&_mutex); + _root.reset(); + Array data; + file.readIntoArray(&data); + if (deserialize(&data, 0) != *reinterpret_cast("CGAD")) + throw Exception(file.path() + " is not a CGAData file."); + if (deserialize(&data, 4) != 0) + throw Exception(file.path() + " is too new for this program."); + _total = deserialize(&data, 8); + _pllWidth = deserialize(&data, 12); + _pllHeight = deserialize(&data, 16); + int offset = 20; + do { + if (offset == data.count()) + return; + int t = deserialize(&data, offset); + int address = deserialize(&data, offset + 4); + int count = deserialize(&data, offset + 8); + int length = 12 + count; + if (offset + length > data.count()) + throw Exception(file.path() + " is truncated."); + changeNoLock(t, address, count, &data[offset + 12]); + offset += (length + 3) & ~3; + } while (true); + } + void saveVRAM(File file) + { + file.openWrite().write(getData(0, _endAddress, 0)); + } + void loadVRAM(File file) + { + Lock lock(&_mutex); + _root.reset(); + Array data; + file.readIntoArray(&data); + changeNoLock(0, 0, data.count(), &data[0]); + } + Byte getDataByte(int address, int t = 0) + { + return getData(address, 1, t)[0]; + } + Array getData(int address, int count, int t = 0) + { + Lock lock(&_mutex); + Array result(count); + Array gotResult(count); + for (int i = 0; i < count; ++i) + gotResult[i] = false; + _root.getData(&result, &gotResult, t, address, count, 0, _total, 0); + return result; + } + +private: + void changeNoLock(int t, int address, int count, const Byte* data) + { + _root.change(t, address, count, data, 0, _total); + if (address + count > _endAddress) { + _endAddress = address + count; + _root.ensureAddresses(registerLogCharactersPerBank, _endAddress); + } + } + int deserialize(Array* data, int offset) + { + if (data->count() < offset + 4) + return -1; + return *reinterpret_cast(&(*data)[offset]); + } + + struct Change + { + Change() { } + Change(int address, const Byte* data, int count) + : _address(address), _data(count) + { + memcpy(&_data[0], data, count); + } + int count() const { return _data.count(); } + int start() const { return _address; } + int end() const { return _address + count(); } + int getData(Array* result, Array* gotResult, int address, + int count, int gotCount) const + { + int s = max(address, start()); + int e = min(address + count, end()); + for (int a = s; a < e; ++a) { + int i = a - address; + if (gotResult == 0 || !(*gotResult)[i]) { + (*result)[i] = _data[a - _address]; + if (gotResult != 0) + (*gotResult)[i] = true; + ++gotCount; + } + } + return gotCount; + } + + int _address; + Array _data; + }; + struct State + { + void latch() + { + int vRAMAddress = _memoryAddress << 1; + int bytesPerBank = 2 << dat(registerLogCharactersPerBank); + if ((dat(registerMode) & 2) != 0) { + if ((_rowAddress & 1) != 0) + vRAMAddress |= bytesPerBank; + else + vRAMAddress &= ~bytesPerBank; + } + vRAMAddress &= (bytesPerBank << 1) - 1; + _latch = (_latch << 16) + dat(vRAMAddress) + + (dat(vRAMAddress + 1) << 8); + } + void startOfFrame() + { + _memoryAddress = (dat(registerStartAddressHigh) << 8) + + dat(registerStartAddressLow); + _leftMemoryAddress = _memoryAddress; + _rowAddress = 0; + _row = 0; + _scanlineIteration = 0; + } + void reset() + { + startOfFrame(); + _character = 0; + _hdot = 0; + _state = 0; + latch(); + } + void runTo(int t) + { + Byte mode = dat(registerMode); + int hdots = (mode & 1) != 0 ? 8 : 16; + while (_t < t) { + int c = min(hdots, _hdot + t - _t); + if (_state == 0) { + UInt64 r = _sequencer->process(_latch, mode | _phase, + dat(registerPalette), _rowAddress, false, 0); + for (; _hdot < c; ++_hdot) { + *_rgbi = (r >> (_hdot * 4)) & 0x0f; + ++_rgbi; + } + } + else { + int v = 0; + if ((_state & 0x18) == 0) { + v = (mode & 0x10) != 0 ? 0 : + dat(registerPalette) & 0xf; + } + else { + v = (_state & 0x10) + ((_state & 0x20) >> 1); + static Byte sync[48] = { + 0x50, 0x50, 0x55, 0x55, 0x55, 0x55, 0x50, 0x58, + 0x58, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + + 0x70, 0x70, 0x75, 0x75, 0x75, 0x75, 0x70, 0x70, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + + 0x76, 0x76, 0x73, 0x73, 0x73, 0x73, 0x76, 0x76, + 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76}; + if ((_state & 8) != 0) { + if ((mode & 1) != 0) { + v = sync[((_hSync + (_phase >> 6)) >> 1) + v]; + } + else + v = sync[_hSync + v]; + } + else + v = (_state & 0x20) != 0 ? 0x66 : 0x60; + } + memset(_rgbi, v, c); + _rgbi += c; + _hdot += c; + } + _t += c; + if (_t == t) + break; + _hdot = 0; + + // Emulate CRTC + if (_character == dat(registerHorizontalTotal) + + (dat(registerHorizontalTotalHigh) << 8)) { + _state &= ~1; + _character = 0; + if ((_state & 0x10) != 0) { + // Vertical sync active + ++_vSync; + if ((_vSync & 0x0f) == 0) { + // End of vertical sync + _state &= ~0x30; + } + } + ++_scanlineIteration; + if (_scanlineIteration == dat(registerScanlinesRepeat)) { + _scanlineIteration = 0; + if (_rowAddress == dat(registerMaximumScanline)) { + // End of row + _rowAddress = 0; + if (_row == dat(registerVerticalTotal) + + (dat(registerVerticalTotalHigh) << 8)) { + _state |= 4; + _adjust = 0; + _latch = 0; + } + ++_row; + if (_row == dat(registerVerticalDisplayed) + + (dat(registerVerticalDisplayedHigh) << 8)) { + _state |= 2; + _latch = 0; + } + if (_row == dat(registerVerticalSyncPosition) + + (dat(registerVerticalSyncPositionHigh) << 8)) { + _state |= 0x10; + _vSync = 0; + } + _memoryAddress = _nextRowMemoryAddress; + _leftMemoryAddress = _nextRowMemoryAddress; + } + else { + ++_rowAddress; + _memoryAddress = _leftMemoryAddress; + } + } + else + _memoryAddress = _leftMemoryAddress; + if ((_state & 4) != 0) { + // Vertical total adjust active + if (_adjust == dat(registerVerticalTotalAdjust)) { + startOfFrame(); + _state &= ~4; + } + else + ++_adjust; + } + } + else { + ++_character; + ++_memoryAddress; + } + _phase ^= 0x40; + if (_character == dat(registerHorizontalDisplayed) + + (dat(registerHorizontalDisplayedHigh) << 8)) { + _state |= 1; + _nextRowMemoryAddress = _memoryAddress; + _latch = 0; + } + if ((_state & 8) != 0) { + // Horizontal sync active + ++_hSync; + bool crtSync = _hSync == 2; + if ((mode & 1) != 0) + crtSync = (((_hSync + (_phase >> 6)) >> 1) == 2); + if (crtSync && (_state & 0x10) != 0) { + if (_vSync == 0) + _state |= 0x20; + else { + if (_vSync == 3) + _state &= ~0x20; + } + } + if ((_hSync & 0x0f) == dat(registerHorizontalSyncWidth)) + _state &= ~8; + } + if (_character == dat(registerHorizontalSyncPosition) + + (dat(registerHorizontalSyncPositionHigh) << 8)) { + _state |= 8; + _hSync = 0; + } + if (_state == 0) + latch(); + } + } + Byte dat(int address) + { + return _data[address - registerLogCharactersPerBank]; + } + + int _memoryAddress; + int _leftMemoryAddress; + int _nextRowMemoryAddress; + int _rowAddress; + int _character; + int _adjust; + int _hSync; + int _vSync; + int _row; + int _hdot; + int _n; + int _t; + int _phase; + int _addresses; + int _scanlineIteration; + + // _state bits: + // 0 = we are in horizontal overscan + // 1 = we are in vertical overscan + // 2 = we are in vertical total adjust + // 3 = we are in horizontal sync + // 4 = we are in vertical CRTC sync + // 5 = we are in vertical CRT sync + int _state; + UInt32 _latch; + Byte* _rgbi; + Array _data; + CGASequencer* _sequencer; + }; + struct Node + { + Node() : _left(0), _right(0) { } + void reset() + { + if (_left != 0) + delete _left; + if (_right != 0) + delete _right; + } + ~Node() { reset(); } + void findChanges(int address, int count, int* start, int* end) + { + int lowStart = 0; + int lowEnd = _changes.count() - 1; + while (lowStart < lowEnd) { + int lowTest = lowStart + (lowEnd - lowStart)/2; + if (_changes[lowTest].end() <= address) { + lowStart = lowTest + 1; + continue; + } + if (_changes[lowTest].start() >= address + count) { + lowEnd = lowTest - 1; + continue; + } + lowStart = lowTest; + break; + } + int highStart = lowStart; + int highEnd = _changes.count() - 1; + while (highStart < highEnd) { + int highTest = highStart + (highEnd - highStart)/2; + if (_changes[highTest].start() >= address + count) { + highStart = highTest - 1; + continue; + } + if (_changes[highTest].end() <= address) { + highEnd = highTest + 1; + continue; + } + highStart = highTest; + break; + } + *start = lowStart; + *end = highEnd; + } + void change(int t, int address, int count, const Byte* data, + int leftTotal, int rightTotal) + { + if (t > 0) { + if (_right == 0) + _right = new Node(); + int rlTotal = roundUpToPowerOf2(rightTotal) / 2; + _right->change(t - rlTotal, address, count, data, rlTotal, + rightTotal - rlTotal); + return; + } + if (t == 0) { + int start, end; + findChanges(address, count, &start, &end); + if (start == end) { + Change* c = &_changes[start]; + if (address >= c->start() && address + count <= c->end()) { + memcpy(&c->_data[0] + address - c->start(), data, + count); + return; + } + } + if (start <= end) { + int startAddress = min(address, _changes[start].start()); + Change e = _changes[end]; + int e2 = address + count; + int endAddress = max(e2, e.end()); + Change c; + c._data.allocate(endAddress - startAddress); + c._address = startAddress; + int a = 0; + if (startAddress < address) { + a = address - startAddress; + memcpy(&c._data[0], &_changes[start]._data[0], + min(a, _changes[start].count())); + } + memcpy(&c._data[a], data, count); + if (endAddress > e2) { + int offset = e2 - e.start(); + if (offset >= 0) { + memcpy(&c._data[a + count], + &e._data[e2 - e.start()], endAddress - e2); + } + else { + memcpy(&c._data[a + count - offset], + &e._data[0], endAddress - e.start()); + } + } + if (start < end) { + Array changes(_changes.count() + start - end); + for (int i = 0; i < start; ++i) + changes[i] = _changes[i]; + changes[start] = c; + for (int i = start + 1; i < changes.count(); ++i) + changes[i] = _changes[i + end - start]; + _changes = changes; + } + else + _changes[start] = c; + } + else { + Array changes(_changes.count() + 1); + for (int i = 0; i < start; ++i) + changes[i] = _changes[i]; + changes[start] = Change(address, data, count); + for (int i = start; i < _changes.count(); ++i) + changes[i + 1] = _changes[i]; + _changes = changes; + } + return; + } + if (_left == 0) + _left = new Node(); + int llTotal = roundUpToPowerOf2(leftTotal) / 2; + int lrTotal = leftTotal - llTotal; + _left->change(t + lrTotal, address, count, data, llTotal, lrTotal); + } + void remove(int t, int address, int count, int leftTotal, + int rightTotal) + { + if (t > 0) { + if (_right != 0) { + int rlTotal = roundUpToPowerOf2(rightTotal) / 2; + _right->remove(t - rlTotal, address, count, rlTotal, + rightTotal - rlTotal); + } + return; + } + if (t == 0) { + int start, end; + findChanges(address, count, &start, &end); + int deleteStart = end, deleteEnd = start; + for (int i = start; i < end; ++i) { + int newCount; + Change c = _changes[i]; + int e2 = address + count; + if (address < c._address) { + newCount = max(0, c.end() - e2); + int offset = c.count() - newCount; + _changes[i] = Change(c._address + offset, + &c._data[offset], newCount); + } + else { + newCount = address - c.start(); + if (newCount < c.count()) { + _changes[i] = + Change(c._address, &c._data[0], newCount); + if (e2 < c.end()) { + Array changes(_changes.count() + 1); + for (int j = 0; j <= i; ++j) + changes[j] = _changes[j]; + changes[i + 1] = + Change(e2, &c._data[newCount + count], + c.end() - e2); + for (int j = i + 1; j < _changes.count(); ++j) + changes[j + 1] = _changes[j]; + _changes = changes; + } + } + } + if (_changes[i].count() == 0) { + deleteStart = min(deleteStart, i); + deleteEnd = max(deleteStart, i + 1); + } + } + int deleteCount = deleteEnd - deleteStart; + if (deleteCount > 0) { + Array changes(_changes.count() - deleteCount); + for (int i = 0; i < deleteStart; ++i) + changes[i] = _changes[i]; + for (int i = deleteEnd; i < _changes.count(); ++i) + changes[i - deleteCount] = _changes[i]; + _changes = changes; + } + return; + } + if (_left != 0) { + int llTotal = roundUpToPowerOf2(leftTotal) / 2; + int lrTotal = leftTotal - llTotal; + _left->remove(t + lrTotal, address, count, llTotal, lrTotal); + } + } + int getData(Array* result, Array* gotResult, int t, + int address, int count, int leftTotal, int rightTotal, + int gotCount) + { + if (t > 0 && _right != 0) { + int rlTotal = roundUpToPowerOf2(rightTotal) / 2; + int c = _right->getData(result, gotResult, t - rlTotal, + address, count, rlTotal, rightTotal - rlTotal, gotCount); + if (c == gotCount) + return c; + gotCount = c; + } + if (t >= 0 && _changes.count() != 0) { + int start, end; + findChanges(address, count, &start, &end); + for (int i = start; i <= end; ++i) { + gotCount = _changes[i].getData(result, gotResult, address, + count, gotCount); + } + } + if (_left != 0) { + int llTotal = roundUpToPowerOf2(leftTotal) / 2; + int lrTotal = leftTotal - llTotal; + gotCount = _left->getData(result, gotResult, t + lrTotal, + address, count, llTotal, lrTotal, gotCount); + } + return gotCount; + } + void resize(int oldTotal, int newTotal) + { + int lTotal = roundUpToPowerOf2(oldTotal) / 2; + do { + if (lTotal < newTotal) + break; + if (_right != 0) + delete _right; + Node* left = _left; + *this = *left; + left->_left = 0; + left->_right = 0; + delete left; + oldTotal = lTotal; + lTotal /= 2; + } while (true); + do { + int rTotal = oldTotal - lTotal; + int newLTotal = roundUpToPowerOf2(newTotal) / 2; + if (lTotal >= newLTotal) + break; + Node* newNode = new Node(); + newNode->_left = this; + *this = *newNode; + oldTotal += lTotal; + lTotal *= 2; + } while (true); + if (_right != 0) + _right->resize(oldTotal - lTotal, newTotal - lTotal); + } + void save(AppendableArray* array, int t, int leftTotal, + int rightTotal) + { + if (_left != 0) { + int llTotal = roundUpToPowerOf2(leftTotal) / 2; + int lrTotal = leftTotal - llTotal; + _left->save(array, t - lrTotal, llTotal, lrTotal); + } + for (auto c : _changes) { + DWord tt = t; + array->append(reinterpret_cast(&tt), 4); + array->append(reinterpret_cast(&c._address), 4); + DWord count = c._data.count(); + array->append(reinterpret_cast(&count), 4); + array->append(&c._data[0], count); + DWord zero = 0; + array->append(reinterpret_cast(&zero), + ((~count) + 1) & 3); + } + if (_right != 0) { + int rlTotal = roundUpToPowerOf2(rightTotal) / 2; + _right-> + save(array, t + rlTotal, rlTotal, rightTotal - rlTotal); + } + } + void output(int t, int leftTotal, int rightTotal, State* state) + { + if (_left != 0) { + int llTotal = roundUpToPowerOf2(leftTotal) / 2; + int lrTotal = leftTotal - llTotal; + _left->output(t - lrTotal, llTotal, lrTotal, state); + } + if (t >= state->_t + state->_n) { + state->runTo(state->_t + state->_n); + return; + } + state->runTo(t); + for (const auto& c : _changes) { + c.getData(&state->_data, 0, registerLogCharactersPerBank, + state->_addresses, 0); + } + if (_right != 0) { + int rlTotal = roundUpToPowerOf2(rightTotal) / 2; + _right->output(t + rlTotal, rlTotal, rightTotal - rlTotal, + state); + } + } + void ensureAddresses(int startAddress, int endAddress) + { + if (_changes.count() == 0) + _changes.allocate(1); + int count = endAddress - startAddress; + if (_changes[0]._data.count() < count) { + Array data(count); + memcpy(&data[0] + _changes[0]._address - startAddress, + &_changes[0]._data[0], _changes[0]._data.count()); + _changes[0]._data = data; + _changes[0]._address = startAddress; + } + } + + Node* _left; + Array _changes; + Node* _right; + }; + // The root of the tree always has a 0 _left branch. + Node _root; + int _total; + int _pllWidth; + int _pllHeight; + int _endAddress; + Mutex _mutex; +}; + +class CGAOutput : public ThreadTask +{ +public: + CGAOutput(CGAData* data, CGASequencer* sequencer, BitmapWindow* window) + : _data(data), _sequencer(sequencer), _window(window), _zoom(0), + _aspectRatio(1), _inputTL(0, 0), _outputSize(0, 0), _active(false) + { } + void run() + { + int connector; + Vector outputSize; + int combFilter; + bool showClipping; + float brightness; + float contrast; + Vector2 inputTL; + float overscan; + double zoom; + double aspectRatio; + static const int decoderPadding = 32; + Vector2 zoomVector; + bool bw; + { + Lock lock(&_mutex); + if (!_active) + return; + + int total = _data->getTotal(); + _rgbi.ensure(total); + _data->output(0, total, &_rgbi[0], _sequencer, _phase); + + connector = _connector; + combFilter = _combFilter; + showClipping = _showClipping; + outputSize = _outputSize; + inputTL = _inputTL; + overscan = static_cast(_overscan); + zoom = _zoom; + aspectRatio = _aspectRatio; + Byte mode = _data->getDataByte(CGAData::registerMode); + bw = (mode & 4) != 0; + _composite.setBW(false); + bool newCGA = connector == 2; + _composite.setNewCGA(newCGA); + _composite.initChroma(); + double black = _composite.black(); + double white = _composite.white(); + _decoder.setHue(_hue + ((mode & 1) != 0 ? 14 : 4) + + (combFilter == 2 ? 180 : 0)); + _decoder.setSaturation(_saturation*1.45*(newCGA ? 1.5 : 1.0)/100); + contrast = static_cast(_contrast/100); + static const int combDivisors[3] = {1, 2, 4}; + int scaling = combDivisors[combFilter]; + _decoder.setInputScaling(scaling); + double c = _contrast*256*(newCGA ? 1.2 : 1)/((white - black)*100); + _decoder.setContrast(c/scaling); + brightness = static_cast(_brightness/100); + _decoder.setBrightness((-black*c + + _brightness*5 + (newCGA ? -50 : 0))/256.0); + _decoder.setChromaBandwidth(_chromaBandwidth); + _decoder.setLumaBandwidth(_lumaBandwidth); + _decoder.setRollOff(_rollOff); + _decoder.setLobes(_lobes); + _scaler.setProfile(_scanlineProfile); + _scaler.setHorizontalProfile(_horizontalProfile); + _scaler.setWidth(static_cast(_scanlineWidth)); + _scaler.setBleeding(_scanlineBleeding); + _scaler.setHorizontalBleeding(_horizontalBleeding); + _scaler.setHorizontalRollOff( + static_cast(_horizontalRollOff)); + _scaler.setVerticalRollOff(static_cast(_verticalRollOff)); + _scaler.setHorizontalLobes(static_cast(_horizontalLobes)); + _scaler.setVerticalLobes(static_cast(_verticalLobes)); + _scaler.setSubPixelSeparation( + static_cast(_subPixelSeparation)); + _scaler.setPhosphor(_phosphor); + _scaler.setMask(_mask); + _scaler.setMaskSize(static_cast(_maskSize)); + zoomVector = scale(); + _scaler.setZoom(zoomVector); + } + + int srgbSize = _data->getTotal(); + _srgb.ensure(srgbSize*3); + int pllWidth = _data->getPLLWidth(); + int pllHeight = _data->getPLLHeight(); + static const int driftHorizontal = 8; + static const int driftVertical = 14*pllWidth; + _scanlines.clear(); + _fields.clear(); + _fieldOffsets.clear(); + + Byte hSync = 0x41; + Byte vSync = 0x42; + if (connector != 0) { + hSync = 0x44; + vSync = 0x44; + } + int lastScanline = 0; + int i; + Vector2 activeSize(0, 0); + do { + int offset = (lastScanline + pllWidth - driftHorizontal) % + srgbSize; + Byte* p = &_rgbi[offset]; + int n = driftHorizontal*2; + if (offset + n <= srgbSize) { + for (i = 0; i < n; ++i) { + if ((p[i] & hSync) == hSync) + break; + } + } + else { + for (i = 0; i < n; ++i) { + if ((_rgbi[(offset + i) % srgbSize] & hSync) == hSync) + break; + } + } + i = (i + offset) % srgbSize; + activeSize.x = max(activeSize.x, + static_cast(wrap(i - lastScanline, srgbSize))); + if ((_rgbi[i] & 0x80) != 0) + break; + _rgbi[i] |= 0x80; + _scanlines.append(i); + lastScanline = i; + } while (true); + int firstScanline = _scanlines.count() - 1; + for (; firstScanline > 0; --firstScanline) { + if (_scanlines[firstScanline] == i) + break; + } + int scanlines = _scanlines.count() - firstScanline; + + for (auto& s : _scanlines) + _rgbi[s] &= ~0x80; + int lastField = 0; + do { + int offset = (lastField + pllHeight - driftVertical) % + srgbSize; + Byte* p = &_rgbi[offset]; + int n = driftVertical*2; + int j; + int s = 0; + if (offset + n <= srgbSize) { + for (j = 0; j < n; j += 57) { + if ((p[j] & vSync) == vSync) { + ++s; + if (s == 3) + break; + } + else + s = 0; + } + } + else { + for (j = 0; j < n; j += 57) { + if ((_rgbi[(offset + j) % srgbSize] & vSync) == vSync) { + ++s; + if (s == 3) + break; + } + else + s = 0; + } + } + j = (j + offset) % srgbSize; + lastField = j; + int s0; + int s1; + float fieldOffset; + for (i = 0; i < scanlines; ++i) { + s0 = _scanlines[ + (firstScanline + scanlines + i - 1) % scanlines]; + if (s0 < 0) + s0 = -1 - s0; + s1 = _scanlines[firstScanline + i]; + if (s1 < 0) + s1 = -1 - s1; + if (s0 < s1) { + if (j >= s0 && j < s1) { + fieldOffset = static_cast(j - s0) / (s1 - s0); + break; + } + } + else { + if (j >= s0) { + fieldOffset = + static_cast(j - s0) / (s1 + srgbSize - s0); + break; + } + else { + if (j < s1) { + fieldOffset = static_cast(j + srgbSize - s0) + / (s1 + srgbSize - s0); + break; + } + } + } + } + int fo = static_cast(fieldOffset * 8 + 0.5); + if (fo == 8) { + fo = 0; + i = (i + 1) % scanlines; + } + float f = fo/8.0f; + int c = _fields.count() - 1; + if (c >= 0) { + int iLast = _fields[c]; + float fLast = _fieldOffsets[c]; + int lines = (i - iLast + scanlines - 1) % scanlines + 1; + activeSize.y = max(activeSize.y, + static_cast(lines) + f - fLast); + } + if (_scanlines[firstScanline + i] < 0) + break; + _fields.append(i); + _fieldOffsets.append(f); + _scanlines[firstScanline + i] = -1 - _scanlines[firstScanline + i]; + } while (true); + int firstField = _fields.count() - 1; + for (; firstField > 0; --firstField) { + if (_fields[firstField] == i) + break; + } + for (auto& f : _fields) + _scanlines[firstScanline + f] = -1 - _scanlines[firstScanline + f]; + + // Assume standard overscan/blank/sync areas + activeSize -= Vector2(272, 62); + + if (outputSize.zeroArea()) { + inputTL = Vector2(157.5f, 35.5f) - overscan*activeSize; + double o = 1 + 2*overscan; + double y = zoom*activeSize.y*o; + double x = zoom*activeSize.x*o*aspectRatio/2; + outputSize = Vector(static_cast(x + 0.5), + static_cast(y + 0.5)); + + Lock lock(&_mutex); + _inputTL = inputTL; + _outputSize = outputSize; + } + Vector2 offset(0, 0); + if (connector != 0) { + offset = Vector2(-decoderPadding - 0.5f, 0); + if (combFilter == 2) + offset += Vector2(2, -1); + } + _scaler.setOffset(inputTL + offset + + Vector2(0.5f, 0.5f)/zoomVector); + _scaler.setOutputSize(outputSize); + + _bitmap.ensure(outputSize); + _scaler.init(); + _unscaled = _scaler.input(); + _scaled = _scaler.output(); + Vector tl = _scaler.inputTL(); + Vector br = _scaler.inputBR(); + _unscaledSize = br - tl; + + if (connector == 0) { + // Convert from RGBI to 9.7 fixed-point sRGB + Byte levels[4]; + for (int i = 0; i < 4; ++i) { + int l = static_cast(255.0f*brightness + 85.0f*i*contrast); + if (showClipping) { + if (l < 0) + l = 255; + else { + if (l > 255) + l = 0; + } + } + else + l = clamp(0, l, 255); + levels[i] = l; + } + // On the RGBI connector we don't show composite sync, colour + // burst, or blanking since these are not output on the actual + // connector. Blanking is visible as black if the overscan is a + // non-black colour. +#ifdef COLOURS_3BIT + int palette[3*0x78] = { + 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 3, 3, + 3, 0, 0, 3, 0, 3, 3, 3, 0, 3, 3, 3, + 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 3, 3, + 3, 0, 0, 3, 0, 3, 3, 3, 0, 3, 3, 3, + 0, 0, 0}; +#else + int palette[3*0x78] = { + 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 2, 2, + 2, 0, 0, 2, 0, 2, 2, 1, 0, 2, 2, 2, + 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 3, 3, + 3, 1, 1, 3, 1, 3, 3, 3, 1, 3, 3, 3}; +#endif + + static int overscanPalette[3*4] = { + 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0}; + for (int i = 3*0x10; i < 3*0x78; i += 3*4) + memcpy(palette + i, overscanPalette, 3*4*sizeof(int)); + Byte srgbPalette[3*0x77]; + for (int i = 0; i < 3*0x77; ++i) + srgbPalette[i] = levels[palette[i]]; + const Byte* rgbi = &_rgbi[0]; + Byte* srgb = &_srgb[0]; + for (int x = 0; x < srgbSize; ++x) { + Byte* p = &srgbPalette[3 * *rgbi]; + ++rgbi; + srgb[0] = p[0]; + srgb[1] = p[1]; + srgb[2] = p[2]; + srgb += 3; + } + } + else { + // Change to 1 to use FIR decoding for output +#define FIR_DECODING 0 +#if FIR_DECODING + int decoderOutputLength = 512 - 2*decoderPadding + _decoder.setLength(decoderOutputLength); +#else + _decoder.setPadding(decoderPadding); +#endif + Byte burst[4]; + for (int i = 0; i < 4; ++i) + burst[i] = _composite.simulateCGA(6, 6, (i + 3) & 3); + _decoder.init(); + _decoder.calculateBurst(burst); + _composite.setBW(bw); + _composite.initChroma(); +#if FIR_DECODING +#if FIR_FP + float* input = _decoder.inputData(); +#else + UInt16* input = _decoder.inputData(); +#endif + int inputLeft = _decoder.inputLeft(); + int inputRight = _decoder.inputRight(); +#endif + + int combedSize = srgbSize + 2*decoderPadding; + Vector combTL = Vector(2, 1)*combFilter; + int ntscSize = combedSize + combTL.y*pllWidth; + _ntsc.ensure(ntscSize); + int rgbiSize = ntscSize + 1; + if (_rgbi.count() < rgbiSize) { + Array rgbi(rgbiSize); + memcpy(&rgbi[0], &_rgbi[0], srgbSize); + _rgbi = rgbi; + } + memcpy(&_rgbi[srgbSize], &_rgbi[0], rgbiSize - srgbSize); + + // Convert from RGBI to composite + const Byte* rgbi = &_rgbi[0]; + Byte* ntsc = &_ntsc[0]; + for (int x = 0; x < ntscSize; ++x) { + *ntsc = _composite.simulateCGA(*rgbi, rgbi[1], x & 3); + ++rgbi; + ++ntsc; + } + // Apply comb filter and decode to sRGB. + ntsc = &_ntsc[0]; + Byte* srgb = &_srgb[0]; + static const int fftLength = 512; + int stride = fftLength - 2*decoderPadding; + Byte* ntscBlock = &_ntsc[0]; + Timer decodeTimer; + +#if FIR_DECODING + stride = decoderOutputLength; + switch (combFilter) { + case 0: + // No comb filter + for (int j = 0; j < srgbSize; j += stride) { + if (j + stride > srgbSize) { + // The last block is a small one, so we'll decode + // it by overlapping the previous one. + j = srgbSize - stride; + ntscBlock = &_ntsc[j]; + srgb = &_srgb[3*j]; + } + Byte* ip = ntscBlock + decoderPadding + inputLeft; + +#if FIR_FP + float* p = input; + for (int i = inputLeft; i < inputRight; ++i) { + p[0] = ip[0]; + p[1] = ip[0]; + p += 2; + ++ip; + } +#else + UInt16* p = input; + for (int i = inputLeft; i < inputRight; ++i) { + p[0] = ip[0] - 128; + p[1] = ip[0] - 128; + p += 2; + ++ip; + } +#endif + _decoder.execute(); + _decoder.outputToSRGB(reinterpret_cast(srgb)); + srgb += stride*3; + ntscBlock += stride; + } + break; + case 1: + // 1 line. Standard NTSC comb filters will have a delay of + // 227.5 color carrier cycles (1 standard scanline) but a + // CGA scanline is 228 color carrier cycles, so instead of + // sharpening vertical detail a comb filter applied to CGA + // will sharpen 1-ldot-per-scanline diagonals. + for (int j = 0; j < srgbSize; j += stride) { + if (j + stride > srgbSize) { + // The last block is a small one, so we'll decode + // it by overlapping the previous one. + j = srgbSize - stride; + ntscBlock = &_ntsc[j]; + srgb = &_srgb[3*j]; + } + + Byte* ip0 = ntscBlock + decoderPadding + inputLeft; + Byte* ip1 = ip0 + pllWidth; +#if FIR_FP + float* p = input; + for (int i = inputLeft; i < inputRight; ++i) { + p[0] = static_cast(2*ip0[0]); + p[1] = static_cast(ip0[0]-ip1[0]); + p += 2; + ++ip0; + ++ip1; + } +#else + UInt16* p = input; + for (int i = inputLeft; i < inputRight; ++i) { + p[0] = 2*ip0[0] - 256; + p[1] = ip0[0]-ip1[0]; + p += 2; + ++ip0; + ++ip1; + } +#endif + + _decoder.execute(); + _decoder.outputToSRGB(reinterpret_cast(srgb)); + srgb += stride*3; + ntscBlock += stride; + } + break; + case 2: + // 2 line. + for (int j = 0; j < srgbSize; j += stride) { + if (j + stride > srgbSize) { + // The last block is a small one, so we'll decode + // it by overlapping the previous one. + j = srgbSize - stride; + ntscBlock = &_ntsc[j]; + srgb = &_srgb[3*j]; + } + + Byte* ip0 = ntscBlock + decoderPadding + inputLeft; + Byte* ip1 = ip0 + pllWidth; + Byte* ip2 = ip1 + pllWidth; +#if FIR_FP + float* p = input; + for (int i = inputLeft; i < inputRight; ++i) { + p[0] = static_cast(4*ip1[0]); + p[1] = static_cast(2*ip1[0]-ip0[0]-ip2[0]); + p += 2; + ++ip0; + ++ip1; + ++ip2; + } +#else + UInt16* p = input; + for (int i = inputLeft; i < inputRight; ++i) { + p[0] = 4*ip1[0] - 512; + p[1] = 2*ip1[0]-ip0[0]-ip2[0]; + p += 2; + ++ip0; + ++ip1; + ++ip2; + } +#endif + _decoder.execute(); + _decoder.outputToSRGB(reinterpret_cast(srgb)); + srgb += stride*3; + ntscBlock += stride; + } + break; + } +#else + switch (combFilter) { + case 0: + // No comb filter + for (int j = 0; j < srgbSize; j += stride) { + if (j + stride > srgbSize) { + // The last block is a small one, so we'll decode + // it by overlapping the previous one. + j = srgbSize - stride; + ntscBlock = &_ntsc[j]; + srgb = &_srgb[3*j]; + } + _decoder.decodeNTSC(ntscBlock, + reinterpret_cast(srgb)); + srgb += stride*3; + ntscBlock += stride; + } + break; + case 1: + // 1 line. Standard NTSC comb filters will have a delay of + // 227.5 color carrier cycles (1 standard scanline) but a + // CGA scanline is 228 color carrier cycles, so instead of + // sharpening vertical detail a comb filter applied to CGA + // will sharpen 1-ldot-per-scanline diagonals. + for (int j = 0; j < srgbSize; j += stride) { + if (j + stride > srgbSize) { + // The last block is a small one, so we'll decode + // it by overlapping the previous one. + j = srgbSize - stride; + ntscBlock = &_ntsc[j]; + srgb = &_srgb[3*j]; + } + Byte* n0 = ntscBlock; + Byte* n1 = n0 + pllWidth; + float* y = _decoder.yData(); + float* i = _decoder.iData(); + float* q = _decoder.qData(); + for (int x = 0; x < fftLength; x += 4) { + y[0] = static_cast(2*n0[0]); + y[1] = static_cast(2*n0[1]); + y[2] = static_cast(2*n0[2]); + y[3] = static_cast(2*n0[3]); + i[0] = -static_cast(n0[1] - n1[1]); + i[1] = static_cast(n0[3] - n1[3]); + q[0] = static_cast(n0[0] - n1[0]); + q[1] = -static_cast(n0[2] - n1[2]); + n0 += 4; + n1 += 4; + y += 4; + i += 2; + q += 2; + } + _decoder.decodeBlock(reinterpret_cast(srgb)); + srgb += stride*3; + ntscBlock += stride; + } + break; + case 2: + // 2 line. + for (int j = 0; j < srgbSize; j += stride) { + if (j + stride > srgbSize) { + // The last block is a small one, so we'll decode + // it by overlapping the previous one. + j = srgbSize - stride; + ntscBlock = &_ntsc[j]; + srgb = &_srgb[3*j]; + } + Byte* n0 = ntscBlock; + Byte* n1 = n0 + pllWidth; + Byte* n2 = n1 + pllWidth; + float* y = _decoder.yData(); + float* i = _decoder.iData(); + float* q = _decoder.qData(); + for (int x = 0; x < fftLength; x += 4) { + y[0] = static_cast(4*n1[0]); + y[1] = static_cast(4*n1[1]); + y[2] = static_cast(4*n1[2]); + y[3] = static_cast(4*n1[3]); + i[0] = static_cast(n0[1] + n2[1] - 2*n1[1]); + i[1] = static_cast(2*n1[3] - n0[3] - n2[3]); + q[0] = static_cast(2*n1[0] - n0[0] - n2[0]); + q[1] = static_cast(n0[2] + n2[2] - 2*n1[2]); + n0 += 4; + n1 += 4; + n2 += 4; + y += 4; + i += 2; + q += 2; + } + _decoder.decodeBlock(reinterpret_cast(srgb)); + srgb += stride*3; + ntscBlock += stride; + } + break; + } +#endif + //decodeTimer.output("Decoder: "); + } + // Shift, clip, show clipping and linearization + _linearizer.setShowClipping(showClipping && _connector != 0); + tl.y = wrap(tl.y + _fields[firstField], scanlines); + Byte* unscaledRow = _unscaled.data(); + int scanlineChannels = _unscaledSize.x*3; + for (int y = 0; y < _unscaledSize.y; ++y) { + int offsetTL = wrap( + tl.x + _scanlines[(tl.y + y)%scanlines + firstScanline], + srgbSize); + const Byte* srgbRow = &_srgb[offsetTL*3]; + float* unscaled = reinterpret_cast(unscaledRow); + const Byte* srgb = srgbRow; + if (offsetTL + _unscaledSize.x > srgbSize) { + int endChannels = max(0, (srgbSize - offsetTL)*3); + for (int x = 0; x < endChannels; ++x) + unscaled[x] = _linearizer.linear(srgb[x]); + for (int x = 0; x < scanlineChannels - endChannels; ++x) + unscaled[x + endChannels] = _linearizer.linear(_srgb[x]); + } + else { + for (int x = 0; x < scanlineChannels; ++x) + unscaled[x] = _linearizer.linear(srgb[x]); + } + unscaledRow += _unscaled.stride(); + } + + // Scale to desired size and apply scanline filter + _scaler.render(); + + // Delinearization and float-to-byte conversion + const Byte* scaledRow = _scaled.data(); + Byte* outputRow = _bitmap.data(); + for (int y = 0; y < outputSize.y; ++y) { + const float* scaled = reinterpret_cast(scaledRow); + DWORD* output = reinterpret_cast(outputRow); + for (int x = 0; x < outputSize.x; ++x) { + SRGB srgb = + _linearizer.srgb(Colour(scaled[0], scaled[1], scaled[2])); + *output = (srgb.x << 16) | (srgb.y << 8) | srgb.z; + ++output; + scaled += 3; + } + scaledRow += _scaled.stride(); + outputRow += _bitmap.stride(); + } + _lastBitmap = _bitmap; + _bitmap = _window->setNextBitmap(_bitmap); + } + + void save(String outputFileName) + { + setOutputSize(Vector(0, 0)); + join(); + _lastBitmap.save(PNGFileFormat(), + File(outputFileName + ".png", true)); + + if (_connector != 0) { + FileStream s = File(outputFileName + ".ntsc", true).openWrite(); + s.write(_ntsc); + } + } + + void setConnector(int connector) + { + { + Lock lock(&_mutex); + _connector = connector; + } + restart(); + } + int getConnector() { return _connector; } + void setScanlineProfile(int profile) + { + { + Lock lock(&_mutex); + _scanlineProfile = profile; + } + restart(); + } + int getScanlineProfile() { return _scanlineProfile; } + void setHorizontalProfile(int profile) + { + { + Lock lock(&_mutex); + _horizontalProfile = profile; + } + restart(); + } + int getHorizontalProfile() { return _horizontalProfile; } + void setScanlineWidth(double width) + { + { + Lock lock(&_mutex); + _scanlineWidth = width; + } + restart(); + } + double getScanlineWidth() { return _scanlineWidth; } + void setScanlineBleeding(int bleeding) + { + { + Lock lock(&_mutex); + _scanlineBleeding = bleeding; + } + restart(); + } + int getScanlineBleeding() { return _scanlineBleeding; } + void setHorizontalBleeding(int bleeding) + { + { + Lock lock(&_mutex); + _horizontalBleeding = bleeding; + } + restart(); + } + int getHorizontalBleeding() { return _horizontalBleeding; } + void setZoom(double zoom) + { + if (zoom == 0) + zoom = 1.0; + { + Lock lock(&_mutex); + if (_window->hWnd() != 0) { + Vector mousePosition = _window->mousePosition(); + Vector size = _outputSize; + Vector2 position = Vector2Cast(size)/2.0f; + if (_dragging || (mousePosition.inside(size) && + (GetAsyncKeyState(VK_LBUTTON) & 0x8000) == 0 && + (GetAsyncKeyState(VK_RBUTTON) & 0x8000) == 0)) + position = Vector2Cast(mousePosition); + _inputTL += position*static_cast(zoom - _zoom)/( + Vector2(static_cast(_aspectRatio)/2.0f, 1.0f) + *static_cast(_zoom*zoom)); + } + _zoom = zoom; + } + restart(); + } + double getZoom() { return _zoom; } + void setHorizontalRollOff(double rollOff) + { + { + Lock lock(&_mutex); + _horizontalRollOff = rollOff; + } + restart(); + } + double getHorizontalRollOff() { return _horizontalRollOff; } + void setHorizontalLobes(double lobes) + { + { + Lock lock(&_mutex); + _horizontalLobes = lobes; + } + restart(); + } + double getHorizontalLobes() { return _horizontalLobes; } + void setVerticalRollOff(double rollOff) + { + { + Lock lock(&_mutex); + _verticalRollOff = rollOff; + } + restart(); + } + double getVerticalRollOff() { return _verticalRollOff; } + void setVerticalLobes(double lobes) + { + { + Lock lock(&_mutex); + _verticalLobes = lobes; + } + restart(); + } + double getVerticalLobes() { return _verticalLobes; } + void setSubPixelSeparation(double separation) + { + { + Lock lock(&_mutex); + _subPixelSeparation = separation; + } + restart(); + } + double getSubPixelSeparation() { return _subPixelSeparation; } + void setPhosphor(int phosphor) + { + { + Lock lock(&_mutex); + _phosphor = phosphor; + } + restart(); + } + int getPhosphor() { return _phosphor; } + void setMask(int mask) + { + { + Lock lock(&_mutex); + _mask = mask; + } + restart(); + } + int getMask() { return _mask; } + void setMaskSize(double size) + { + { + Lock lock(&_mutex); + _maskSize = size; + } + restart(); + } + double getMaskSize() { return _maskSize; } + void setAspectRatio(double ratio) + { + if (ratio == 0) + ratio = 1.0; + { + Lock lock(&_mutex); + if (_window->hWnd() != 0) { + Vector mousePosition = _window->mousePosition(); + Vector size = _outputSize; + Vector2 position = Vector2Cast(size)/2.0f; + if (_dragging || (mousePosition.inside(size) && + (GetAsyncKeyState(VK_LBUTTON) & 0x8000) == 0 && + (GetAsyncKeyState(VK_RBUTTON) & 0x8000) == 0)) + position = Vector2Cast(mousePosition); + _inputTL.x += position.x*2.0f*static_cast( + (ratio - _aspectRatio)/(_zoom*ratio*_aspectRatio)); + } + _aspectRatio = ratio; + } + restart(); + } + double getAspectRatio() { return _aspectRatio; } + void setOverscan(double overscan) + { + { + Lock lock(&_mutex); + _overscan = overscan; + } + restart(); + } + void setOutputSize(Vector outputSize) + { + { + Lock lock(&_mutex); + _outputSize = outputSize; + _active = true; + } + restart(); + } + void setCombFilter(int combFilter) + { + { + Lock lock(&_mutex); + _combFilter = combFilter; + } + restart(); + } + int getCombFilter() { return _combFilter; } + + void setHue(double hue) + { + { + Lock lock(&_mutex); + _hue = hue; + } + restart(); + } + double getHue() { return _hue; } + void setSaturation(double saturation) + { + { + Lock lock(&_mutex); + _saturation = saturation; + } + restart(); + } + double getSaturation() { return _saturation; } + void setContrast(double contrast) + { + { + Lock lock(&_mutex); + _contrast = contrast; + } + restart(); + } + double getContrast() { return _contrast; } + void setBrightness(double brightness) + { + { + Lock lock(&_mutex); + _brightness = brightness; + } + restart(); + } + double getBrightness() { return _brightness; } + void setShowClipping(bool showClipping) + { + { + Lock lock(&_mutex); + _showClipping = showClipping; + } + restart(); + } + bool getShowClipping() { return _showClipping; } + void setChromaBandwidth(double chromaBandwidth) + { + { + Lock lock(&_mutex); + _chromaBandwidth = chromaBandwidth; + } + restart(); + } + double getChromaBandwidth() { return _chromaBandwidth; } + void setLumaBandwidth(double lumaBandwidth) + { + { + Lock lock(&_mutex); + _lumaBandwidth = lumaBandwidth; + } + restart(); + } + double getLumaBandwidth() { return _lumaBandwidth; } + void setRollOff(double rollOff) + { + { + Lock lock(&_mutex); + _rollOff = rollOff; + } + restart(); + } + double getRollOff() { return _rollOff; } + void setLobes(double lobes) + { + { + Lock lock(&_mutex); + _lobes = lobes; + } + restart(); + } + double getLobes() { return _lobes; } + void setPhase(int phase) + { + { + Lock lock(&_mutex); + _phase = phase; + } + restart(); + } + + Vector requiredSize() + { + { + Lock lock(&_mutex); + if (!_outputSize.zeroArea()) + return _outputSize; + _active = true; + } + restart(); + join(); + { + Lock lock(&_mutex); + return _outputSize; + } + } + void mouseInput(Vector position, bool button) + { + _mousePosition = position; + if (button) { + if (!_dragging) { + _dragStart = position; + _dragStartInputPosition = _inputTL + + Vector2Cast(position)/scale(); + } + _inputTL = + _dragStartInputPosition - Vector2Cast(position)/scale(); + restart(); + } + _dragging = button; + } + void saveRGBI(File outputFile) + { + outputFile.openWrite().write(static_cast(&_rgbi[0]), + _data->getTotal()); + } + +private: + // Output pixels per input pixel + Vector2 scale() + { + return Vector2(static_cast(_aspectRatio)/2.0f, 1.0f)* + static_cast(_zoom); + } + + CGAData* _data; + CGASequencer* _sequencer; + AppendableArray _scanlines; // hdot positions of scanline starts + AppendableArray _fields; // scanline numbers of field starts + AppendableArray _fieldOffsets; // fractional scanline numbers + + int _connector; + int _phase; + int _scanlineProfile; + int _horizontalProfile; + double _scanlineWidth; + int _scanlineBleeding; + int _horizontalBleeding; + double _horizontalRollOff; + double _verticalRollOff; + double _horizontalLobes; + double _verticalLobes; + double _subPixelSeparation; + int _phosphor; + int _mask; + double _maskSize; + double _zoom; + double _aspectRatio; + double _overscan; + Vector _outputSize; + Vector2 _inputTL; // input position of top-left of output + double _hue; + double _saturation; + double _contrast; + double _brightness; + double _chromaBandwidth; + double _lumaBandwidth; + double _rollOff; + double _lobes; + int _combFilter; + bool _showClipping; + bool _active; + + Bitmap _bitmap; + Bitmap _lastBitmap; + CGAComposite _composite; +#if FIR_DECODING + MatchingNTSCDecoder _decoder; +#else + NTSCDecoder _decoder; +#endif + Linearizer _linearizer; + BitmapWindow* _window; + Mutex _mutex; + + ScanlineRenderer _scaler; + Vector _combedSize; + Array _rgbi; + Array _ntsc; + Array _srgb; + Vector _unscaledSize; + AlignedBuffer _unscaled; + AlignedBuffer _scaled; + + bool _dragging; + Vector _dragStart; + Vector2 _dragStartInputPosition; + Vector _mousePosition; +}; + +#endif // INCLUDED_CGA_H diff --git a/80386/disassembler/include/alfe/character_source.h b/80386/disassembler/include/alfe/character_source.h new file mode 100644 index 0000000..7da61d2 --- /dev/null +++ b/80386/disassembler/include/alfe/character_source.h @@ -0,0 +1,346 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_CHARACTER_SOURCE_H +#define INCLUDED_CHARACTER_SOURCE_H + +class Location +{ +public: + Location() : _line(0), _column(0), _offset(0) { } + Location(const File& file) : _file(file), _line(1), _column(1), _offset(0) + { } + Location(const File& file, int line, int column) + : _file(file), _line(line), _column(column), _offset(0) + { } + String toString() const + { + return _file.path() + "(" + _line + "," + _column + ")"; + } + File file() const { return _file; } + void operator++() { ++_offset; } + void advanceColumn() { ++_column; } + void advanceLine() { _column = 1; ++_line; } + void throwError(const String& message) const + { + throw Exception(toString() + ": " + message); + } + void throwErrorWithOffset(const String& message) const + { + throw Exception(toString() + ": " + message + "(offset " + + hex(_offset) + ")"); + } + int offset() const { return _offset; } + int line() const { return _line; } + int column() const { return _column; } +private: + File _file; + int _line; + int _column; + int _offset; +}; + +class Span +{ +public: + Span() : _startLine(-1) { } + Span(Location start, Location end) + : _file(start.file()), + _startLine(start.line()), + _startColumn(start.column()), + _endLine(end.line()), + _endColumn(end.column()) + { } + Span(const File& file, int startLine, int startColumn, int endLine, + int endColumn) + : _file(file), + _startLine(startLine), + _startColumn(startColumn), + _endLine(endLine), + _endColumn(endColumn) + { } + File file() const { return _file; } + int startLine() const { return _startLine; } + int startColumn() const { return _startColumn; } + int endLine() const { return _endLine; } + int endColumn() const { return _endColumn; } + String toString() const + { + return _file.path() + "(" + _startLine + "," + _startColumn + ")-(" + + _endLine + "," + _endColumn + ")"; + } + void throwError(const String& message) const + { + if (!valid()) + throw Exception(message); + throw Exception(toString() + ": " + message); + } + Location start() const + { + return Location(_file, _startLine, _startColumn); + } + Location end() const { return Location(_file, _endLine, _endColumn); } + Span operator+(const Span& other) const + { + if (!valid()) + return other; + if (!other.valid()) + return *this; + return Span(start(), other.end()); + } + const Span& operator+=(const Span& other) + { + *this = *this + other; + return *this; + } + bool valid() const { return _startLine != -1; } +private: + File _file; + int _startLine; + int _startColumn; + int _endLine; + int _endColumn; +}; + +template class CharacterSourceT +{ +public: + CharacterSourceT() { } + CharacterSourceT(const String& string) : _string(string) { } + CharacterSourceT(const String& string, const File& file) + : _string(string), _location(file) { } + int get(Span* span = 0) + { + Location start = _location; + int c = getCharacter(); + if (span != 0) + *span += Span(start, location()); + return c; + } + bool parse(int character, Span* span = 0) + { + CharacterSource s = *this; + Span span2; + if (s.get(&span2) == character) { + *this = s; + if (span != 0) + *span += span2; + return true; + } + return false; + } + void assert(int character, Span* span = 0) + { + CharacterSource s = *this; + int found = s.get(span); + if (found == character) { + *this = s; + return; + } + throwUnexpected(printable(character), printable(found)); + } + bool parseString(const String& string, Span* span = 0) + { + CharacterSource s = *this; + CharacterSource ss(string); + Span span2; + do { + int character = ss.getCharacter(); + if (character == -1) + break; + if (!s.parse(character, &span2)) + return false; + if (span != 0) + *span += span2; + } while (true); + *this = s; + return true; + } + void assertString(const String& string, Span* span = 0) + { + CharacterSource s = *this; + CharacterSource ss(string); + Span span2; + do { + int character = ss.getCharacter(); + if (character == -1) + break; + s.assert(character, &span2); + if (span != 0) + *span += span2; + } while (true); + *this = s; + } + String delimitString(const String& delimiter, bool* eof, Span* span = 0) + { + CharacterSource s = *this; + int startOffset = s.offset(); + CharacterSource ss(delimiter); + int first = ss.getCharacter(); + *eof = false; + do { + int endOffset = s.offset(); + Span span2; + int character = s.get(&span2); + if (character == -1) { + *eof = true; + return String(); + } + if (character == first) { + CharacterSource s2 = s; + CharacterSource ss2 = ss; + int delimiterCharacter; + do { + delimiterCharacter = ss2.getCharacter(); + if (delimiterCharacter == -1) { + *this = s2; + return subString(startOffset, endOffset); + } + } while (s2.getCharacter() == delimiterCharacter); + } + if (span != 0) + *span += span2; + } while (true); + } + Location location() const { return _location; } + void throwUnexpected(const String& expected, String observed = "") + { + if (observed.empty()) { + CharacterSource s = *this; + observed = printable(s.get()); + } + _location.throwError("Expected " + expected + ", found " + observed + + "."); + } + int offset() const { return _location.offset(); } + String subString(int start, int end) const + { + return _string.subString(start, end - start); + } + int length() const { return _string.length(); } + int getByte() + { + int l = _location.offset(); + if (l == _string.length()) + return -1; + int b = _string[l]; + ++_location; + return b; + } +private: + static String printable(int character) + { + if (character == -1) + return "end of file"; + if (character == 10) + return "end of line"; + if (character == '\'') + return "single quote"; + if (character >= ' ' && character <= '~') + return String("'") + codePoint(character) + "'"; + return String("code point U+") + hex(character, + character < 0x10000 ? 4 : character < 0x100000 ? 5 : 6); + } + int getCharacter() + { + int c = getCodePoint(); + if (c == 10) { + CharacterSource s = *this; + if (s.getCodePoint() == 13) + *this = s; + _location.advanceLine(); + return 10; + } + if (c == 13) { + CharacterSource s = *this; + if (s.getCodePoint() == 10) + *this = s; + _location.advanceLine(); + return 10; + } + return c; + } + int getCodePoint() + { + int b0 = getByte(); + if (b0 < 0x80) { + if (b0 >= 0) + _location.advanceColumn(); + return b0; + } + if (b0 < 0xc0 || b0 >= 0xf8) + _location.throwErrorWithOffset( + String("Expected 0x00..0x7F or 0xC0..0xF7, found ") + + printableByte(b0)); + + int b1 = getContinuationByte(); + if (b0 >= 0xc0 && b0 < 0xe0) { + int codePoint = ((b0 & 0x1f) << 6) | (b1 & 0x3f); + if (codePoint < 0x80) + _location.throwErrorWithOffset("Overlong encoding"); + _location.advanceColumn(); + return codePoint; + } + + int b2 = getContinuationByte(); + if (b0 >= 0xe0 && b0 < 0xf0) { + int codePoint = ((b0 & 0x0f) << 12) | ((b1 & 0x3f) << 6) | + (b2 & 0x3f); + if (codePoint < 0x800) + _location.throwErrorWithOffset("Overlong encoding"); + if (codePoint >= 0xd800 && codePoint < 0xe000) + _location.throwErrorWithOffset("Unexpected surrogate"); + _location.advanceColumn(); + return codePoint; + } + + int b3 = getContinuationByte(); + int codePoint = ((b0 & 0x07) << 18) | ((b1 & 0x3f) << 12) | + ((b2 & 0x3f) << 6) | (b3 & 0x3f); + if (codePoint < 0x10000) + _location.throwErrorWithOffset("Overlong encoding"); + if (codePoint >= 0x110000) + _location.throwErrorWithOffset("Code point too high"); + _location.advanceColumn(); + return codePoint; + } + String printableByte(int b) + { + return b == -1 ? String("end of string") : String(hex(b, 2)); + } + int getContinuationByte() + { + int b = getByte(); + if (b < 0x80 || b >= 0xc0) + _location.throwErrorWithOffset( + String("Expected 0x80..0xBF, found ") + printableByte(b)); + return b; + } + + String _string; + Location _location; +}; + +String enquote(String s) +{ + String r = "\""; + CharacterSource source(s); + int startOffset = source.offset(); + do { + int offset = source.offset(); + int c = source.get(); + switch (c) { + case -1: + return r + source.subString(startOffset, offset) + "\""; + case '\"': + r += source.subString(startOffset, offset) + "\\\""; + startOffset = source.offset(); + break; + case '\\': + r += source.subString(startOffset, offset) + "\\\\"; + startOffset = source.offset(); + break; + } + } while (true); +} + +#endif // INCLUDED_CHARACTER_SOURCE_H diff --git a/80386/disassembler/include/alfe/circular_buffer.h b/80386/disassembler/include/alfe/circular_buffer.h new file mode 100644 index 0000000..08ad82a --- /dev/null +++ b/80386/disassembler/include/alfe/circular_buffer.h @@ -0,0 +1,93 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_CIRCULAR_BUFFER_H +#define INCLUDED_CIRCULAR_BUFFER_H + +template class CircularBuffer +{ +public: + CircularBuffer() + : _buffer(0), _readPosition(0), _writePosition(0), _mask(1), _count(0), + _size(0) + { } + ~CircularBuffer() { if (_buffer != 0) delete[] _buffer; } + void write(const T& t) + { + add(1); + _buffer[writeOffset(0)] = t; + added(1); + } + const T& read(int n = 0) const + { + return _buffer[readOffset(n)]; + } + int readBoundary() const { return _size - _readPosition; } + int writeBoundary() const { return _size - _writePosition; } + T* readPointer() const { return _buffer + _readPosition; } + T* writePointer() const { return _buffer + _writePosition; } + T* lowPointer() const { return _buffer; } + void copyIn(T* source, int first, int n) + { + int start = writeOffset(first); + int n1 = min(n, _size - start); + memcpy(_buffer + start, source, n1*sizeof(T)); + memcpy(_buffer, source + n1, (n - n1)*sizeof(T)); + } + void copyOut(T* destination, int first, int n) + { + int start = readOffset(first); + int n1 = min(n, _size - start); + memcpy(destination, _buffer + start, n1*sizeof(T)); + memcpy(destination + n1, _buffer, (n - n1)*sizeof(T)); + } + + int count() const { return _count; } + + void add(int n) + { + // Make sure we have enough space for an additional n items + int newN = n + _count; + if (_size < newN) { + // Double the size of the buffer until it's big enough. + int newSize = _size; + if (newSize == 0) + newSize = 1; + while (newSize < newN) + newSize <<= 1; + // Since buffers never shrink, this doesn't need to be particularly + // fast. Just copy all the data to the start of the new buffer. + T* newBuffer = new T[newSize]; + if (_buffer != 0) { + copyOut(newBuffer, 0, _count); + delete[] _buffer; + } + _writePosition = _count; + _readPosition = 0; + _size = newSize; + _buffer = newBuffer; + _mask = _size - 1; + } + } + void added(int n) + { + _count += n; + _writePosition = writeOffset(n); + } + void remove(int n) + { + _count -= n; + _readPosition = readOffset(n); + } +private: + int readOffset(int delta) const { return (delta + _readPosition)&_mask; } + int writeOffset(int delta) const { return (delta + _writePosition)&_mask; } + + T* _buffer; + int _readPosition; + int _writePosition; + int _mask; + int _count; + int _size; +}; + +#endif // INCLUDED_CIRCULAR_BUFFER_H diff --git a/80386/disassembler/include/alfe/code.h b/80386/disassembler/include/alfe/code.h new file mode 100644 index 0000000..26a44c5 --- /dev/null +++ b/80386/disassembler/include/alfe/code.h @@ -0,0 +1,656 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_CODE_H +#define INCLUDED_CODE_H + +#include "alfe/expression.h" + +class CodeList; + +class Code +{ +public: + Code(const Code& other) : _body(other._body) { } + Code prev() const { return body()->_prev; } + Code next() const { return body()->_next; } + + // Unlike Handle/ConstHandle, Code equality is just pointer equality. + bool operator==(Code other) const { return body() == other.body(); } + bool operator!=(Code other) const { return body() != other.body(); } + + // Moves all the code from list to immediately before this. If this is a + // CodeList, list will be inserted at the end. + Code insert(CodeList list) const + { + Code o = list; + Body* c = o.body(); + Body* f = o.next().body(); + if (f != c) { + Body* l = o.prev().body(); + Body* n = body(); + Body* p = prev().body(); + f->_prev = p; + l->_next = n; + p->_next = f; + n->_prev = l; + c->_next = c; + c->_prev = c; + } + return *this; + } + template Code insert(Args&&... args) const + { + Body* b = new T::Body(std::forward(args)...); + Body* n = body(); + Body* p = prev().body(); + b->_next = n; + b->_prev = p; + n->_prev = b; + p->_next = b; + return *this; + } + CodeList split(Code start) const + { + Body* s = start.body(); + Body* e = body(); + Body* l = s->_prev; + Body* p = e->_prev; + CodeList r; + Code o = r; + Body* b = o.body(); + b->_next = s; + s->_prev = b; + b->_prev = p; + p->_next = b; + l->_next = e; + e->_prev = l; + return r; + } + bool walk(const std::function& function) + { + return body()->walk(function); + } + bool isSentinel() const { return as() != 0; } + bool valid() const { return _body != 0; } +protected: + class Body : Uncopyable + { + protected: + Body() : _prev(this), _next(this) { } + Code code() { return Code(this); } + virtual bool walk(const std::function& function) + { + return function(code()); + } + private: + template T* as() { return static_cast(this); } + template T* to() { return dynamic_cast(this); } + + Body* _prev; + Body* _next; + + friend class Code; + }; + Body* body() const { return _body; } + template T* as() const { return _body->as(); } + template T* to() const { return _body->to(); } + +private: + Code(Body* body) : _body(body) { } + Body* _body; + + friend class CodeList; + friend class Statement; +}; + +class CodeList : public Code +{ +public: + CodeList() : Code(new Body()) { } + ~CodeList() { reset(); } + CodeList(const CodeList& other) : Code(other) { body()->acquire(); } + Code begin() const { return next(); } + Code end() const { return *this; } +private: + class Body : public Code::Body + { + protected: + virtual ~Body() { } + private: + Body() : _count(1) { } + void release() + { + --_count; + if (_count != 0) + return; + Code e = code(); + Code c = e.next(); + while (c != e) { + Code n = c.next(); + delete c.body(); + c = n; + } + delete this; + } + bool walk(const std::function& function) + { + Code e = code(); + Code c = e.next(); + while (c != e) { + if (!c.walk(function)) + return false; + c = c.next(); + } + return true; + } + void acquire() { ++_count; } + int _count; + + friend class CodeList; + }; + Body* body() const { return as(); } + void reset() const { body()->release(); } + + friend class Code; +}; + +class Annotation +{ +public: + Annotation() : _annotation(0) { } + virtual ~Annotation() { } +private: + Annotation* _annotation; + + friend class Statement; + friend class Statement::Body; +}; + +class SpanAnnotation : public Annotation +{ +public: + SpanAnnotation(Span span) : _span(span) { } + Span span() const { return _span; } +private: + Span _span; +}; + +class Statement : public Code +{ +public: + Statement(Code code) : Code(code.to()) { } + bool walkAnnotations(const std::function& function) + const + { + return body()->walkAnnotations(function); + } + template T* annotate(Args&&... args) const + { + T* t = new T(std::forward(args)...); + Annotation* a = static_cast(t); + Annotation* o = &body()->_annotation; + a->_annotation = o->_annotation; + o->_annotation = a; + return a; + } + template T* getAnnotation() const + { + Annotation* a = body()->_annotation._annotation; + while (a != 0) { + T* t = dynamic_cast(a); + if (t != 0) + return t; + } + return 0; + } + Span span() const + { + SpanAnnotation* a = getAnnotation(); + if (a == 0) + return Span(); + return a->span(); + } +protected: + class Body : public Code::Body + { + protected: + Body(Span span) { statement().annotate(span); } + ~Body() + { + Annotation* a = _annotation._annotation; + while (a != 0) { + Annotation* n = a->_annotation; + delete a; + a = n; + } + } + Statement statement() { return Statement(this); } + private: + bool walkAnnotations(const std::function& function) + { + Annotation* a = _annotation._annotation; + while (a != 0) { + if (!function(a)) + return false; + a = a->_annotation; + } + } + Annotation _annotation; + + friend class Statement; + }; + Statement(Body* body) : Code(body) { } +private: + Body* body() const { return as(); } +}; + +class ExpressionStatement : public Statement +{ +public: + Expression expression() const { return body()->expression(); } +private: + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + Expression expression() const { return _expression; } + private: + Expression _expression; + }; + Body* body() const { return as(); } +}; + +class FunctionDefinitionStatement : public Statement +{ +public: + TycoSpecifier returnTypeSpecifier() const + { + return body()->_returnTypeSpecifier; + } + Identifier name() const { return body()->_name; } + List parameterList() const + { + return body()->_parameterList; + } +protected: + class Body : public Statement::Body + { + public: + Body(const TycoSpecifier& returnTypeSpecifier, const Identifier& name, + const List& parameterList, const Span& span) + : Statement::Body(span), + _returnTypeSpecifier(returnTypeSpecifier), _name(name), + _parameterList(parameterList) { } + private: + TycoSpecifier _returnTypeSpecifier; + Identifier _name; + List _parameterList; + + friend class FunctionDefinitionStatement; + }; +private: + Body* body() const { return as(); } +}; + +class FunctionDefinitionCodeStatement : public FunctionDefinitionStatement +{ +public: + Code code() const { return body()->_body; } +private: + class Body : public FunctionDefinitionStatement::Body + { + public: + Body(const TycoSpecifier& returnTypeSpecifier, const Identifier& name, + const List& parameterList, CodeList body, + const Span& span) + : FunctionDefinitionStatement::Body(returnTypeSpecifier, name, + parameterList, span), + _body(body) { } + bool walk(const std::function& function) + { + if (!function(code())) + return false; + return _body.walk(function); + } + private: + CodeList _body; + + friend class FunctionDefinitionCodeStatement; + }; + Body* body() const { return as(); } +}; + +class FunctionDefinitionFromStatement : public FunctionDefinitionStatement +{ +public: + Expression from() const { return body()->_from; } +private: + class Body : public FunctionDefinitionStatement::Body + { + public: + Body(const TycoSpecifier& returnTypeSpecifier, const Identifier& name, + const List& parameterList, Expression from, + const Span& span) + : FunctionDefinitionStatement::Body(returnTypeSpecifier, name, + parameterList, span), + _from(from) { } + private: + Expression _from; + + friend class FunctionDefinitionFromStatement; + }; + Body* body() const { return as(); } +}; + +// TycoDefinitionStatement := TycoSignifier "=" TycoSpecifier ";" +class TycoDefinitionStatement : public Statement +{ +public: + TycoSignifier tycoSignifier() const { return body()->_tycoSignifier; } + TycoSpecifier tycoSpecifier() const { return body()->_tycoSpecifier; } +private: + class Body : public Statement::Body + { + public: + Body(const TycoSignifier& tycoSignifier, + const TycoSpecifier& tycoSpecifier, const Span& span) + : Statement::Body(span), _tycoSignifier(tycoSignifier), + _tycoSpecifier(tycoSpecifier) { } + private: + TycoSignifier _tycoSignifier; + TycoSpecifier _tycoSpecifier; + + friend class TycoDefinitionStatement; + }; + Body* body() const { return as(); } +}; + +// ConditionalStatement = (`if` | `unless`) ConditionedStatement +// ((`elseIf` | `elseUnless`) ConditionedStatement)* [`else` Statement]; +// ConditionedStatement = "(" Expression ")" Statement; +class ConditionalStatement : public Statement +{ +public: + Expression condition() const { return body()->_condition; } + Code trueStatement() const { return body()->_trueStatement; } + Code falseStatement() const { return body()->_falseStatement; } +private: + class Body : public Statement::Body + { + public: + Body(const Expression& condition, CodeList trueStatement, + CodeList falseStatement, const Span& span) + : Statement::Body(span), _condition(condition), + _trueStatement(trueStatement), _falseStatement(falseStatement) { } + bool walk(const std::function& function) + { + if (!function(code())) + return false; + if (!_trueStatement.walk(function)) + return false; + return _falseStatement.walk(function); + } + private: + Expression _condition; + CodeList _trueStatement; + CodeList _falseStatement; + + friend class ConditionalStatement; + }; + Body* body() const { return as(); } +}; + +class SwitchStatement : public Statement +{ +public: + class Case : public ParseTreeObject + { + public: + bool isDefault() const { return body()->isDefault(); } + Code code() const { return body()->_code; } + List expressions() + { + ValueBody* v = as(); + if (v == 0) + return List(); + return v->_expressions; + } + Case() { } + Case(CodeList code, const Span& span) + : ParseTreeObject(create(code, span)) { } + Case(const List& expressions, CodeList code, + const Span& span) + : ParseTreeObject(create(expressions, code, span)) { } + + class Body : public ParseTreeObject::Body + { + public: + Body(CodeList code, const Span& span) + : ParseTreeObject::Body(span), _code(code) { } + virtual bool isDefault() const = 0; + private: + CodeList _code; + + friend class Case; + }; + private: + Case(Handle other) : ParseTreeObject(other) { } + + Body* body() { return as(); } + const Body* body() const { return as(); } + + class DefaultBody : public Body + { + public: + DefaultBody(CodeList code, const Span& span) + : Body(code, span) { } + bool isDefault() const { return true; } + }; + class ValueBody : public Body + { + public: + ValueBody(const List& expressions, + CodeList code, const Span& span) + : Body(code, span), _expressions(expressions) { } + bool isDefault() const { return false; } + private: + List _expressions; + + friend class Case; + }; + }; + + Expression expression() const { return body()->_expression; } + Case defaultCase() const { return body()->_defaultCase; } + List cases() const { return body()->_cases; } + bool walkCases(std::function& function) const + { + for (auto c : cases()) { + if (!function(c)) + return false; + } + return function(defaultCase()); + } + +private: + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Case& defaultCase, + const List& cases, const Span& span) + : Statement::Body(span), _expression(expression), + _defaultCase(defaultCase), _cases(cases) { } + private: + Expression _expression; + Case _defaultCase; + List _cases; + + friend class SwitchStatement; + }; + + Body* body() const { return as(); } +}; + +class ReturnStatement : public Statement +{ +public: + Expression expression() const { return body()->_expression; } +private: + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + private: + Expression _expression; + + friend class ReturnStatement; + }; + + Body* body() const { return as(); } +}; + +class BreakOrContinueStatement : public Statement +{ +public: + int breakCount() const { return body()->_breakCount; } + bool hasContinue() const { return body()->_hasContinue; } +private: + class Body : public Statement::Body + { + public: + Body(const Span& span, int breakCount, bool hasContinue) + : Statement::Body(span), _breakCount(breakCount), + _hasContinue(hasContinue) + { } + private: + int _breakCount; + bool _hasContinue; + + friend class BreakOrContinueStatement; + }; + + Body* body() const { return as(); } +}; + +class ForeverStatement : public Statement +{ +public: + Code code() const { return body()->_code; } +private: + class Body : public Statement::Body + { + public: + Body(CodeList code, const Span& span) + : Statement::Body(span), _code(code) { } + private: + CodeList _code; + + friend class ForeverStatement; + }; + + Body* body() const { return as(); } +}; + +class WhileStatement : public Statement +{ +public: + Code doStatement() const { return body()->_doStatement; } + Expression condition() const { return body()->_condition; } + Code statement() const { return body()->_statement; } + Code doneStatement() const { return body()->_doneStatement; } +private: + class Body : public Statement::Body + { + public: + Body(CodeList doStatement, const Expression& condition, + CodeList statement, CodeList doneStatement, + const Span& span) + : Statement::Body(span), _doStatement(doStatement), + _condition(condition), _statement(statement), + _doneStatement(doneStatement) { } + private: + CodeList _doStatement; + Expression _condition; + CodeList _statement; + CodeList _doneStatement; + + friend class WhileStatement; + }; + + Body* body() const { return as(); } +}; + +class ForStatement : public Statement +{ +public: + Code preStatement() const { return body()->_preStatement; } + Expression condition() const { return body()->_condition; } + Code postStatement() const { return body()->_postStatement; } + Code statement() const { return body()->_statement; } + Code doneStatement() const { return body()->_doneStatement; } +private: + class Body : public Statement::Body + { + public: + Body(CodeList preStatement, const Expression& condition, + CodeList postStatement, CodeList statement, + CodeList doneStatement, const Span& span) + : Statement::Body(span), _preStatement(preStatement), + _condition(condition), _postStatement(postStatement), + _statement(statement), _doneStatement(doneStatement) { } + private: + CodeList _preStatement; + Expression _condition; + CodeList _postStatement; + CodeList _statement; + CodeList _doneStatement; + + friend class ForStatement; + }; + + Body* body() const { return as(); } +}; + +class LabelStatement : public Statement +{ +public: + Identifier identifier() const { return body()->_identifier; } +private: + class Body : public Statement::Body + { + public: + Body(const Identifier& identifier, const Span& span) + : Statement::Body(span), _identifier(identifier) { } + private: + Identifier _identifier; + + friend class LabelStatement; + }; + + Body* body() const { return as(); } +}; + +class GotoStatement : public Statement +{ +public: + Expression expression() const { return body()->_expression; } +private: + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + void resolve(Scope* scope) { _expression.resolve(scope); } + private: + Expression _expression; + + friend class GotoStatement; + }; + + Body* body() const { return as(); } +}; + + +#endif // INCLUDED_CODE_H diff --git a/80386/disassembler/include/alfe/colour_space.h b/80386/disassembler/include/alfe/colour_space.h new file mode 100644 index 0000000..b38ea4f --- /dev/null +++ b/80386/disassembler/include/alfe/colour_space.h @@ -0,0 +1,425 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_COLOUR_SPACE_H +#define INCLUDED_COLOUR_SPACE_H + +#include "alfe/vectors.h" +#include + +typedef Vector3 Colour; +typedef Vector3 SRGB; + +Colour labFromXyz(Colour xyz) +{ + static const Colour xyzWhite(95.047f, 100, 108.883f); + auto helper = [=](float t) + { + static const float d = 6.0f/29.0f; + static const float d3 = d*d*d; + static const float a = 1.0f/(3.0f*d*d); + static const float b = 4.0f/29.0f; + if (t > d3) + return pow(t, 1/3.0f); + return a*t + b; + }; + Colour c = xyz/xyzWhite; + float y = helper(c.y); + return Colour(116.0f*y - 16.0f, 500.0f*(helper(c.x) - y), + 200.0f*(y - helper(c.z))); +} + +Colour luvFromXyz(Colour xyz) +{ + float x = xyz.x; + float y = xyz.y; + float z = xyz.z; + static const float d = 3.0f/29.0f; + static const float d2 = d*2.0f; + float l; + if (y <= d2*d2*d2) + l = y/(d*d*d); + else + l = 116.0f*pow(y, 1.0f/3.0f) - 16.0f; + float r = x + 15*y + 3*z; + float u; + float v; + if (r < 1.0e-5) { + u = 13.0f*l*(4.0f - 0.2105f); + v = 13.0f*l*(9.0f/15.0f - 0.4737f); + } + else { + u = 13.0f*l*(4.0f*x/r - 0.2105f); + v = 13.0f*l*(9.0f*y/r - 0.4737f); + } + return Colour(l, u, v); +} + +Colour xyzFromRgb(Colour rgb) +{ + return Colour(rgb.x*41.24f + rgb.y*35.76f + rgb.z*18.05f, + rgb.x*21.26f + rgb.y*71.52f + rgb.z*7.22f, + rgb.x*1.93f + rgb.y*11.92f + rgb.z*95.05f); +} + +Colour labFromRgb(Colour rgb) { return labFromXyz(xyzFromRgb(rgb)); } +Colour luvFromRgb(Colour rgb) { return luvFromXyz(xyzFromRgb(rgb)); } + +float deltaE2CIEDE2000(Colour rgb1, Colour rgb2) +{ + Colour lab1 = labFromRgb(rgb1); + Colour lab2 = labFromRgb(rgb2); + float c1 = sqrt(lab1.y*lab1.y + lab1.z*lab1.z); + float c2 = sqrt(lab2.y*lab2.y + lab2.z*lab2.z); + float meanC = (c1 + c2)/2.0f; + float c3 = meanC*meanC*meanC; + float c7 = c3*c3*meanC; + static const float twentyFive7 = 25.0f*25.0f*25.0f*25.0f*25.0f*25.0f*25.0f; + float d = sqrt(c7/(c7 + twentyFive7)); + float e = 1 + (1 - d)/2.0f; + float a1p = lab1.y*e; + float a2p = lab2.y*e; + float c1p = sqrt(a1p*a1p + lab1.z*lab1.z); + float c2p = sqrt(a2p*a2p + lab2.z*lab2.z); + float meanCp = (c1p + c2p)/2.0f; + static const float tauf = static_cast(tau); + static const float degrees = 360.0f/tauf; + static const float pi = tauf/2; + float meanHp = (atan2(-lab1.z - lab2.z, -a1p - a2p) + pi); + float deltaHp = 2*sqrt(c1p*c2p)* + sin(atan2(lab2.z*a1p - a2p*lab1.z, a2p*a1p + lab2.z*lab1.z)/2); + static const float p1 = -30/degrees; + static const float p3 = 6/degrees; + static const float p4 = -63/degrees; + float t = 1 - 0.17f*cos(meanHp + p1) + 0.24f*cos(2*meanHp) + + 0.32f*cos(3*meanHp + p3) - 0.20f*cos(4*meanHp + p4); + float meanL = (lab1.x + lab2.x)/2 - 50; + float meanL2 = meanL*meanL; + float sL = 1 + 0.015f*meanL2/sqrt(20 + meanL2); + float f = (meanHp*degrees - 275)/25; + static const float g = 60/degrees; + float deltaL = lab2.x - lab1.x; + float deltaCp = c2p - c1p; + float l = deltaL/sL; + float sC = 1 + 0.045f*meanCp; + float c = deltaCp/sC; + float sH = 1 + 0.015f*meanCp*t; + float h = deltaHp/sH; + return l*l + c*c + h*h + -2*d*sin(g*exp(-f*f))*deltaCp*deltaHp/(sC*sH); +} + +float deltaE2Luv(Colour rgb1, Colour rgb2) +{ + return (luvFromRgb(rgb1) - luvFromRgb(rgb2)).modulus2(); +} + +float deltaE2CIE76(Colour rgb1, Colour rgb2) +{ + return (labFromRgb(rgb1) - labFromRgb(rgb2)).modulus2(); +} + +float deltaE2CIE94(Colour rgb1, Colour rgb2) +{ + Colour lab1 = labFromRgb(rgb1); + Colour lab2 = labFromRgb(rgb2); + float deltaL = lab1.x - lab2.x; + float c1 = sqrt(lab1.y*lab1.y + lab1.z*lab1.z); + float deltaC = c1 - sqrt(lab2.y*lab2.y + lab2.z*lab2.z); + float deltaa = lab1.y - lab2.y; + float deltab = lab1.z - lab2.z; + float c = deltaC/(1 + 0.045f*c1); + float sH = 1 + 0.015f*c1; + return deltaL*deltaL + c*c + + (deltaa*deltaa + deltab*deltab - deltaC*deltaC)/(sH*sH); +} + +class ColourSpaceBody +{ +public: + virtual Colour fromSrgb(const Colour& srgb) = 0; + virtual Colour toSrgb(const Colour& colour) = 0; + virtual Colour fromRgb(const Colour& rgb) = 0; + virtual Colour toRgb(const Colour& colour) = 0; +}; + +template class ColourSpaceT; +typedef ColourSpaceT ColourSpace; + +// CIELUV L*u*v* conversions from +// http://en.wikipedia.org/wiki/CIELUV_color_space +template class LUVColourSpaceBodyT : public ColourSpaceBody +{ +public: + Colour fromSrgb(const Colour& srgb) + { + return fromRgb(ColourSpace::rgb().fromSrgb(srgb)); + } + Colour toSrgb(const Colour& luv) + { + return ColourSpace::rgb().toSrgb(toRgb(luv)); + } + Colour fromRgb(const Colour& rgb) { return luvFromRgb(rgb); } + Colour toRgb(const Colour& luv) + { + float l = luv.x; + float u = luv.y; + float v = luv.z; + float uu = u/(13.0f*l) + 0.2105f; + float vv = v/(13.0f*l) + 0.4737f; + float y; + static const float d = 3.0f/29.0f; + if (l <= 8.0f) + y = l*d*d*d; + else { + y = (l + 16.0f)/116.0f; + y = y*y*y; + } + if (vv < 1.0e-5) + return SRGB(0, 0, 0); + float x = y*(9.0f*uu)/(4.0f*vv); + float z = y*(12.0f - 3.0f*uu - 20.0f*vv)/(4.0f*vv); + return ColourSpace::xyz().toRgb(Colour(x, y, z)); + } +private: + LUVColourSpaceBodyT() { } + friend class ColourSpaceT; +}; + +typedef LUVColourSpaceBodyT LUVColourSpaceBody; + +// CIELAB L*a*b* conversions from http://en.wikipedia.org/wiki/Lab_color_space +template class LABColourSpaceBodyT : public ColourSpaceBody +{ +public: + Colour fromSrgb(const Colour& srgb) + { + return fromRgb(ColourSpace::rgb().fromSrgb(srgb)); + } + Colour toSrgb(const Colour& lab) + { + return ColourSpace::rgb().toSrgb(toRgb(lab)); + } + Colour fromRgb(const Colour& rgb) { return labFromRgb(rgb); } + Colour toRgb(const Colour& lab) + { + float y = (lab.x + 16.0f)/116.0f; + return ColourSpace::xyz().toRgb(Colour( + xyzFromLabHelper(y + lab.y/500.0f), + xyzFromLabHelper(y), + xyzFromLabHelper(y - lab.z/200.0f))); + } +private: + float xyzFromLabHelper(float t) + { + static const float d = 6.0f/29.0f; + return t > d ? pow(t, 3.0f) : (t - 4.0f/29.0f)*3.0f*d*d; + } + + LABColourSpaceBodyT() { } + friend class ColourSpaceT; +}; + +typedef LABColourSpaceBodyT LABColourSpaceBody; + +template class SRGBColourSpaceBodyT : public ColourSpaceBody +{ +public: + Colour fromSrgb(const Colour& srgb) { return srgb; } + Colour toSrgb(const Colour& srgb) { return srgb; } + Colour fromRgb(const Colour& rgb) + { + return ColourSpace::rgb().toSrgb(rgb); + } + Colour toRgb(const Colour& srgb) + { + return ColourSpace::rgb().fromSrgb(srgb); + } +private: + SRGBColourSpaceBodyT() { } + friend class ColourSpaceT; +}; + +typedef SRGBColourSpaceBodyT SRGBColourSpaceBody; + +// sRGB conversions from http://en.wikipedia.org/wiki/SRGB +class RGBColourSpaceBody : public ColourSpaceBody +{ +public: + Colour fromSrgb(const Colour& srgb) + { + return Colour( + rgbFromSrgbHelper(srgb.x), + rgbFromSrgbHelper(srgb.y), + rgbFromSrgbHelper(srgb.z)); + } + Colour toSrgb(const Colour& rgb) + { + return Colour( + srgbFromRgbHelper(rgb.x), + srgbFromRgbHelper(rgb.y), + srgbFromRgbHelper(rgb.z)); + } + Colour fromRgb(const Colour& rgb) { return rgb; } + Colour toRgb(const Colour& rgb) { return rgb; } +private: + static float srgbFromRgbHelper(float t) + { + return 256.0f*(t <= 0.0031308f ? 12.92f*t : + (1.0f + 0.055f)*pow(t, 1.0f/2.4f) - 0.055f); + } + static float rgbFromSrgbHelper(float t) + { + t /= 256.0f; + return t <= 0.04045f ? t/12.92f : pow((t + 0.055f)/(1 + 0.055f), 2.4f); + } + + friend class ColourSpaceT; +}; + +template class XYZColourSpaceBodyT : public ColourSpaceBody +{ +public: + Colour fromSrgb(const Colour& srgb) + { + return fromRgb(ColourSpace::rgb().fromSrgb(srgb)); + } + Colour toSrgb(const Colour& xyz) + { + return ColourSpace::rgb().toSrgb(toRgb(xyz)); + } + Colour fromRgb(const Colour& rgb) + { + return Colour( + 0.4124f*rgb.x + 0.3576f*rgb.y + 0.1805f*rgb.z, + 0.2126f*rgb.x + 0.7152f*rgb.y + 0.0722f*rgb.z, + 0.0193f*rgb.x + 0.1192f*rgb.y + 0.9505f*rgb.z); + } + Colour toRgb(const Colour& xyz) + { + return Colour( + 3.2406f*xyz.x - 1.5372f*xyz.y - 0.4986f*xyz.z, + -0.9689f*xyz.x + 1.8758f*xyz.y + 0.0415f*xyz.z, + 0.0557f*xyz.x - 0.2040f*xyz.y + 1.0570f*xyz.z); + } +private: + XYZColourSpaceBodyT() { } + friend class ColourSpaceT; +}; + +typedef XYZColourSpaceBodyT XYZColourSpaceBody; + +template class ColourSpaceT : public ConstHandle +{ +public: + ColourSpaceT() { } + static ColourSpace luv() { return ColourSpace(&_luv); } + static ColourSpace lab() { return ColourSpace(&_lab); } + static ColourSpace srgb() { return ColourSpace(&_srgb); } + static ColourSpace rgb() { return ColourSpace(&_rgb); } + static ColourSpace xyz() { return ColourSpace(&_xyz); } + Colour fromSrgb(const Colour& srgb) + { + return _body->fromSrgb(srgb); + } + Colour toSrgb(const Colour& colour) + { + return _body->toSrgb(colour); + } + Colour fromRgb(const Colour& rgb) + { + return _body->fromRgb(rgb); + } + Colour toRgb(const Colour& colour) + { + return _body->toRgb(colour); + } + SRGB toSrgb24(const Colour& colour) + { + Colour c = _body->toSrgb(colour); + return SRGB(byteClamp(c.x), byteClamp(c.y), byteClamp(c.z)); + } +private: + ColourSpaceT(ColourSpaceBody* body) : _body(body) { } + ColourSpaceBody* _body; + static LUVColourSpaceBody _luv; + static LABColourSpaceBody _lab; + static SRGBColourSpaceBody _srgb; + static RGBColourSpaceBody _rgb; + static XYZColourSpaceBody _xyz; +}; + +LUVColourSpaceBody ColourSpace::_luv; +LABColourSpaceBody ColourSpace::_lab; +SRGBColourSpaceBody ColourSpace::_srgb; +RGBColourSpaceBody ColourSpace::_rgb; +XYZColourSpaceBody ColourSpace::_xyz; + +class Linearizer +{ +public: + Linearizer() : _gamma(0), _showClipping(false) { init(); } + void setShowClipping(bool showClipping) + { + _showClipping = showClipping; + init(); + } + void setGamma(float gamma) { _gamma = gamma; init(); } + Colour linear(SRGB srgb) const + { + return Colour(linear(srgb.x), linear(srgb.y), linear(srgb.z)); + } + SRGB srgb(Colour linear) const + { + return SRGB(srgb(linear.x), srgb(linear.y), srgb(linear.z)); + } + float linear(Byte srgb) const { return _linear[srgb]; } + Byte srgb(float linear) const + { + return _srgb[clamp(0, static_cast(linear*_multiplier), 6589)]; + } +private: + void init() + { + if (_gamma == 0) { + for (int i = 1; i < 255; ++i) { + float t = i/255.0f; + if (t <= 0.04045f) + _linear[i] = t/12.92f; + else + _linear[i] = pow((t + 0.055f)/(1 + 0.055f), 2.4f); + } + for (int i = 0; i < 6590; ++i) { + float l = i/_multiplier; + float s; + if (l <= 0.0031308) + s = 12.92f*l; + else + s = 1.055f*pow(l, 1/2.4f) - 0.055f; + _srgb[i] = byteClamp(0.5f + 255.0f*s); + } + } + else { + for (int i = 1; i < 255; ++i) + _linear[i] = pow(i/255.0f, _gamma); + for (int i = 0; i < 6590; ++i) { + _srgb[i] = byteClamp(0.5f + + 255.0f*pow(i/_multiplier, 1/_gamma)); + } + } + if (_showClipping) { + _linear[0] = 1.0f; + _linear[255] = 0.0f; + } + else { + _linear[0] = 0.0f; + _linear[255] = 1.0f; + } + } + + float _linear[256]; + Byte _srgb[6590]; + float _gamma; + bool _showClipping; + constexpr static const float _multiplier = 2*255.0f*12.92f; +}; + +#endif // INCLUDED_COLOUR_SPACE_H diff --git a/80386/disassembler/include/alfe/com.h b/80386/disassembler/include/alfe/com.h new file mode 100644 index 0000000..41a288f --- /dev/null +++ b/80386/disassembler/include/alfe/com.h @@ -0,0 +1,105 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_COM_H +#define INCLUDED_COM_H + +#include +#include +#include "alfe/assert.h" + + +#define IF_ERROR_THROW(expr) CODE_MACRO( \ + HRESULT hrMacro = (expr); \ + IF_TRUE_THROW(FAILED(hrMacro), exceptionFromHResult(hrMacro)); \ +) + +class Bstr : Uncopyable +{ +public: + Bstr() : m_bstr(NULL) { } + ~Bstr() { SysFreeString(m_bstr); } + operator String() const { return String(m_bstr); } + BSTR* operator&() + { + assert(m_bstr == NULL, L"Re-initializing Bstr"); + return &m_bstr; + } +private: + BSTR m_bstr; +}; + + +template class COMPointer +{ +public: + COMPointer() : _p(0) { } + COMPointer(const COMPointer& spT) : _p(spT._p) { _p->AddRef(); } + COMPointer(T* pT) : _p(pT) { if (valid()) _p->AddRef(); } + const COMPointer& operator=(const COMPointer& spT) + { + reset(); + _p = spT._p; + if (valid()) + _p->AddRef(); + return *this; + } + template COMPointer(const COMPointer& spU, + const IID* piid = &__uuidof(T)) + { + IF_FALSE_THROW(spU.valid()); + IF_ERROR_THROW( + spU->QueryInterface(*piid, reinterpret_cast(&_p))); + } + ~COMPointer() { reset(); } + T** operator&() + { + if (valid()) + assert(false, L"Re-initializing COMPointer"); + return &_p; + } + T* operator->() const + { + if (!valid()) + assert(false, L"Using uninitialized COMPointer"); + return _p; + } + bool valid() const { return _p != 0; } + void reset() + { + if (valid()) + _p->Release(); + _p = 0; + } + operator T*() { return _p; } + operator const T*() const { return _p; } +private: + T* _p; +}; + + +Exception exceptionFromHResult(HRESULT hresult) +{ + COMPointer spIEI; + if (GetErrorInfo(0, &spIEI) == S_OK) { + Bstr bstrDescription; + spIEI->GetDescription(&bstrDescription); + return Exception(bstrDescription); + } + else + return Exception::fromErrorCode(hresult); +} + + +class COMInitializer : Uncopyable +{ +public: + COMInitializer(DWORD dwCoInit = COINIT_MULTITHREADED) + { + HRESULT hr = CoInitializeEx(NULL, dwCoInit); + if (FAILED(hr)) + throw Exception::systemError(String("COM initialization failed")); + } + ~COMInitializer() { CoUninitialize(); } +}; + +#endif // INCLUDED_COM_H diff --git a/80386/disassembler/include/alfe/complex.h b/80386/disassembler/include/alfe/complex.h new file mode 100644 index 0000000..b121d27 --- /dev/null +++ b/80386/disassembler/include/alfe/complex.h @@ -0,0 +1,158 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_COMPLEX_H +#define INCLUDED_COMPLEX_H + +#include "alfe/vectors.h" +#include + +template class Complex +{ +public: + Complex(Real re, Real im) : x(re), y(im) { } + Complex(Real re) : x(re), y(0) { } + Complex() { } + Complex(const Complex& other) : x(other.x), y(other.y) { } + explicit Complex(const Vector2& vector) : x(vector.x), y(vector.y) { } + Real modulus() const { return sqrt(modulus2()); } + Real modulus2() const { return x*x + y*y; } + Real argument() const { return atan2(y, x); } + Complex unit() const { return *this/modulus(); } + Complex conjugate() const { return Complex(x, -y); } + const Complex& operator+=(const Complex& other) { x += other.x; y += other.y; return *this; } + const Complex& operator-=(const Complex& other) { x -= other.x; y -= other.y; return *this; } + const Complex& operator*=(const Complex& other) + { + Real xx = x*other.x; + Real yy = y*other.y; + y = (x+y)*(other.x+other.y)-xx-yy; + x = xx-yy; + return *this; + } + const Complex& operator/=(const Complex& other) + { + Real q = other.modulus2(); + *this *= other.conjugate(); + *this /= q; + return *this; + } + const Complex& operator+=(const Real& other) { x += other; return *this; } + const Complex& operator-=(const Real& other) { x -= other; return *this; } + const Complex& operator*=(const Real& other) { x *= other; y *= other; return *this; } + const Complex& operator/=(const Real& other) { x /= other; y /= other; return *this; } + Complex operator+(const Complex& other) const { Complex t(*this); t += other; return t; } + Complex operator-(const Complex& other) const { Complex t(*this); t -= other; return t; } + Complex operator*(const Complex& other) const { Complex t(*this); t *= other; return t; } + Complex operator/(const Complex& other) const { Complex t(*this); t /= other; return t; } + Complex operator+(const Real& other) const { Complex t(*this); t += other; return t; } + Complex operator-(const Real& other) const { Complex t(*this); t -= other; return t; } + Complex operator*(const Real& other) const { Complex t(*this); t *= other; return t; } + Complex operator/(const Real& other) const { Complex t(*this); t /= other; return t; } + Complex operator-() const { return Complex(-x, -y); } + const Complex& operator=(const Real& re) { x = re; y = 0; return *this; } + const Complex& operator=(const Complex& other) { x = other.x; y = other.y; return *this; } + + bool operator==(const Complex& other) { return x==other.x && y==other.y; } + + Real x, y; +}; + +template class ComplexCast : public Complex +{ +public: + template ComplexCast(const Complex& other) + : Complex(static_cast(other.x), static_cast(other.y)) + { } + template ComplexCast(const R2& x, const R2& y) + : Complex(static_cast(x), static_cast(y)) { } +}; + +template Complex operator*(const Real& x, const Complex& c) { return c*x; } +template Complex operator/(const Real& x, const Complex& c) { return Complex(x)/c; } +template Complex operator-(const Real& x, const Complex& c) { return Complex(x)-c; } +template Complex operator+(const Real& x, const Complex& c) { return c+x; } + +template Complex exp(const Complex& z) +{ + Real magnitude = exp(z.x); + return Complex(magnitude*cos(z.y), magnitude*sin(z.y)); +} + +// unit(t) = e^(2*pi*i*t) +template Complex unit(const Real& t) +{ + Real a = static_cast(tau)*t; + return Complex(cos(a), sin(a)); +} + +template Complex log(const Complex& z) +{ + return Complex(log(z.modulus()), z.argument()); +} + +template Complex log(const Complex& z, Real theta) +{ + Real n = floor(((theta - z.argument())/static_cast(M_PI)+1)/2); + return Complex(log(z.modulus()), z.argument() + 2*static_cast(M_PI)*n); +} + +template Complex sqrt(const Complex& z) +{ + Real r = z.modulus(); + Real x = z.x; + if (z.y > 0) + return Complex(sqrt((r+x)/2), sqrt((r-x)/2)); + return Complex(sqrt((r+x)/2), -sqrt((r-x)/2)); +} + +template Complex pow(const Complex& a,const Complex& b) +{ + return exp(b*log(a)); +} + +template Complex pow(const Complex& a,const Complex& b, Real theta) +{ + return exp(b*log(a, theta)); +} + +template Complex sin(const Complex& z) +{ + return Complex(sin(z.x)*cosh(z.y), cos(z.x)*sinh(z.y)); +} + +template Complex cos(const Complex& z) +{ + return Complex(cos(z.x)*cosh(z.y), -sin(z.x)*sinh(z.y)); +} + +template Complex tan(const Complex& z) +{ + return sin(z)/cos(z); +} + +template Complex atan(const Complex& z) +{ + return Complex(0, -1)*(log(Complex(1+z.y, z.x))-log(Complex(1-z.y, z.x)))/2; +} + +template Complex sinh(const Complex& z) +{ + return Complex(sinh(z.x)*cos(z.y), cosh(z.x)*sin(z.y)); +} + +template Complex cosh(const Complex& z) +{ + return Complex(cosh(z.x)*cos(z.y), sinh(z.x)*sin(z.y)); +} + +template Complex tanh(const Complex& z) +{ + return sinh(z)/cosh(z); +} + +template Complex atanh(const Complex& z) +{ + return log(1+z)-log(1-z)/2; +} + +#endif // INCLUDED_COMPLEX_H diff --git a/80386/disassembler/include/alfe/concrete.h b/80386/disassembler/include/alfe/concrete.h new file mode 100644 index 0000000..812aefe --- /dev/null +++ b/80386/disassembler/include/alfe/concrete.h @@ -0,0 +1,316 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_CONCRETE_H +#define INCLUDED_CONCRETE_H + +#include "alfe/rational.h" +#include "alfe/type.h" + +class UnitMismatchException : public Exception +{ +public: + UnitMismatchException() : Exception("Unit mismatch") { } +}; + +template class ConcreteTypeTemplate; +typedef ConcreteTypeTemplate ConcreteType; + +template class ConcreteTemplate +{ +public: + ConcreteTemplate() : _type(ConcreteTypeTemplate()), _value(1) { } + static ConcreteTemplate zero() + { + return ConcreteTemplate(ConcreteTypeTemplate::zero(), 0); + } + + const ConcreteTemplate& operator+=(const ConcreteTemplate& other) + { + check(other); + _value += other._value; + return *this; + } + const ConcreteTemplate& operator-=(const ConcreteTemplate& other) + { + check(other); + _value -= other._value; + return *this; + } + ConcreteTemplate operator+(const ConcreteTemplate& other) + { + check(other); + if (_value == 0) + return other; + return ConcreteTemplate(_type, _value + other._value); + } + ConcreteTemplate operator-(const ConcreteTemplate& other) + { + check(other); + if (_value == 0) + return ConcreteTemplate(other._type, -other._value); + return ConcreteTemplate(_type, _value - other._value); + } + ConcreteTemplate operator*(const ConcreteTemplate& other) + { + return ConcreteTemplate(_type + other._type, _value * other._value); + } + ConcreteTemplate operator/(const ConcreteTemplate& other) + { + return ConcreteTemplate(_type - other._type, _value / other._value); + } + const ConcreteTemplate& operator*=(const ConcreteTemplate& other) + { + _type += other._type; + _value *= other._value; + return *this; + } + const ConcreteTemplate& operator/=(const ConcreteTemplate& other) + { + _type -= other._type; + _value /= other._value; + return *this; + } + template const ConcreteTemplate& operator*=(const U& other) + { + _value *= other; + return *this; + } + template const ConcreteTemplate& operator/=(const U& other) + { + _value /= other; + return *this; + } + template ConcreteTemplate operator*(const U& other) const + { + return ConcreteTemplate(_type, _value * other); + } + template ConcreteTemplate operator/(const U& other) const + { + return ConcreteTemplate(_type, _value / other); + } + Rational value() const + { + if (!isAbstract()) + throw UnitMismatchException(); + return _value; + } + bool operator<(const ConcreteTemplate& other) const + { + check(other); + return _value < other._value; + } + bool operator>(const ConcreteTemplate& other) const + { + return other < *this; + } + bool operator<=(const ConcreteTemplate& other) const + { + return !(other > *this); + } + bool operator>=(const ConcreteTemplate& other) const + { + return !(other < *this); + } + bool operator==(const ConcreteTemplate& other) const + { + if (!commensurable(other)) + return false; + return _value == other._value; + } + bool operator!=(const ConcreteTemplate& other) const + { + return !(other == *this); + } + bool commensurable(const ConcreteTemplate& other) const + { + return _value == 0 || other._value == 0 || _type == other._type; + } + bool isAbstract() const { return _type.isAbstract() || _value == 0; } + ConcreteTemplate reciprocal() const + { + return ConcreteTemplate(-_type, 1 / _value); + } + ConcreteTypeTemplate type() const { return _type; } + +private: + ConcreteTemplate(const ConcreteTypeTemplate& type, const T& value) + : _type(type), _value(value) { } + + void check(const ConcreteTemplate& other) const + { + if (!commensurable(other)) + throw UnitMismatchException(); + } + friend class ConcreteTypeTemplate; + + ConcreteTypeTemplate _type; + T _value; +}; + +template ConcreteTemplate operator*(const T& x, + const ConcreteTemplate& y) +{ + return y*x; +} + +template ConcreteTemplate operator/(const T& x, + const ConcreteTemplate& y) +{ + return x*y.reciprocal(); +} + +typedef ConcreteTemplate Concrete; + +class ConcreteTyco : public NamedNullary +{ +public: + ConcreteTyco() { } + static String name() { return "Concrete"; } +protected: + class Body : public NamedNullary::Body + { + public: + Kind kind() const { assert(false); return Kind(); } + }; + friend class Nullary; +}; + +// ConcreteType is a bit strange. It's really a family of types, but these +// types cannot be instantiated via the usual template syntax. The normal +// constructor takes no arguments, but constructs a different dimension each +// time, so care must be taken to keep track of instantiations and use the +// correct one. +template class ConcreteTypeTemplate : public Type +{ + class BaseBody : public Type::Body + { + typedef Array::Body Body; + public: + String toString() const { return "Concrete"; } + bool equals(const ConstHandle::Body* other) const + { + auto b = other->to(); + if (b == 0) + return false; + for (int i = 0; i < max(elements(), b->elements()); ++i) + if ((*body())[i] != (*b)[i]) + return false; + return true; + } + Hash hash() const + { + Hash h = Type::Body::hash(); + int i; + for (i = elements() - 1; i >= 0; --i) + if ((*body())[i] != 0) + break; + for (; i >= 0; --i) + h.mixin((*body())[i]); + return h; + } + bool isAbstract() const + { + for (int i = 0; i < elements(); ++i) + if ((*body())[i] != 0) + return false; + return true; + } + bool canConvertTo(const Type& to, String* reason) const + { + ConcreteTypeTemplate c(to); + if (c.valid()) { + *reason = String("Types are not commensurate"); + return false; + } + if (!isAbstract()) { + *reason = String("Type is denominate"); + return false; + } + return RationalType().canConvertTo(to); + } + Value convertTo(const Type& to, const Value& value) const + { + return RationalType().convertTo(to, Value(RationalType(), + value.value>().value(), value.span())); + } + int elements() const { return body()->size(); } + Value defaultValue() const { return Concrete::zero(); } + Value simplify(const Value& value) const + { + auto v = value.value>(); + if (v.isAbstract()) + return Value(RationalType(), v.value(), value.span()); + return value; + } + void deserialize(const Value& value, void* p) const + { + *static_cast(p) = value.value()._value; + } + private: + Body* body() { return as(); } + const Body* body() const { return as(); } + }; + typedef Array::Body Body; + + static int _bases; +public: + ConcreteTypeTemplate() + : Type(Array::create(_bases + 1, _bases + 1)) + { + for (int i = 0; i < elements(); ++i) + element(i) = 0; + element(elements() - 1) = 1; + ++_bases; + } + ConcreteTypeTemplate(const Type& other) : Type(to(other)) { } + static ConcreteTypeTemplate zero() + { + return ConcreteTypeTemplate(0); + } + bool isAbstract() const { return body()->isAbstract(); } + const ConcreteTypeTemplate& operator+=(const ConcreteTypeTemplate& other) + { + *this = *this + other; + return *this; + } + const ConcreteTypeTemplate& operator-=(const ConcreteTypeTemplate& other) + { + *this = *this - other; + return *this; + } + ConcreteTypeTemplate operator-() const + { + ConcreteTypeTemplate t(elements()); + for (int i = 0; i < elements(); ++i) + t.element(i) = -element(i); + return t; + } + ConcreteTypeTemplate operator+(const ConcreteTypeTemplate& other) const + { + ConcreteTypeTemplate t(max(elements(), other.elements())); + for (int i = 0; i < t.elements(); ++i) + t.element(i) = element(i) + other.element(i); + return t; + } + ConcreteTypeTemplate operator-(const ConcreteTypeTemplate& other) const + { + ConcreteTypeTemplate t(max(elements(), other.elements())); + for (int i = 0; i < t.elements(); ++i) + t.element(i) = element(i) - other.element(i); + return t; + } +private: + const Body* body() const { return as(); } + Body* body() { return const_cast(as()); } + ConcreteTypeTemplate(int bases) + : Type(Array::create(bases, bases)) { } + int elements() const { return body()->elements(); } + int& element(int i) { return (*body())[i]; } + int element(int i) const { return i >= elements() ? 0 : (*body())[i]; } +}; + +template<> int ConcreteTypeTemplate::_bases = 0; + +template<> Type typeFromValue(const Concrete& c) { return c.type(); } + +#endif // INCLUDED_CONCRETE_H diff --git a/80386/disassembler/include/alfe/concrete_functions.h b/80386/disassembler/include/alfe/concrete_functions.h new file mode 100644 index 0000000..aca6901 --- /dev/null +++ b/80386/disassembler/include/alfe/concrete_functions.h @@ -0,0 +1,367 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_CONCRETE_FUNCTIONS_H +#define INCLUDED_CONCRETE_FUNCTIONS_H + +#include "alfe/function.h" +#include "alfe/concrete.h" + +class AddConcreteConcrete : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Concrete l = i->value(); + ++i; + return Value(l + i->value()); + } + Identifier identifier() const { return OperatorPlus(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + ConcreteType l(*i); + if (!l.valid()) + return false; + ++i; + return ConcreteType(*i).valid(); + } + List parameterTycos() const + { + List r; + r.add(ConcreteTyco()); + r.add(ConcreteTyco()); + return r; + } + }; +}; + +class SubtractConcreteConcrete + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Concrete l = i->value(); + ++i; + return Value(l - i->value()); + } + Identifier identifier() const { return OperatorMinus(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + ConcreteType l(*i); + if (!l.valid()) + return false; + ++i; + return ConcreteType(*i).valid(); + } + List parameterTycos() const + { + List r; + r.add(ConcreteTyco()); + r.add(ConcreteTyco()); + return r; + } + }; +}; + +class MultiplyConcreteConcrete + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Concrete l = i->value(); + ++i; + return Value(l * i->value()); + } + Identifier identifier() const { return OperatorStar(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + ConcreteType l(*i); + if (!l.valid()) + return false; + ++i; + return ConcreteType(*i).valid(); + } + List parameterTycos() const + { + List r; + r.add(ConcreteTyco()); + r.add(ConcreteTyco()); + return r; + } + }; +}; + +class MultiplyConcreteRational + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Concrete l = i->value(); + ++i; + return l * i->convertTo(RationalType()).value(); + } + Identifier identifier() const { return OperatorStar(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + ConcreteType l(*i); + if (!l.valid()) + return false; + ++i; + return i->canConvertTo(RationalType()); + } + List parameterTycos() const + { + List r; + r.add(ConcreteTyco()); + r.add(RationalType()); + return r; + } + }; +}; + +class MultiplyRationalConcrete + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + auto l = i->convertTo(RationalType()).value(); + ++i; + return Value(l * i->value()); + } + Identifier identifier() const { return OperatorStar(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + if (!i->canConvertTo(RationalType())) + return false; + ++i; + return ConcreteType(*i).valid(); + } + List parameterTycos() const + { + List r; + r.add(RationalType()); + r.add(ConcreteTyco()); + return r; + } + }; +}; + +class DivideConcreteConcrete : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Concrete l = i->value(); + ++i; + return Value(l / i->value()); + } + Identifier identifier() const { return OperatorDivide(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + ConcreteType l(*i); + if (!l.valid()) + return false; + ++i; + return ConcreteType(*i).valid(); + } + List parameterTycos() const + { + List r; + r.add(ConcreteTyco()); + r.add(ConcreteTyco()); + return r; + } + }; +}; + +class DivideConcreteRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Concrete l = i->value(); + ++i; + return l / i->convertTo(RationalType()).value(); + } + Identifier identifier() const { return OperatorDivide(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + ConcreteType l(*i); + if (!l.valid()) + return false; + ++i; + return i->canConvertTo(RationalType()); + } + List parameterTycos() const + { + List r; + r.add(ConcreteTyco()); + r.add(RationalType()); + return r; + } + }; +}; + +class DivideRationalConcrete : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + auto l = i->convertTo(RationalType()).value(); + ++i; + return Value(l / i->value()); + } + Identifier identifier() const { return OperatorDivide(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + if (!i->canConvertTo(RationalType())) + return false; + ++i; + return ConcreteType(*i).valid(); + } + List parameterTycos() const + { + List r; + r.add(RationalType()); + r.add(ConcreteTyco()); + return r; + } + }; +}; + +class ShiftLeftConcreteInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + auto l = i->value(); + ++i; + int r = i->value(); + if (r < 0) + return l*Rational(1, 1 << -r); + return l*Rational(1 << r, 1); + } + Identifier identifier() const { return OperatorShiftLeft(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + if (!ConcreteType(*i).valid()) + return false; + ++i; + return *i == IntegerType(); + } + List parameterTycos() const + { + List r; + r.add(ConcreteTyco()); + r.add(IntegerType()); + return r; + } + }; +}; + +class ShiftRightConcreteInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + auto l = i->value(); + ++i; + int r = i->value(); + if (r < 0) + return l*Rational(1 << -r, 1); + return l*Rational(1, 1 << r); + } + Identifier identifier() const { return OperatorShiftRight(); } + bool argumentsMatch(List argumentTypes) const + { + if (argumentTypes.count() != 2) + return false; + auto i = argumentTypes.begin(); + if (!ConcreteType(*i).valid()) + return false; + ++i; + return *i == IntegerType(); + } + List parameterTycos() const + { + List r; + r.add(ConcreteTyco()); + r.add(IntegerType()); + return r; + } + }; +}; + +#endif // INCLUDED_CONCRETE_FUNCTIONS_H diff --git a/80386/disassembler/include/alfe/config_file.h b/80386/disassembler/include/alfe/config_file.h new file mode 100644 index 0000000..adca24b --- /dev/null +++ b/80386/disassembler/include/alfe/config_file.h @@ -0,0 +1,307 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_CONFIG_FILE_H +#define INCLUDED_CONFIG_FILE_H + +#include "alfe/hash_table.h" +#include "alfe/space.h" +#include "alfe/any.h" +#include "alfe/type.h" +#include "alfe/set.h" +#include "alfe/expression.h" +#include "alfe/function.h" +#include "alfe/integer_functions.h" +#include "alfe/string_functions.h" +#include "alfe/rational_functions.h" +#include "alfe/concrete_functions.h" +#include "alfe/array_functions.h" +#include "alfe/boolean_functions.h" +#include "alfe/double_functions.h" + +template class ConfigFileT; +typedef ConfigFileT ConfigFile; + +template class ConfigOptionT +{ +public: + T get() { return _config->template get(_member); } +private: + ConfigOptionT(ConfigFile* config, String member) + : _config(config), _member(member) { } + ConfigFileT* _config; + String _member; + + friend class ConfigFileT; +}; + +template using ConfigOption = ConfigOptionT; + +template class ConfigFileT : public Structure +{ +public: + ConfigFileT() + { + addType(IntegerType()); + addType(BooleanType()); + addFunco(AddIntegerInteger()); + addFunco(SubtractIntegerInteger()); + addFunco(MultiplyIntegerInteger()); + addFunco(AddStringString()); + addFunco(MultiplyIntegerString()); + addFunco(MultiplyStringInteger()); + addFunco(AddRationalRational()); + addFunco(AddRationalInteger()); + addFunco(AddIntegerRational()); + addFunco(SubtractRationalRational()); + addFunco(SubtractRationalInteger()); + addFunco(SubtractIntegerRational()); + addFunco(MultiplyRationalRational()); + addFunco(MultiplyRationalInteger()); + addFunco(MultiplyIntegerRational()); + addFunco(DivideRationalRational()); + addFunco(DivideRationalInteger()); + addFunco(DivideIntegerRational()); + addFunco(DivideIntegerInteger()); + addFunco(AddConcreteConcrete()); + addFunco(SubtractConcreteConcrete()); + addFunco(MultiplyConcreteConcrete()); + addFunco(MultiplyConcreteRational()); + addFunco(MultiplyRationalConcrete()); + addFunco(DivideConcreteConcrete()); + addFunco(DivideConcreteRational()); + addFunco(DivideRationalConcrete()); + addFunco(ShiftLeftIntegerInteger()); + addFunco(ShiftRightIntegerInteger()); + addFunco(ShiftLeftRationalInteger()); + addFunco(ShiftRightRationalInteger()); + addFunco(ShiftLeftConcreteInteger()); + addFunco(ShiftRightConcreteInteger()); + addFunco(PowerIntegerInteger()); + addFunco(PowerRationalInteger()); + addFunco(NegativeRational()); + addFunco(FloorRational()); + addFunco(IndexArray()); + addFunco(LogicalNotBoolean()); + addFunco(LessThanIntegerInteger()); + addFunco(GreaterThanIntegerInteger()); + addFunco(LessThanOrEqualToIntegerInteger()); + addFunco(GreaterThanOrEqualToIntegerInteger()); + addFunco(NegativeInteger()); + addFunco(AddDoubleDouble()); + addFunco(AddDoubleRational()); + addFunco(AddRationalDouble()); + addFunco(SubtractDoubleDouble()); + addFunco(SubtractDoubleRational()); + addFunco(SubtractRationalDouble()); + addFunco(MultiplyDoubleDouble()); + addFunco(MultiplyDoubleRational()); + addFunco(MultiplyRationalDouble()); + addFunco(DivideDoubleDouble()); + addFunco(DivideDoubleRational()); + addFunco(DivideRationalDouble()); + addFunco(PowerDoubleDouble()); + addFunco(PowerDoubleRational()); + addFunco(PowerRationalDouble()); + addFunco(ShiftLeftDoubleInteger()); + addFunco(ShiftRightDoubleInteger()); + addFunco(NegativeDouble()); + } + template ConfigOption addOption(String name) + { + addOption(name, typeFromCompileTimeType()); + return ConfigOption(this, name); + } + void addOption(String name, Type type) + { + addOption(name, Value(type)); + } + template void addDefaultOption(String name, Type type, + const V& defaultValue) + { + StructuredType s(type); + if (s.valid()) { + addOption(name, + s.lValueFromRValue(defaultValue, &_structureOwner)); + } + else + addOption(name, Value(type, defaultValue)); + } + template ConfigOption addDefaultOption(String name, + const V& defaultValue) + { + addDefaultOption(name, typeFromCompileTimeType(), defaultValue); + return ConfigOption(this, name); + } + void addType(Type type, TycoIdentifier identifier = TycoIdentifier()) + { + _scope.addType(type, identifier); + } +private: + void addOption(String name, Value defaultValue) + { + VariableDefinition s(defaultValue.type(), name); + _scope.addObject(name, s); + set(name, defaultValue, Span()); + } +public: + void addFunco(Funco funco) + { + _scope.addFunction(funco.identifier(), funco); + } + + void load(File file) + { + _file = file; + loadFromString(file.contents()); + } + void loadFromString(String contents) + { + CharacterSource source(contents, _file); + Space::parse(&source); + do { + CharacterSource s = source; + if (s.get() == -1) + break; + s = source; + Span span; + if (Space::parseKeyword(&s, "include", &span)) { + Expression e = Expression::parse(&s); + e.resolve(&_scope); + Value v = e.evaluate(this).convertTo(StringType()); + Space::assertCharacter(&s, ';', &span); + load(File(v.value(), _file.parent())); + source = s; + continue; + } + TycoSpecifier tycoSpecifier = TycoSpecifier::parse(&s); + if (tycoSpecifier.valid()) { + Type type = _scope.resolveType(tycoSpecifier); + Identifier objectIdentifier = Identifier::parse(&s); + if (objectIdentifier.isOperator()) { + objectIdentifier.span().throwError("Cannot create an " + "object with operator name"); + } + String objectName = objectIdentifier.toString(); + if (has(objectIdentifier)) { + objectIdentifier.span().throwError(objectName + + " already exists"); + } + Value value = StructuredType::empty(); + if (Space::parseCharacter(&s, '=', &span)) { + Expression e = Expression::parse(&s); + e.resolve(&_scope); + value = e.evaluate(this); + } + Space::assertCharacter(&s, ';', &span); + source = s; + value = value.rValue().convertTo(type); + span = tycoSpecifier.span() + span; + if (type.member(Identifier("*")) == StringType()) { + // This special member is how ConfigFile tells created + // objects their names so that they can responsible for + // persistence so that this functionality doesn't need to + // be in ConfigFile. + // Using an actual identifier here would lead to collisions + // with real members. ALFE persistence is done by types + // knowing how to persist themselves. + // I also don't want to use the empty string, since I might + // want to use that as the connector name for + // single-connector components. + value.value()->set(Identifier("*"), + objectName, span); + } + _scope.addObject(objectIdentifier, + VariableDefinition(type, objectIdentifier)); + set(objectIdentifier, value, span); + + continue; + } + Identifier identifier = Identifier::parse(&s); + if (!identifier.valid()) { + s.location().throwError("Expected an include statement, an " + "object creation statement or an assignment statement."); + } + Expression le = Expression::parseDot(&source); + le.resolve(&_scope); + Value left = le.evaluate(this); + Space::assertCharacter(&source, '=', &span); + Expression e = Expression::parse(&source); + if (!e.valid()) + source.location().throwError("Expected expression."); + Space::assertCharacter(&source, ';', &span); + e.resolve(&_scope); + Value loadedExpression = e.evaluate(this); + LValueType lValueType(left.type()); + if (!lValueType.valid()) + left.span().throwError("LValue required"); + Type type = lValueType.inner(); + LValue p = left.value(); + Identifier i = Identifier(OperatorAssignment()); + Value v = loadedExpression.rValue(); + span = left.span() + v.span(); + if (type.member(i).valid()) { + List arguments; + arguments.add(left); + arguments.add(v); + auto s = p.rValue().value(); + Value f = s->getValue(i); + if (f.type() == FuncoType()) + f.value().evaluate(arguments, span); + else { + List argumentTypes; + argumentTypes.add(PointerType(type)); + argumentTypes.add(PointerType(v.type())); + auto func = f.value(); + if (!func.argumentsMatch(argumentTypes)) { + span.throwError("Cannot assign value of type " + + v.type().toString() + " to object of type " + + type.toString() + "."); + } + func.evaluate(arguments, span); + } + } + else { + StructuredType s(type); + if (s.valid()) + s.setLValue(p, v.convertTo(type)); + else + p.set(v.convertTo(type), span); + } + } while (true); + for (auto i : *this) { + if (!i.value().valid()) + throw Exception(_file.path() + ": " + i.key().toString() + + " not defined and no default is available."); + } + } + + File file() const { return _file; } + + template U evaluate(String text, const U& def) + { + CharacterSource s(text); + Value c; + try { + Expression e = Expression::parse(&s); + if (!e.valid()) + return def; + e.resolve(&_scope); + Value v = e.evaluate(this); + if (!v.valid()) + return def; + c = v.convertTo(typeFromCompileTimeType()); + if (!c.valid()) + return def; + } + catch (...) { + return def; + } + return c.template value(); + } +private: + File _file; + StructureOwner _structureOwner; + Scope _scope; +}; + +#endif // INCLUDED_CONFIG_FILE_H diff --git a/80386/disassembler/include/alfe/constructor.h b/80386/disassembler/include/alfe/constructor.h new file mode 100644 index 0000000..db6a61f --- /dev/null +++ b/80386/disassembler/include/alfe/constructor.h @@ -0,0 +1,35 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_CONSTRUCTOR_H +#define INCLUDED_CONSTRUCTOR_H + +// Constructor is a base class of both Tyco (type constructor) and Funco +// (function constructor). It handles instantiations. +class Constructor : public Handle +{ +public: + String toString() const { return body()->toString(); } + Tyco instantiate(const Tyco& argument) const + { + return body()->instantiate(argument); + } +protected: + class Body : public Handle::Body + { + public: + virtual String toString() const = 0; + virtual bool canInstantiate(const Tyco& argument) const = 0; + virtual Constructor instantiate(const Tyco& argument) const + { + if (_instantiations.hasKey(argument)) + return _instantiations[argument]; + + } + private: + mutable HashTable _instantiations; + }; +private: + const Body* body() const { return as(); } +}; + +#endif // INCLUDED_CONSTRUCTOR_H diff --git a/80386/disassembler/include/alfe/convolution_pipe.h b/80386/disassembler/include/alfe/convolution_pipe.h new file mode 100644 index 0000000..2e83ad0 --- /dev/null +++ b/80386/disassembler/include/alfe/convolution_pipe.h @@ -0,0 +1,311 @@ +// Pipes that convolve with a kernel function to act as a finite impulse +// response filter, and classes to define such kernel functions. + +#include "alfe/main.h" + +#ifndef INCLUDED_CONVOLUTION_PIPE_H +#define INCLUDED_CONVOLUTION_PIPE_H + +#include "alfe/pipes.h" +#include "alfe/gcd.h" +#include "float.h" + +class ProductKernel; + +// A convolution kernel is indexed in such a way that the input samples +// correspond to integer input values. +class ConvolutionKernel : private Handle +{ +public: + class Body : public Handle::Body + { + public: + virtual double operator()(double x) const = 0; + virtual double leftExtent() const { return -DBL_MAX; } + virtual double rightExtent() const { return DBL_MAX; } + }; + + ConvolutionKernel(Body* body) : Handle(body) { } + double operator()(double x) const { return (body()->operator())(x); } + double leftExtent() const { return _body->leftExtent(); } + double rightExtent() const { return _body->rightExtent(); } + ConvolutionKernel& operator*=(const ConvolutionKernel& right) + { + _body = new ProductKernel(*this, right); + } + ConvolutionKernel& operator+=(const ConvolutionKernel& right) + { + _body = new SumKernel(*this, right); + } + ConvolutionKernel& operator-=(const ConvolutionKernel& right) + { + _body = new SumKernel(*this, -right); + } + ConvolutionKernel operator-() const + { + return ProductKernel(*this, ConstantKernel()); + } + ConvolutionKernel operator*(const ConvolutionKernel& right) + { + ConvolutionKernel k = *this; k *= right; return k; + } + ConvolutionKernel operator+(const ConvolutionKernel& right) + { + ConvolutionKernel k = *this; k += right; return k; + } + ConvolutionKernel operator-(const ConvolutionKernel& right) + { + ConvolutionKernel k = *this; k -= right; return k; + } +}; + +// Sinc filter corresponds to perfect band-limited interpolation - it removes +// all frequencies higher than the sample rate (if x is measured in samples). +class SincFilter : public ConvolutionKernel +{ +public: + SincFilter() : ConvolutionKernel(new Body) { } + class Body : public ConvolutionKernel::Body + { + virtual double operator()(double x) const + { + return sin(M_PI*x)/(M_PI*x); + } + }; +}; + +class RectangleWindow : public ConvolutionKernel +{ +public: + RectangleWindow(double semiWidth) + : ConvolutionKernel(new Body(semiWidth)) { } + class Body : public ConvolutionKernel::Body + { + public: + Body(double semiWidth) : _semiWidth(semiWidth) { } + virtual double operator()(double x) const { return 1; } + virtual double leftExtent() const { return -_semiWidth; } + virtual double rightExtent() const { return _semiWidth; } + private: + double _semiWidth; + }; +}; + +class ScaledFilter : public ConvolutionKernel +{ +public: + ScaledFilter(ConvolutionKernel kernel, double scale) + : ConvolutionKernel(new Body(kernel, scale)) { } + class Body : public ConvolutionKernel::Body + { + public: + Body(ConvolutionKernel kernel, double scale) + : _kernel(kernel), _scale(scale) { } + virtual double operator()(double x) const + { + return _kernel(x / _scale); + } + virtual double leftExtent() const + { + return _kernel.leftExtent() * _scale; + } + virtual double rightExtent() const + { + return _kernel.rightExtent() * _scale; + } + private: + ConvolutionKernel _kernel; + double _scale; + }; +}; + +class ProductKernel : public ConvolutionKernel +{ +public: + ProductKernel(ConvolutionKernel a, ConvolutionKernel b) + : ConvolutionKernel(new Body(a, b)) { } + class Body : public ConvolutionKernel::Body + { + public: + Body(ConvolutionKernel a, ConvolutionKernel b) + : _a(a), _b(b) { } + virtual double operator()(double x) const { return _a(x)*_b(x); } + virtual double leftExtent() const + { + return max(_a.leftExtent(), _b.leftExtent()); + } + virtual double rightExtent() const + { + return min(_a.rightExtent(), _b.rightExtent()); + } + private: + ConvolutionKernel _a; + ConvolutionKernel _b; + }; +}; + +class SumKernel : public ConvolutionKernel +{ +public: + SumKernel(ConvolutionKernel a, ConvolutionKernel b) + : ConvolutionKernel(new Body(a, b)) { } + class Body : public ConvolutionKernel::Body + { + public: + Body(ConvolutionKernel a, ConvolutionKernel b) + : _a(a), _b(b) { } + virtual double operator()(double x) const { return _a(x)+_b(x); } + virtual double leftExtent() const + { + return min(_a.leftExtent(), _b.leftExtent()); + } + virtual double rightExtent() const + { + return max(_a.rightExtent(), _b.rightExtent()); + } + private: + ConvolutionKernel _a; + ConvolutionKernel _b; + }; +}; + +class ConstantKernel : public ConvolutionKernel +{ +public: + ConstantKernel(double c) : ConvolutionKernel(new Body(c)) { } + class Body : public ConvolutionKernel::Body + { + public: + Body(double c) : _c(c) { } + virtual double operator()(double) const { return c; } + private: + double _c; + }; +}; + +// A convolution pipe which computes kernel coefficients as they are needed, +// which is likely to be very slow. The kernel is measured in output samples +// which is the appropriate default for downsampling. For upsampling, scale +// the +template class SmallConvolutionPipe + : public Pipe > +{ +public: + SmallConvolutionPipe(Rate producerRate, Rate consumerRate, + ConvolutionKernel kernel, int n = defaultSampleCount) + : Pipe(this, n), + _kernel(kernel), + _t(0), + _r(static_cast(producerRate)/consumerRate), + _le(kernel.leftExtent()), + _re(kernel.rightExtent()), + _maxRead((n + (_re - _le))/_r) + { } + void produce(int n) + { + Accessor reader = _sink.reader(_maxRead); + Accessor writer = _source.writer(n); + int read = 0; + for (int i = 0; i < n; ++i) { + T sample = 0; + int j = read; + for (double k = _t + _le; k < _re; k += _r) { + sample += reader.item(j)*_kernel(k); + ++j; + } + writer.item() = sample; + + int r = static_cast((_r + 1.0 - _t)/_r); + _t += r*_r; + read += r; + } + _sink.read(read); + _source.written(n); + } +private: + ConvolutionKernel _kernel; + double _t; + double _r; + int _maxRead; // Maximum number of samples that are read at once + double _le; + double _re; +}; + +// A convolution pipe that stores the kernel coefficients it requires. This +// may use a lot of memory if the producing and consuming rates have a high +// lowest common multiple, and it can't be used if the resampling factor +// changes. +template class LCMConvolutionPipe + : public Pipe > +{ +public: + // For every "consumerRate" samples consumed we will produce "producerRate" + // samples. + LCMConvolutionPipe(Rate producerRate, Rate consumerRate, + ConvolutionKernel kernel, int n = defaultSampleCount) + : Pipe(this, n), + _t(0) + { + Rate l = lcm(producerRate, consumerRate); // 275625000 + int c = l/producerRate; // 6250 + _delta = l/consumerRate; // 231 + double le = kernel.leftExtent(); + double re = kernel.rightExtent(); + double extent = re-le; // 10 + _maxRead = (n + extent)/_r; + _kernelSize = extent*c; + // TODO: rearrange kernel coefficients so that they are adjacent in + // memory for better cache performance + _kernel.allocate(_kernelSize); + for (int i = 0; i < _kernelSize; ++i) + _kernel[i] = kernel(static_cast(i)/c + le); + } + void produce(int n) + { + Accessor reader = _sink.reader(_maxRead); + Accessor writer = _source.writer(n); + int read = 0; + for (int i = 0; i < n; ++i) { + T sample = 0; + int j = read; + for (int k = _t; k < _kernelSize; k += _delta) { + sample += reader.item(j)*_kernel[k]; + ++j; + } + writer.item() = sample; + int r = static_cast((c + _delta - _t)/_delta); + _t += r*_delta; + read += r; + } + _sink.read(read); + _source.written(n); + } +private: + // _kernel is indexed in units of 1/c of an output sample and offset by le + // output samples + Array _kernel; + int _kernelSize; + int _t; + int _delta; + int _t; +}; + +// A convolution pipe that computes a fixed number of kernel coefficients, and +// uses the closest one to the one required. +template class NearestNeighborConvolutionPipe + : public Pipe > +{ + // TODO +}; + +// A convolution pipe that computes a fixed number of kernel coefficients, and +// uses linear interpolation to find the others. +template class LinearConvolutionPipe + : public Pipe > +{ +}; + + +// 985428/44100 == 492714/22050 == 246357/11025 == 82119/3675 == 27373/1225 + +#endif // INCLUDED_CONVOLUTION_PIPE_H diff --git a/80386/disassembler/include/alfe/directx.h b/80386/disassembler/include/alfe/directx.h new file mode 100644 index 0000000..2b0d13c --- /dev/null +++ b/80386/disassembler/include/alfe/directx.h @@ -0,0 +1,511 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_DIRECTX_H +#define INCLUDED_DIRECTX_H + +#include +#ifdef _DEBUG +#include +#endif +#include +#include "alfe/vectors.h" +#include "alfe/user.h" +#include "alfe/pool.h" +#include "alfe/fix.h" +#include "alfe/com.h" + +typedef Fixed<16, Int32, Int64> Fix16p16; + +// This is the exception that we throw if any DirectX methods fail. +class DirectXException : public Exception +{ +public: + DirectXException(HRESULT hr) +#ifdef _DEBUG + : Exception(DXGetErrorDescription(hr)) +#endif + { } +}; + +#define IF_ERROR_THROW_DX(expr) CODE_MACRO( \ + HRESULT hrMacro = (expr); \ + IF_TRUE_THROW(FAILED(hrMacro), DirectXException(hrMacro)); \ +) + + +class Direct3D : Uncopyable +{ +public: + Direct3D() + { + // The *& causes the smart pointer to avoid the AddRef and take over + // ownership of the raw pointer, causing the interface to be released + // when the Direct3D object is destructed. + *&_direct3D = Direct3DCreate9(D3D_SDK_VERSION); + IF_FALSE_THROW(_direct3D.valid()); + } +private: + COMPointer _direct3D; + + friend class Device; +}; + + +struct Vertex +{ + float x, y, z; + float rhw; + float u, v; +}; + + +class Device : Uncopyable +{ +public: + Device(bool clampTextures = true) : _clampTextures(clampTextures), + _filterType(D3DTEXF_FORCE_DWORD), + _gammaCorrection(false), + //_backBufferSize(0, 0), + _adapter(D3DADAPTER_DEFAULT) + { + ZeroMemory(&_parameters, sizeof(D3DPRESENT_PARAMETERS)); + _parameters.BackBufferCount = 1; + _parameters.MultiSampleType = D3DMULTISAMPLE_NONE; + _parameters.MultiSampleQuality = 0; + _parameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + _parameters.Windowed = TRUE; + _parameters.EnableAutoDepthStencil = FALSE; + _parameters.AutoDepthStencilFormat = D3DFMT_D16; + _parameters.Flags = 0; + _parameters.FullScreen_RefreshRateInHz = 0; + _parameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + } + + //bool resetNeeded(Vector size) + //{ + // /*return true;*/ + // return size.x > static_cast(_parameters.BackBufferWidth) || + // size.y > static_cast(_parameters.BackBufferHeight); + //} + + void setSize(Vector size) + { + //printf("Resizing to %i,%i\n",size.x, size.y); + //_parameters.BackBufferWidth = _backBufferSize.x = 800; + //_parameters.BackBufferHeight = _backBufferSize.y = 600; + //reset(); + + //if (resetNeeded(size)) { + //growBackBuffer(size); + _parameters.BackBufferWidth = size.x; + _parameters.BackBufferHeight = size.y; + reset(); + //} + D3DVIEWPORT9 viewport; + viewport.X = 0; + viewport.Y = 0; + viewport.Width = size.x; + viewport.Height = size.y; + viewport.MinZ = 0.0f; + viewport.MaxZ = 1.0f; + IF_ERROR_THROW_DX(_device->SetViewport(&viewport)); + //_size = size; + } + + void create(Direct3D* direct3D, Window* window) + { + _direct3D = direct3D; + initBackBuffer(); + Vector size = window->getSize(); + _parameters.BackBufferWidth = size.x; + _parameters.BackBufferHeight = size.y; + + //_size = _backBufferSize; + _parameters.hDeviceWindow = *window; + // D3DCREATE_MULTITHREADED causes the Direct3D runtime to enter a + // critical section for the duration of every Direct3D call, preventing + // multiple Direct3D calls happening at once. It is not actually + // needed here, since we are careful always to use our own locks to + // prevent multiple Direct3D calls from happening at once. However, the + // debug version of the Direct3D runtime complains if we call Direct3D + // from multiple threads without this flag. + IF_ERROR_THROW_DX(direct3D->_direct3D->CreateDevice( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + NULL, + D3DCREATE_SOFTWARE_VERTEXPROCESSING | + D3DCREATE_FPU_PRESERVE /*| D3DCREATE_MULTITHREADED*/, + &_parameters, + &_device)); + postReset(); + } + + void destination() + { + IF_ERROR_THROW_DX(_device->SetRenderTarget(0, _renderTarget)); + } + + void setFilter(D3DTEXTUREFILTERTYPE type) + { + if (_filterType == type) + return; + _filterType = type; + IF_ERROR_THROW_DX( + _device->SetSamplerState(0, D3DSAMP_MINFILTER, type)); + IF_ERROR_THROW_DX( + _device->SetSamplerState(0, D3DSAMP_MAGFILTER, type)); + } + + void setGammaCorrection(bool enabled) + { + if (_gammaCorrection == enabled) + return; + _gammaCorrection = enabled; + IF_ERROR_THROW_DX(_device->SetRenderState( + D3DRS_SRGBWRITEENABLE, enabled ? TRUE : FALSE)); + } + + void setTextureAddressingMode(D3DTEXTUREADDRESS mode) + { + IF_ERROR_THROW_DX(_device->SetSamplerState(0, D3DSAMP_ADDRESSU, mode)); + IF_ERROR_THROW_DX(_device->SetSamplerState(0, D3DSAMP_ADDRESSV, mode)); + } + + void reset() + { + //printf("Reset\n"); + _renderTarget = 0; + initBackBuffer(); + IF_ERROR_THROW_DX(_device->Reset(&_parameters)); + postReset(); + } + + void present() + { + HRESULT hr = _device->Present( + NULL, // pSourceRect + NULL, // pDestRect + NULL, // hDestWindowOverride + NULL); // pDirtyRegion + if (hr == D3DERR_DEVICELOST) + reset(); + else + IF_ERROR_THROW_DX(hr); + } + + Vector2 transform() const + { + //return Vector2Cast(_backBufferSize + Vector(1,1))/Vector2Cast(_size); + return Vector2(1.0f, 1.0f); + } + +private: + //void growBackBuffer(Vector size) + //{ + // /*_parameters.BackBufferWidth = 0; + // _parameters.BackBufferHeight = 0; */ + + // _parameters.BackBufferWidth = _backBufferSize.x = + // max(static_cast(_parameters.BackBufferWidth), size.x); + // _parameters.BackBufferHeight = _backBufferSize.y = + // max(static_cast(_parameters.BackBufferHeight), size.y); + + // //_parameters.BackBufferWidth = _backBufferSize.x = 800; + // //_parameters.BackBufferHeight = _backBufferSize.y = 600; + //} + + void initBackBuffer() + { + D3DDISPLAYMODE displayMode; + IF_ERROR_THROW_DX(_direct3D->_direct3D-> + GetAdapterDisplayMode(_adapter, &displayMode)); + + _parameters.BackBufferFormat = displayMode.Format; + //growBackBuffer(Vector(displayMode.Width, displayMode.Height)); + } + + void postReset() + { + IF_ERROR_THROW_DX(_device->GetRenderTarget(0, &_renderTarget)); + IF_ERROR_THROW_DX(_device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1)); + IF_ERROR_THROW_DX(_device->SetRenderState(D3DRS_LIGHTING, FALSE)); + if (_clampTextures) + setTextureAddressingMode(D3DTADDRESS_CLAMP); + D3DTEXTUREFILTERTYPE filterType = _filterType; + _filterType = D3DTEXF_FORCE_DWORD; + setFilter(filterType); + } + + Direct3D* _direct3D; + UINT _adapter; + COMPointer _device; + D3DPRESENT_PARAMETERS _parameters; + COMPointer _renderTarget; + bool _clampTextures; + D3DTEXTUREFILTERTYPE _filterType; + bool _gammaCorrection; + //Vector _backBufferSize; + //Vector _size; + + friend class Texture; + friend class Geometry; + friend class Scene; + friend class GPUTexture; + friend class CPUTexture; + friend class Tile; + template friend class GridRenderer; +}; + + +class Geometry : Uncopyable +{ +public: + void create(Device* device, int size, D3DPRIMITIVETYPE type) + { + _device = device; + _size = size; + _type = type; + postReset(); + } + + void draw() + { + IF_ERROR_THROW_DX(_device->_device->SetStreamSource( + 0, // StreamNumber + _vertexBuffer, // pStreamData + 0, // OffsetInBytes + sizeof(Vertex))); // Stride + IF_ERROR_THROW_DX( + _device->_device->DrawPrimitive(_type, 0, _size - 2)); + } + + void preReset() { _vertexBuffer = 0; } + + void postReset() + { + IF_ERROR_THROW_DX(_device->_device->CreateVertexBuffer( + sizeof(Vertex)*_size, // Length + D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, // Usage + D3DFVF_XYZRHW | D3DFVF_TEX1, // FVF + D3DPOOL_DEFAULT, // Pool + &_vertexBuffer, // ppVertexBuffer + NULL)); // pSharedHandle + } + +private: + Device* _device; + int _size; + D3DPRIMITIVETYPE _type; + COMPointer _vertexBuffer; + + friend class GeometryLock; +}; + + +class GeometryLock : Uncopyable +{ +public: + GeometryLock(Geometry* geometry) : _geometry(geometry) + { + VOID* data; + // Lock the entire geometry. + IF_ERROR_THROW_DX(_geometry->_vertexBuffer->Lock( + 0, // OffsetToLock + 0, // SizeToLock + &data, // ppbData + D3DLOCK_DISCARD)); // Flags + _vertices = reinterpret_cast(data); + for (int i = 0; i < _geometry->_size; ++i) { + _vertices[i].rhw = 1.0f; + _vertices[i].z = 0.0f; + } + } + + ~GeometryLock() { _geometry->_vertexBuffer->Unlock(); } + + void setXY(int n, Vector2 position) + { + _vertices[n].x = position.x; + _vertices[n].y = position.y; + } + + void setUV(int n, Vector2 texturePosition) + { + _vertices[n].u = texturePosition.x; + _vertices[n].v = texturePosition.y; + } +private: + Geometry* _geometry; + Vertex* _vertices; +}; + + +class Quad : public Geometry +{ +public: + void create(Device* device) + { + Geometry::create(device, 4, D3DPT_TRIANGLESTRIP); + } +}; + + +// Base class for CPUTexture and GPUTexture. +class Texture : Uncopyable +{ +protected: + void create(Device* device, Vector2 size, DWORD usage, D3DPOOL pool) + { + _device = device; + IF_ERROR_THROW_DX(device->_device->CreateTexture( + size.x, // Width + size.y, // Height + 1, // Levels + usage, // Usage + D3DFMT_A8R8G8B8, // Format + pool, // Pool + &_texture, // ppTexture + NULL)); // pSharedHandle + } + + Device* _device; + COMPointer _texture; + + friend class CPUTextureLock; + friend class CPUTexture; +}; + + +// A texture in GPU memory. Used as render sources and render targets. +class GPUTexture : public Texture, public LinkedListMember +{ +public: + void create(Device* device, Vector size) + { + _device = device; + _size = size; + postReset(); + plotBlock(Vector(0, 0), 256, 0x808080); + } + + void plotBlock(Vector texel, int size, DWORD colour) + { + RECT rect; + //if (size > 1) { + // rect.left = texel.x; + // rect.top = texel.y; + // rect.right = texel.x + size; + // rect.bottom = texel.y + size; + // IF_ERROR_THROW_DX( + // _device->_device->ColorFill(_surface, &rect, 0xffffff)); + // + // rect.left = texel.x; + // rect.top = texel.y; + // rect.right = texel.x + size - 1; + // rect.bottom = texel.y + size - 1; + // IF_ERROR_THROW_DX( + // _device->_device->ColorFill(_surface, &rect, colour)); + // return; + //} + rect.left = texel.x; + rect.top = texel.y; + rect.right = texel.x + size; + rect.bottom = texel.y + size; + IF_ERROR_THROW_DX( + _device->_device->ColorFill(_surface, &rect, colour)); + } + + void source() + { + IF_ERROR_THROW_DX(_device->_device->SetTexture(0, _texture)); + } + + void destination() + { + IF_ERROR_THROW_DX(_device->_device->SetRenderTarget(0, _surface)); + } + + void preReset() { _surface = 0; _texture = 0; } + + void postReset() + { + Texture::create(_device, _size, D3DUSAGE_RENDERTARGET, + D3DPOOL_DEFAULT); + IF_ERROR_THROW_DX(_texture->GetSurfaceLevel(0, &_surface)); + } + +private: + Device* _device; + Vector _size; + COMPointer _surface; + + friend class CPUTexture; +}; + + +// A texture in CPU memory. When a device is lost it is generally faster +// (especially when there is a lot of detail) to redraw the texture in CPU +// memory and then blit it to the GPU. +class CPUTexture : public Texture +{ +public: + void create(Device* device, Vector2 size) + { + Texture::create(device, size, 0, D3DPOOL_SYSTEMMEM); + } + + void update(GPUTexture* target) + { + IF_ERROR_THROW_DX( + _device->_device->UpdateTexture(_texture, target->_texture)); + } +}; + + +// A lock on a CPU texture which can be used to plot blocks. +class CPUTextureLock : Uncopyable +{ +public: + CPUTextureLock(CPUTexture* texture) : _texture(texture) + { + // Lock the entire texture - this is only used when we're plotting a + // new tile or when the device is lost. In both of these cases we need + // to update the entire texture anyway. + IF_ERROR_THROW_DX(_texture->_texture->LockRect( + 0, // Level + &_lockData, // pLockedRect + NULL, // pRect + 0)); // Flags + } + + ~CPUTextureLock() { _texture->_texture->UnlockRect(0); } + + int stride() const { return _lockData.Pitch; } + Byte* data() const { return reinterpret_cast(_lockData.pBits); } + + void plotBlock(Vector texel, int size, DWORD colour) + { + int pitch = stride(); + Byte* p = data() + texel.y*pitch + texel.x*4; + for (int y = 0; y < size; ++y) { + DWord* l = reinterpret_cast(p); + for (int x = 0; x < size; ++x) + *l++ = colour; + p += pitch; + } + } + +private: + CPUTexture* _texture; + D3DLOCKED_RECT _lockData; +}; + + +class Renderer +{ +public: + +}; + + +#endif // INCLUDED_DIRECTX_H diff --git a/80386/disassembler/include/alfe/double_functions.h b/80386/disassembler/include/alfe/double_functions.h new file mode 100644 index 0000000..574b891 --- /dev/null +++ b/80386/disassembler/include/alfe/double_functions.h @@ -0,0 +1,385 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_DOUBLE_FUNCTIONS_H +#define INCLUDED_DOUBLE_FUNCTIONS_H + +#include "alfe/function.h" +#include "alfe/rational.h" + +class AddDoubleDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return Value(l + i->value()); + } + Identifier identifier() const { return OperatorPlus(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), DoubleType()); + } + }; +}; + +class AddDoubleRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return Value(l + i->value().value()); + } + Identifier identifier() const { return OperatorPlus(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), RationalType()); + } + }; +}; + +class AddRationalDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l.value() + i->value()); + } + Identifier identifier() const { return OperatorPlus(); } + FunctionType type() const + { + return FunctionType(DoubleType(), RationalType(), DoubleType()); + } + }; +}; + +class SubtractDoubleDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return Value(l - i->value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), DoubleType()); + } + }; +}; + +class SubtractDoubleRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return Value(l - i->value().value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), RationalType()); + } + }; +}; + +class SubtractRationalDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l.value() - i->value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return FunctionType(DoubleType(), RationalType(), DoubleType()); + } + }; +}; + +class MultiplyDoubleDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return Value(l * i->value()); + } + Identifier identifier() const { return OperatorStar(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), DoubleType()); + } + }; +}; + +class MultiplyDoubleRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return Value(l * i->value().value()); + } + Identifier identifier() const { return OperatorStar(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), RationalType()); + } + }; +}; + +class MultiplyRationalDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l.value() * i->value()); + } + Identifier identifier() const { return OperatorStar(); } + FunctionType type() const + { + return FunctionType(DoubleType(), RationalType(), DoubleType()); + } + }; +}; + +class DivideDoubleDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return Value(l / i->value()); + } + Identifier identifier() const { return OperatorDivide(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), DoubleType()); + } + }; +}; + +class DivideDoubleRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return Value(l / i->value().value()); + } + Identifier identifier() const { return OperatorDivide(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), RationalType()); + } + }; +}; + +class DivideRationalDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l.value() / i->value()); + } + Identifier identifier() const { return OperatorDivide(); } + FunctionType type() const + { + return FunctionType(DoubleType(), RationalType(), DoubleType()); + } + }; +}; + +class ShiftLeftDoubleInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + auto l = i->value(); + ++i; + return l*pow(2.0, i->value()); + } + Identifier identifier() const { return OperatorShiftLeft(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), IntegerType()); + } + }; +}; + +class ShiftRightDoubleInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + auto l = i->value(); + ++i; + return l/pow(2.0, i->value()); + } + Identifier identifier() const { return OperatorShiftRight(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), IntegerType()); + } + }; +}; + +class PowerDoubleDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return pow(l, i->value()); + } + Identifier identifier() const { return OperatorPower(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), DoubleType()); + } + }; +}; + +class PowerDoubleRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + double l = i->value(); + ++i; + return pow(l, i->value().value()); + } + Identifier identifier() const { return OperatorPower(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType(), RationalType()); + } + }; +}; + +class PowerRationalDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return pow(l.value(), i->value()); + } + Identifier identifier() const { return OperatorPower(); } + FunctionType type() const + { + return FunctionType(DoubleType(), RationalType(), DoubleType()); + } + }; +}; + +class NegativeDouble : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + return Value( - arguments.begin()->value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return FunctionType(DoubleType(), DoubleType()); + } + }; +}; + +#endif // INCLUDED_DOUBLE_FUNCTIONS_H diff --git a/80386/disassembler/include/alfe/edge.h b/80386/disassembler/include/alfe/edge.h new file mode 100644 index 0000000..c4e478b --- /dev/null +++ b/80386/disassembler/include/alfe/edge.h @@ -0,0 +1,98 @@ +class Edge; + +class EdgeExpression +{ +public: + EdgeExpression operator+(EdgeExpression a) + { + EdgeExpression l(*this); + for (auto p : a._clauses) + l.add(*p); + return l; + } + EdgeExpression operator-(EdgeExpression a) + { + EdgeExpression l(*this); + for (auto p : a._clauses) { + Clause c = *p; + c._coefficient = -c._coefficient; + l.add(c); + } + return l; + } + EdgeExpression operator*(double a) + { + EdgeExpression l(*this); + l.multiply(a); + return l; + } + EdgeExpression operator/(double a) + { + EdgeExpression l(*this); + l.multiply(1.0/a); + return l; + } +private: + class Clause + { + public: + Clause(Edge* edge, double coefficient) + : _edge(edge), _coefficient(coefficient) { } + Edge* _edge; + double _coefficient; + }; + List _clauses; + double _offset; + + void setToEdge(Edge* edge) + { + _clauses = List(); + _clauses.add(Clause(edge, 1)); + _offset = 0; + } + void add(const Clause& clause) + { + for (auto p = _clauses) + if (clause._edge == p._edge) { + p._coefficient += clause._coefficient; + return; + } + _clauses.add(clause); + } + void add(double offset) + { + _offset += offset; + } + void multiply(double a) + { + for (auto p : _clauses) + p._coefficient *= a; + } + + friend class Edge; +}; + +class Edge : public EdgeExpression +{ +public: + Edge() + { + setToEdge(this); + } + void operator=(const EdgeExpression& expression) + { + EdgeExpression::operator=(expression); + } +private: + List _dependents; +}; + + + +// Add to Window: +// Edge top; +// Edge left; +// Edge right; +// Edge bottom; + + diff --git a/80386/disassembler/include/alfe/edge_expressions.txt b/80386/disassembler/include/alfe/edge_expressions.txt new file mode 100644 index 0000000..c1a32d8 --- /dev/null +++ b/80386/disassembler/include/alfe/edge_expressions.txt @@ -0,0 +1,112 @@ +How do we describe the layout hierarchy? + A Window can have constraints on its dimensions: + Minimum/maximum height/width + +We want to avoid having to manually write the resize routine for each window layout. +We want to avoid manually computing the positions of things. + +(1) By default a Window's size is fixed and it's position is fixed relative to the top-left of it's parent: + topLeft = parent.topLeft + offset + bottomRight = topLeft + size +(2) We'd like to be able to pin it to the bottom right by doing: + topLeft = parent.bottomRight + offset - size +(3) We'd like to be able to pin it to both corners by doing: + bottomRight = parent.bottomRight + offset +(4) We'd like to be able to centre it in the parent by doing: + topLeft = parent.topLeft*2/3 + parent.bottomRight*1/3 + bottomRight = parent.topLeft*1/3 + parent.bottomRight*2/3 + +These handles are not just positions - they're live objects so that (e.g. in case 2) as size changes, bottomRight will change as well +Use the spreadsheet evaluation pattern to avoid circular references + + + +After create, each window has a default/natural size + create: + +We would like the size/position of child windows to be driven by the size of the parent window, not the other way around. + +Edge: + Computed Edge + Parent Edge 1 + Multiplier 1 + Parent Edge 2 + Multiplier 2 + Offset + Real Edge: + Left/Right/Top/Bottom + +Sides form an affine structure + +Edge needs to know which other edges refer to it + + +Maybe we need two edge constrains: + One that can be overridden by the mouse and one which can't.[*] + +Instead of rewriting constraint code in each window's setInnerSize(), have minimum & maximum size constraints + +What do we do about unsatisfyable constraints (e.g. min > max)? + Undefined + +[*] + There is the current size/position which can be overridden with the mouse, and the edge equations/size constrains, which can't. + +The "unlimited" edge equation just says, e.g. + right=right; // This means right = left + current_size, overridable +It's not useful to have "edge = constant" - all edges are relative to some other edge so that the entire top-level window can be moved arbitrarily. + +Currently, each constraint is associated with an edge (e.g. right = ...). This doesn't really need to be the case, but it does solve some problems: + * Specifying constraints in the first place (rearrange so that an edge is on the left, then use overridden assignment). + * Identifying constraints for deletion/replacement. + +Each edge will need a list of edges that refer to it. + 2 child edge per edge is enough - if we need more we can create an intermediate edge + Maybe have a helper for this for the aspect ratio case at least. + + +Algorithm for computing edges: + Find set of unknown edges required to compute edge we're trying to find + Turn this into a set of equations and solve + +We'd like to set up rules like: + This window should take up the bottom 10% unless that would make it smaller than 10 pixels, in which case make it 10 pixels. + +Final position is a function of requested position and computed position + +If a window's constraints are not satisfied, it can switch to an alternate set of edge equations, which are then re-solved, fixing the mouse position, so the window can't get smaller than the + minimum size. + How are such rules specified? + In setInnerSize(), check constraints. If not met: + Save old edges + Set fixed edges + Recompute + Restore old edges + WM_SIZE message returns false if window size was not set to requested size? + +Can set aspect ratio constraints by setting: + right = left + (bottom - top)*4/3; + That is an example of a 3-edge constraint so 2 is not enough. + + +Who owns fake edges made up for the 3-edge scenario? + right = left + (botton - top)*4/3 +Allow just adding an extra edge to the window? +Or reference count + + +Edge / const -> Edge +Edte * const -> Edge +Edge + Edge -> Edge +Edge - Edge -> Edge + +Have a TempEdge or EdgeExpression class which doesn't have a list of its referents +Instead of having edges form a tree, have a list of component edges in each edge + Lists are filled in when edges are assigned (from edge or edgeexpression) + + + +This does not solve problems like: + * Put the bottom edge of this window at the lowest position in which it doesn't overlap any of these windows + +It also doesn't really buy us much over just writing the layout specifications in the resize routine diff --git a/80386/disassembler/include/alfe/email.h b/80386/disassembler/include/alfe/email.h new file mode 100644 index 0000000..332b5a1 --- /dev/null +++ b/80386/disassembler/include/alfe/email.h @@ -0,0 +1,62 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_EMAIL_H +#define INCLUDED_EMAIL_H + +void sendMail(String from, String to, String subject, String body) +{ + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + HANDLE pipeReadHandle; + HANDLE pipeWriteHandle; + if (CreatePipe( + &pipeReadHandle, &pipeWriteHandle, &sa, 0) == 0) { + throw Exception::systemError("Could not create pipe"); + } + + Stream pipeRead(pipeReadHandle, File(), true); + Stream pipeWrite(pipeWriteHandle, File(), true); + + if (SetHandleInformation(pipeWriteHandle, HANDLE_FLAG_INHERIT, 0) == 0) + throw Exception::systemError("Could not set write handle of input " + "pipe to not inherited"); + + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + + STARTUPINFO si; + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.hStdError = console; + si.hStdOutput = console; + si.hStdInput = pipeReadHandle; + si.dwFlags |= STARTF_USESTDHANDLES; + + // Make a copy of the command line because CreateProcess needs to modify + // it. + WCHAR commandLine[] = L"sendmail.exe -t"; + + if (CreateProcess(NULL, // lpApplicationName + commandLine, // lpCommandName + NULL, // lpProcessAttributes + NULL, // lpThreadAttributes + TRUE, // bInheritHandles + 0, // dwCreationFlags + NULL, // lpEnvironment + NULL, // lpCurrentDirectory + &si, // lpStartupInfo + &pi) == 0) { // lpProcessInformation + throw Exception::systemError("Could not create sendmail process"); + } + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + pipeWrite.write("From: " + from + "\n"); + pipeWrite.write("To: " + to + "\n"); + pipeWrite.write("Subject: " + subject + "\n\n"); + pipeWrite.write(body + "\n"); +} + +#endif // INCLUDED_EMAIL_H diff --git a/80386/disassembler/include/alfe/evaluate.h b/80386/disassembler/include/alfe/evaluate.h new file mode 100644 index 0000000..b8ced69 --- /dev/null +++ b/80386/disassembler/include/alfe/evaluate.h @@ -0,0 +1,36 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_EVALUATE_H +#define INCLUDED_EVALUATE_H + +#include "alfe/space.h" + +template T evaluate(CharacterSource s) +{ + throw Exception("Don't know how to evaluate this expression"); +} + +template<> int evaluate(CharacterSource s) +{ + int c = s.get(); + if (c < '0' || c > '9') + return 0; + int n = 0; + do { + n = n*10 + c - '0'; + c = s.get(); + if (c < '0' || c > '9') { + Space::parse(&s); + return n; + } + } while (true); +} + +template T evaluate(String s) +{ + CharacterSource source(s); + return evaluate(source); +} + +#endif // INCLUDED_EVALUATE_H + diff --git a/80386/disassembler/include/alfe/exception.h b/80386/disassembler/include/alfe/exception.h new file mode 100644 index 0000000..da17d94 --- /dev/null +++ b/80386/disassembler/include/alfe/exception.h @@ -0,0 +1,156 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_EXCEPTION_H +#define INCLUDED_EXCEPTION_H + +#define CODE_MACRO(x) do { x } while (false) + +#define IF_TRUE_THROW(expr,exception) CODE_MACRO( \ + if (expr) \ + throw exception; \ +) + +#define IF_FALSE_THROW(expr) \ + IF_TRUE_THROW(!(expr), Exception::systemError()) +#define IF_MINUS_ONE_THROW(expr) \ + IF_TRUE_THROW((expr) == -1, Exception::systemError()) +#define IF_ZERO_THROW(expr) \ + IF_TRUE_THROW((expr) == 0, Exception::systemError()) +#define IF_NULL_THROW(expr) \ + IF_TRUE_THROW((expr) == NULL, Exception::systemError()) +#define IF_NONZERO_THROW(expr) \ + IF_TRUE_THROW((expr) != 0, Exception::systemError()) + +#define IF_ZERO_CHECK_THROW_LAST_ERROR(expr) CODE_MACRO( \ + if ((expr) == 0) \ + IF_FALSE_THROW(GetLastError() == 0); \ +) + +#define BEGIN_CHECKED \ + try { \ + try + +#define END_CHECKED \ + catch(std::bad_alloc&) { \ + throw Exception::outOfMemory(); \ + } \ + catch(std::exception&) { \ + throw Exception::unknown(); \ + } \ + } \ + catch + +template class ExceptionT +{ +public: +#ifdef _WIN32 + ExceptionT() : _message(messageFromErrorCode(E_FAIL)) { } +#else + ExceptionT() : _message("Unspecified error") { } +#endif + ExceptionT(const String& message) : _message(message) { } + void write(const StreamT& stream) const + { + stream.write(_message + codePoint(10)); + } + static Exception systemError(const String& message = String()) + { + String m; +#ifdef _WIN32 + m = messageFromErrorCode(GetLastError()); +#else + m = String(strerror(errno)); +#endif + if (message.empty()) + return Exception(m); + return Exception(message + " : " + m); + } + static Exception outOfMemory() + { +#ifdef _WIN32 + return Exception(messageFromErrorCode(E_OUTOFMEMORY)); +#else + return Exception(strerror(ENOMEM)); +#endif + } + static Exception unknown() { return Exception(); } + String message() const { return _message; } + +#ifdef _WIN32 + static Exception fromErrorCode(DWORD error) + { + return Exception(messageFromErrorCode(error)); + } +#else + static Exception fromErrorCode(int error) + { + return Exception(strerror(error)); + } +#endif +private: +#ifdef _WIN32 + static String messageFromErrorCode(DWORD error) + { + if (error == 0) { + // If there was really no error we wouldn't be here. Avoid emitting + // messages like "Error: Success" + error = E_FAIL; + } + LocalString strMessage; + // The reinterpret_cast<> here is necessary because of the + // FORMAT_MESSAGE_ALLOCATE_BUFFER flag, which causes Windows to put a + // LPWSTR value in a *LPWSTR variable. + DWORD formatted = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + error, + 0, + reinterpret_cast(&strMessage), + 0, + NULL); + if (formatted == 0) + return String("Error code: ") + hex(error, 8); + // It's safe to destruct the LocalString because it uses wide + // characters and the String constructor will allocate its own buffer + // for the UTF-8 conversion. + return strMessage.string(); + } +#endif + String _message; +}; + +class NotYetImplementedException : public Exception +{ +public: + NotYetImplementedException() : Exception("Not yet implemented") { } +}; + +class PreserveSystemError +{ +public: + PreserveSystemError() + { +#ifdef _WIN32 + _lastError = GetLastError(); +#else + _errno = errno; +#endif + } + ~PreserveSystemError() + { +#ifdef _WIN32 + SetLastError(_lastError); +#else + errno = _errno; +#endif + } +private: +#ifdef _WIN32 + DWORD _lastError; +#else + int _errno; +#endif +}; + +#endif // INCLUDED_EXCEPTION_H diff --git a/80386/disassembler/include/alfe/expression.h b/80386/disassembler/include/alfe/expression.h new file mode 100644 index 0000000..f720d4b --- /dev/null +++ b/80386/disassembler/include/alfe/expression.h @@ -0,0 +1,1417 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_EXPRESSION_H +#define INCLUDED_EXPRESSION_H + +#include "alfe/parse_tree_object.h" +#include "alfe/operator.h" +#include "alfe/identifier.h" +#include "alfe/type_specifier.h" + +template class ExpressionT; +typedef ExpressionT Expression; + +template class IdentifierT; +typedef IdentifierT Identifier; + +template class FunctionCallExpressionT; +typedef FunctionCallExpressionT FunctionCallExpression; + +template class TypeT; +typedef TypeT Type; + +template class ValueT; +typedef ValueT Value; + +template class TycoT; +typedef TycoT Tyco; + +template class ValueT; +typedef ValueT Value; + +template class TycoIdentifierT; +typedef TycoIdentifierT TycoIdentifier; + +template class LogicalOrExpressionT; +typedef LogicalOrExpressionT LogicalOrExpression; + +template class ConditionalExpressionT; +typedef ConditionalExpressionT ConditionalExpression; + +template class NumericLiteralT; +typedef NumericLiteralT NumericLiteral; + +template class StructuredTypeT; +typedef StructuredTypeT StructuredType; + +template class LValueTypeT; +typedef LValueTypeT LValueType; + +template class LValueT; +typedef LValueT LValue; + +template class StructureT; +typedef StructureT Structure; + +template class OverloadedFunctionSetT; +typedef OverloadedFunctionSetT OverloadedFunctionSet; + +template class VariableDefinitionT; +typedef VariableDefinitionT VariableDefinition; + +class Function; + +template class FuncoTypeT; +typedef FuncoTypeT FuncoType; + +template class BooleanTypeT; +typedef BooleanTypeT BooleanType; + +class ArrayType; + +int parseHexadecimalCharacter(CharacterSource* source, Span* span) +{ + CharacterSource s = *source; + int c = s.get(span); + if (c >= '0' && c <= '9') { + *source = s; + return c - '0'; + } + if (c >= 'A' && c <= 'F') { + *source = s; + return c + 10 - 'A'; + } + if (c >= 'a' && c <= 'f') { + *source = s; + return c + 10 - 'a'; + } + return -1; +} + +template class ExpressionT : public ParseTreeObject +{ +public: + ExpressionT() { } + ExpressionT(Handle other) : ParseTreeObject(other) { } + + class Body : public ParseTreeObject::Body + { + public: + Body(const Span& span) : ParseTreeObject::Body(span) { } + virtual Expression stringify() const + { + return create< + typename FunctionCallExpressionT::FunctionCallBody>( + Expression(expression()).dot(IdentifierT("toString")), + List(), span()); + } + virtual String toString() const = 0; + virtual Value evaluate(Structure* context) const = 0; + Expression expression() const { return handle(); } + virtual TypeT type() const = 0; + virtual void resolve(Scope* scope) = 0; + virtual bool mightHaveSideEffect() const = 0; + }; + + ExpressionT(const String& string, const Span& span) + : ParseTreeObject(create(string, span)) { } + + static Expression parse(CharacterSource* source) + { + return ConditionalExpressionT::parse(source); + } + static Expression parseOrFail(CharacterSource* source) + { + Expression expression = parse(source); + if (!expression.valid()) + throwError(source); + return expression; + } + Expression operator+(const Expression& other) const + { + Expression e = *this; + e += other; + return e; + } + Expression operator-(const Expression& other) const + { + Expression e = *this; + e -= other; + return e; + } + const Expression& operator+=(const Expression& other) + { + *this = FunctionCallExpressionT::binary(OperatorPlus(), + Span(), *this, other); + return *this; + } + const Expression& operator-=(const Expression& other) + { + *this = FunctionCallExpressionT::binary(OperatorMinus(), + Span(), *this, other); + return *this; + } + Expression operator!() const + { + return FunctionCallExpressionT::unary(OperatorNot(), + Span(), *this); + } + Expression dot(const Identifier& identifier) + { + return create(*this, identifier); + } + + // toString() creates a compile-time String which is a pretty-printed + // representation of the Expression. + // stringify() create a run-time Expression which converts the value of + // the expression into a String. + Expression stringify() const { return body()->stringify(); } + String toString() const { return body()->toString(); } + + static Expression parseDot(CharacterSource* source) + { + Expression e = FunctionCallExpressionT::parse(source); + if (!e.valid()) + return e; + do { + Span span; + if (Space::parseCharacter(source, '.', &span)) { + IdentifierT i = IdentifierT::parse(source); + if (!i.valid()) + source->location().throwError("Identifier expected"); + e = e.dot(i); + continue; + } + return e; + } while (true); + } + + void resolve(Scope* scope) { body()->resolve(scope); } + ValueT evaluate(Structure* context) const + { + return body()->evaluate(context).simplify(); + } + TypeT type() const { return body()->type(); } + bool mightHaveSideEffect() const { return body()->mightHaveSideEffect(); } + +protected: + const Body* body() const { return as(); } + Body* body() { return as(); } + + static Expression parseElement(CharacterSource* source) + { + Location start = source->location(); + Expression e = parseDoubleQuotedString(source); + if (e.valid()) + return e; + e = parseEmbeddedLiteral(source); + if (e.valid()) + return e; + e = parseNumber(source); + if (e.valid()) + return e; + e = IdentifierT::parse(source); + if (e.valid()) + return e; + e = FunctionCallExpressionT::parseConstructorCall(source); + if (e.valid()) + return e; + e = VariableDefinitionT::parse(source); + if (e.valid()) + return e; + Span span; + if (Space::parseKeyword(source, "true", &span)) + return create(span); + if (Space::parseKeyword(source, "false", &span)) + return create(span); + CharacterSource s2 = *source; + if (Space::parseCharacter(&s2, '(', &span)) { + List expressions; + bool foundExpression = false; + do { + Span span2; + if (Space::parseCharacter(&s2, ')', &span2)) { + *source = s2; + if (expressions.count() == 0) + return create(span + span2); + if (expressions.count() == 1) + return *expressions.begin(); + return create(expressions, span + span2); + } + if (foundExpression && + !Space::parseCharacter(&s2, ',', &span2)) { + return Expression(); + } + e = parse(&s2); + if (!e.valid()) + return e; + expressions.add(e); + foundExpression = true; + } while (true); + } + if (Space::parseCharacter(&s2, '{', &span)) { + List expressions; + bool foundExpression = false; + do { + Span span2; + if (Space::parseCharacter(&s2, '}', &span2)) { + *source = s2; + return create(expressions, span + span2); + } + if (foundExpression && + !Space::parseCharacter(&s2, ',', &span2)) { + return Expression(); + } + e = parse(&s2); + if (!e.valid()) + return e; + expressions.add(e); + foundExpression = true; + } while (true); + } + return e; + } + + static void throwError(CharacterSource* source) + { + source->location().throwError("Expected expression"); + } +private: + static Expression parseDoubleQuotedString(CharacterSource* source) + { + Span span; + Span startSpan; + if (!source->parse('"', &startSpan)) + return Expression(); + Span stringStartSpan = startSpan; + Span stringEndSpan = startSpan; + int startOffset = source->offset(); + int endOffset; + String insert; + int n; + int nn; + String string; + Expression expression; + Expression part; + do { + CharacterSource s = *source; + endOffset = s.offset(); + int c = s.get(&span); + if (c < 0x20 && c != 10) { + if (c == -1) + source->location().throwError("End of file in string"); + source->throwUnexpected("printable character"); + } + *source = s; + switch (c) { + case '"': + { + string += s.subString(startOffset, endOffset); + Space::parse(source); + Expression r(string, stringStartSpan + span); + if (expression.valid()) + return expression + r; + return r; + } + case '\\': + string += s.subString(startOffset, endOffset); + c = s.get(&stringEndSpan); + if (c < 0x20) { + if (c == 10) + source->location().throwError( + "End of line in string"); + if (c == -1) + source->location().throwError( + "End of file in string"); + source->throwUnexpected("escaped character"); + } + *source = s; + switch (c) { + case 'n': + insert = "\n"; + break; + case 't': + insert = codePoint(9); + break; + case '$': + insert = "$"; + break; + case '"': + insert = "\""; + break; + case '\'': + insert = "'"; + break; + case '`': + insert = "`"; + break; + case '\\': + insert = "\\"; + break; + case 'U': + source->assert('+', &stringEndSpan); + n = 0; + for (int i = 0; i < 4; ++i) { + nn = parseHexadecimalCharacter(source, + &stringEndSpan); + if (nn == -1) { + source-> + throwUnexpected("hexadecimal digit"); + } + n = (n << 4) | nn; + } + nn = parseHexadecimalCharacter(source, + &stringEndSpan); + if (nn != -1) { + n = (n << 4) | nn; + nn = parseHexadecimalCharacter(source, + &stringEndSpan); + if (nn != -1) + n = (n << 4) | nn; + } + insert = codePoint(n); + break; + default: + source->throwUnexpected("escaped character"); + } + string += insert; + startOffset = source->offset(); + break; + case '$': + part = IdentifierT::parse(source); + if (!part.valid()) { + if (Space::parseCharacter(source, '(', &span)) { + part = Expression::parseOrFail(source); + source->assert(')', &span); + } + else + source->location().throwError("Expected " + "identifier or parenthesized expression"); + } + string += s.subString(startOffset, endOffset); + startOffset = source->offset(); + if (part.valid()) { + expression += Expression(string, + stringStartSpan + stringEndSpan); + string = ""; + expression += part.stringify(); + } + break; + default: + stringEndSpan = span; + } + } while (true); + } + + static Expression parseEmbeddedLiteral(CharacterSource* source) + { + Span startSpan; + if (!source->parseString("###", &startSpan)) + return Expression(); + int startOffset = source->offset(); + Location location = source->location(); + CharacterSource s = *source; + + bool eof; + String terminator = s.delimitString(String(String::CodePoint(10)), &eof); + if (eof) + source->location().throwError("End of file in string"); + + String string = s.delimitString(terminator + "###", &eof); + if (eof) + s.location().throwError("End of file in string"); + + return Expression(string, Span(startSpan.start(), s.location())); + } + + static Expression parseNumber(CharacterSource* source) + { + Rational n; + Span span; + if (Space::parseNumber(source, &n, &span)) + return NumericLiteralT(n, span); + return Expression(); + } + + class UnitBody : public Body + { + public: + UnitBody(const Span& span) : Body(span) { } + Expression stringify() const { return Expression("()", this->span()); } + String toString() const { return "()"; } + ValueT evaluate(Structure* context) const { return ValueT(); } + TypeT type() const { return VoidTypeT(); } + void resolve(Scope* scope) { } + bool mightHaveSideEffect() const { return false; } + }; + class TupleBody : public Body + { + public: + TupleBody(List expressions, const Span& span) + : Body(span), _expressions(expressions) { } + Expression stringify() const + { + Expression r("(", Span()); + bool first = true; + for (auto e : _expressions) { + if (!first) + r += Expression(", ", Span()); + first = false; + r += e.stringify(); + } + r += Expression(")", Span()); + r.setSpan(this->span()); + return r; + } + String toString() const + { + String r = "("; + bool first = true; + for (auto e : _expressions) { + if (!first) + r += ", "; + first = false; + r += e.toString(); + } + return r + ")"; + } + ValueT evaluate(Structure* context) const + { + List> v; + for (auto e : _expressions) + v.add(e.evaluate(context)); + return ValueT(type(), v); + } + TypeT type() const + { + TupleTycoT t; + for (auto e : _expressions) + t = t.instantiate(e.type()); + return t; + } + void resolve(Scope* scope) + { + for (auto e : _expressions) + e.resolve(scope); + } + bool mightHaveSideEffect() const + { + for (auto e : _expressions) { + if (e.mightHaveSideEffect()) + return true; + } + return false; + } + private: + List _expressions; + }; + class BooleanBody : public Body + { + public: + BooleanBody(const Span& span) : Body(span) { } + Expression stringify() const + { + return Expression(this->toString(), this->span()); + } + TypeT type() const { return BooleanTypeT(); } + void resolve(Scope* scope) { } + bool mightHaveSideEffect() const { return false; } + }; + class TrueBody : public BooleanBody + { + public: + TrueBody(const Span& span) : BooleanBody(span) { } + String toString() const { return "true"; } + ValueT evaluate(Structure* context) const { return true; } + }; + class FalseBody : public BooleanBody + { + public: + FalseBody(const Span& span) : BooleanBody(span) { } + String toString() const { return "false"; } + ValueT evaluate(Structure* context) const { return false; } + }; + class StringLiteralBody : public Body + { + public: + StringLiteralBody(const String& string, const Span& span) + : Body(span), _string(string) { } + Expression stringify() const { return this->expression(); } + String toString() const + { + CharacterSource s(_string); + String r = "\""; + do { + int c = s.get(); + if (c == -1) + break; + switch (c) { + case '\"': + r += "\\\""; + break; + case '$': + r += "\\$"; + break; + default: + r += codePoint(c); + break; + } + } while (true); + return r + "\""; + } + ValueT evaluate(Structure* context) const { return _string; } + TypeT type() const { return StringTypeT(); } + void resolve(Scope* scope) { } + bool mightHaveSideEffect() const { return false; } + private: + String _string; + }; + class ArrayLiteralBody : public Body + { + public: + ArrayLiteralBody(const List& expressions, const Span& span) + : Body(span), _expressions(expressions) { } + ValueT evaluate(Structure* context) const + { + HashTable values; + List::Member> members; + int i = 0; + for (auto e : _expressions) { + ValueT v = e.evaluate(context); + Type t = v.type(); + String n = decimal(i); + values.add(n, v); + members.add(typename StructuredTypeT::Member("", t)); + ++i; + } + return Value(StructuredType("", members), values, this->span()); + } + TypeT type() const + { + TypeT type = VoidTypeT(); + int i = 0; + for (auto e : _expressions) { + if (i == 0) + type = e.type(); + else { + if (type != e.type()) { + e.span().throwError("Array literal has inconsistent " + "types. Element 0 has type " + type.toString() + + ", element" + decimal(i) + " has type " + + e.type().toString() + "."); + } + } + ++i; + } + return ArrayType(type); + } + Expression stringify() const + { + Expression r("{", Span()); + bool first = true; + for (auto e : _expressions) { + if (!first) + r += Expression(", ", Span()); + first = false; + r += e.stringify(); + } + r += Expression("}", Span()); + r.setSpan(this->span()); + return r; + } + String toString() const + { + String r = "{"; + bool first = true; + for (auto e : _expressions) { + if (!first) + r += ", "; + first = false; + r += e.toString(); + } + return r + "}"; + } + void resolve(Scope* scope) + { + for (auto e : _expressions) + e.resolve(scope); + } + bool mightHaveSideEffect() const + { + for (auto e : _expressions) { + if (e.mightHaveSideEffect()) + return true; + } + return false; + } + private: + List _expressions; + }; + class DotBody : public Body + { + public: + DotBody(const Expression& left, const IdentifierT& right) + : Body(left.span() + right.span()), _left(left), _right(right) { } + ValueT evaluate(Structure* context) const + { + ValueT e = _left.evaluate(context); + + LValueTypeT lValueType(e.type()); + if (!lValueType.valid()) { + if (!e.type().member(_right).valid()) { + this->span().throwError("Expression has no member named " + + _right.toString()); + } + auto m = e.template value, + ValueT>>(); + e = m[_right]; + e = Value(e.type(), e.value(), this->span()); + } + else { + TypeT t = lValueType.inner().member(_right); + if (!t.valid()) { + this->span().throwError("Expression has no member named " + + _right.toString()); + } + e = Value(LValueTypeT::wrap(t), + e.template value>().member(_right), + this->span()); + } + return e; + } + TypeT type() const + { + TypeT lType = _left.type(); + StructuredType s = lType; + if (!s.valid()) + _left.span().throwError("Expression has no members"); + return s.member(_right); + } + String toString() const + { + return _left.toString() + "." + _right.toString(); + } + void resolve(Scope* scope) + { + _left.resolve(scope); + StructuredType t = _left.type().rValue(); + if (!t.valid()) + _left.span().throwError("Expression has no members"); + _right.resolve(t.scope()); + } + bool mightHaveSideEffect() const + { + return _left.mightHaveSideEffect(); + } + private: + ExpressionT _left; + IdentifierT _right; + }; +}; + +template class NumericLiteralT : public Expression +{ +public: + NumericLiteralT(Rational n, Span span = Span()) + : Expression(create(n, span)) { } + NumericLiteralT(const Expression& e) : Expression(e) { } + int value() const { return as()->value(); } + + class Body : public Expression::Body + { + public: + Body(Rational n, const Span& span) : Expression::Body(span), _n(n) { } + String toString() const + { + return decimal(_n.numerator) + "/" + decimal(_n.denominator); + } + ValueT evaluate(Structure* context) const { return _n; } + Rational value() const { return _n; } + TypeT type() const + { + if (_n.denominator == 1) + return IntegerTypeT(); + return RationalTypeT(); + } + void resolve(Scope* scope) { } + bool mightHaveSideEffect() const { return false; } + private: + Rational _n; + }; +}; + +template class FuncoT; +typedef FuncoT Funco; + +template class FunctionCallExpressionT : public Expression +{ +public: + FunctionCallExpressionT(Handle other) : Expression(other) { } + + static List parseList(CharacterSource* source) + { + List list; + Expression expression = Expression::parse(source); + if (!expression.valid()) + return list; + list.add(expression); + Span span; + while (Space::parseCharacter(source, ',', &span)) + list.add(parseOrFail(source)); + return list; + } + + static Expression parseConstructorCall(CharacterSource* source) + { + TycoSpecifier t = TycoSpecifier::parse(source); + if (!t.valid()) + return Expression(); + Span span; + if (!Space::parseCharacter(source, '(', &span)) + return Expression(); + List arguments = parseList(source); + Space::assertCharacter(source, ')', &span); + return parseRemainder( + create(t, arguments, t.span() + span), + source); + } + + static Expression parse(CharacterSource* source) + { + Expression e = parseElement(source); + if (!e.valid()) + return e; + return parseRemainder(e, source); + } + + static Expression parsePower(CharacterSource* source) + { + Expression expression = Expression::parseDot(source); + if (!expression.valid()) + return expression; + Span span; + Operator o = OperatorPower().parse(source, &span); + if (o.valid()) { + Expression right = parsePower(source); + if (!right.valid()) + throwError(source); + expression = binary(o, span, expression, right); + } + return expression; + } + + static Expression parseUnary(CharacterSource* source) + { + static const Operator ops[] = { + OperatorTwiddle(), OperatorNot(), OperatorPlus(), OperatorMinus(), + OperatorStar(), OperatorAmpersand(), Operator()}; + const Operator* op = ops; + for (const Operator* op = ops; op->valid(); ++op) { + Span span; + Operator o = op->parse(source, &span); + if (o.valid()) { + Expression inner = parseUnary(source); + if (!inner.valid()) + return inner; + return unary(o, span, inner); + } + } + return parsePower(source); + } + + static Expression parseHelper(CharacterSource* source, const Operator* ops, + Expression (*parser)(CharacterSource* source)) + { + Expression expression = parser(source); + if (!expression.valid()) + return expression; + const Operator* op = ops; + do { + Span span; + Operator o; + do { + o = op->parse(source, &span); + if (o.valid()) + break; + ++op; + if (!op->valid()) + return expression; + } while (true); + Expression right = parser(source); + if (!right.valid()) + throwError(source); + expression = binary(o, span, expression, right); + op = ops; + } while (true); + assert(false); + return Expression(); + } + + static Expression parseMultiplicative(CharacterSource* source) + { + static const Operator ops[] = { + OperatorStar(), OperatorDivide(), OperatorModulo(), Operator()}; + return parseHelper(source, ops, parseUnary); + } + + static Expression parseAdditive(CharacterSource* source) + { + static const Operator ops[] = { + OperatorPlus(), OperatorMinus(), Operator()}; + return parseHelper(source, ops, parseMultiplicative); + } + + static Expression parseShift(CharacterSource* source) + { + static const Operator ops[] = { + OperatorShiftLeft(), OperatorShiftRight(), Operator()}; + return parseHelper(source, ops, parseAdditive); + } + + static Expression parseComparison(CharacterSource* source) + { + static const Operator ops[] = { + OperatorLessThanOrEqualTo(), OperatorGreaterThanOrEqualTo(), + OperatorLessThan(), OperatorGreaterThan(), Operator()}; + return parseHelper(source, ops, parseShift); + } + + static Expression parseEquality(CharacterSource* source) + { + static const Operator ops[] = { + OperatorEqualTo(), OperatorNotEqualTo(), Operator()}; + return parseHelper(source, ops, parseComparison); + } + + static Expression parseBitwiseAnd(CharacterSource* source) + { + static const Operator ops[] = { OperatorAmpersand(), Operator()}; + return parseHelper(source, ops, parseEquality); + } + + static Expression parseXor(CharacterSource* source) + { + static const Operator ops[] = { OperatorTwiddle(), Operator()}; + return parseHelper(source, ops, parseBitwiseAnd); + } + + static Expression parseBitwiseOr(CharacterSource* source) + { + static const Operator ops[] = { OperatorBitwiseOr(), Operator()}; + return parseHelper(source, ops, parseXor); + } + + static FunctionCallExpression unary(const Operator& op, const Span& span, + const Expression& expression) + { + Identifier identifier(op, span); + List arguments; + arguments.add(expression); + return create(identifier, arguments, + span + expression.span()); + } + + static FunctionCallExpression binary(const Operator& op, const Span& span, + const Expression& left, const Expression& right) + { + Identifier identifier(op, span); + List arguments; + arguments.add(left); + arguments.add(right); + return create(identifier, arguments, + left.span() + right.span()); + } + + class Body : public Expression::Body + { + protected: + Body(const Span& span, const List& arguments) + : Expression::Body(span), _arguments(arguments) { } + void resolve(Scope* scope) + { + for (auto e : _arguments) { + e.resolve(scope); + _argumentTypes.add(e.type()); + } + } + String toString() const + { + String r = "("; + bool first = true; + for (auto e : _arguments) { + if (!first) + r += ", "; + first = false; + r += e.toString(); + } + return r + ")"; + } + + List _arguments; + List _argumentTypes; + }; + + class FunctionCallBody : public Body + { + public: + FunctionCallBody(const Expression& function, + const List& arguments, const Span& span) + : Body(span, arguments), _function(function) { } + ValueT evaluate(Structure* context) const + { + ValueT l; + if (!_resolvedFunco.valid()) + l = _function.evaluate(context).rValue(); + List arguments; + for (auto p : this->_arguments) + arguments.add(p.evaluate(context).rValue()); + if (_resolvedFunco.valid()) + return _resolvedFunco.evaluate(arguments, this->span()); + TypeT lType = l.type(); + if (lType == FuncoTypeT()) { + return l.template value().evaluate( + arguments, this->span()); + } + // What we have on the left isn't a function, try to call its + // operator() method instead. + IdentifierT i = IdentifierT(OperatorFunctionCall()); + if (!lType.member(i).valid()) + this->span().throwError("Expression is not a function."); + if (!LValueTypeT(lType).valid()) { + auto m = l.template value>(); + l = m[i]; + l = Value(l.type(), l.value(), this->span()); + } + else { + StructureT* p = l.template + value().rValue().template value(); + l = Value(LValueTypeT::wrap(p->getValue(i).type()), + LValue(p, i), this->span()); + } + List convertedArguments; + Function f = l.template value(); + List parameterTycos = f.parameterTycos(); + auto ii = parameterTycos.begin(); + for (auto a : arguments) { + Type type = *ii; + if (!type.valid()) { + a.span().throwError("Function parameter's type " + "constructor is not a type."); + } + convertedArguments.add(a.convertTo(type)); + ++ii; + } + return f.evaluate(convertedArguments, this->span()); + } + TypeT type() const { return _resolvedFunco.type().returnType(); } + String toString() const + { + return _function.toString() + Body::toString(); + } + void resolve(ScopeT* scope) + { + Body::resolve(scope); + Identifier i = _function; + if (!i.valid()) { + _function.resolve(scope); + return; + } + _resolvedFunco = scope->resolveFunction(i, this->_argumentTypes); + } + // TODO: check if it's a pure function + bool mightHaveSideEffect() const { return true; } + private: + Expression _function; + Funco _resolvedFunco; + }; + + class ConstructorCallBody : public Body + { + public: + ConstructorCallBody(const TycoSpecifier& tycoSpecifier, + const List& arguments, const Span& span) + : Body(span, arguments), _tycoSpecifier(tycoSpecifier) { } + ValueT evaluate(Structure* context) const + { + List> arguments; + for (auto p : this->_arguments) + arguments.add(p.evaluate(context)); + + StructuredTypeT type = _type; + if (!type.valid()) { + _tycoSpecifier.span().throwError( + "Only structure types can be constructed at the moment."); + } + auto members = type.members(); + List values; + Span span = _tycoSpecifier.span(); + auto ai = arguments.begin(); + for (int i = 0; i < members.count(); ++i) { + ValueT value = ai->convertTo(members[i].type()); + values.add(value.value()); + span += value.span(); + ++ai; + } + return type.constructValue(Value(type, values, span)); + } + TypeT type() const { return _type; } + String toString() const { return _type.toString() + Body::toString(); } + void resolve(ScopeT* scope) + { + Body::resolve(scope); + _type = scope->resolveType(_tycoSpecifier); + } + bool mightHaveSideEffect() const { return true; } + private: + TycoSpecifier _tycoSpecifier; + Type _type; + }; +private: + static Expression parseRemainder(Expression e, CharacterSource* source) + { + do { + Span span; + if (Space::parseCharacter(source, '(', &span)) { + List arguments = parseList(source); + Space::assertCharacter(source, ')', &span); + e = FunctionCallExpression( + create(e, arguments, e.span() + span)); + } + else + if (Space::parseCharacter(source, '[', &span)) { + Span span2; + Expression index = Expression::parse(source); + Space::assertCharacter(source, ']', &span2); + e = binary(OperatorIndex(), span + span2, e, index); + } + else + break; + + } while (true); + return e; + } + + template friend class ExpressionT; +}; + +template class VariableDefinitionT : public Expression +{ +public: + static VariableDefinitionT parse(CharacterSource* source) + { + CharacterSource s = *source; + TycoSpecifier t = TycoSpecifier::parse(&s); + if (!t.valid()) + return VariableDefinitionT(); + Identifier i = Identifier::parse(&s); + if (!i.valid()) + return VariableDefinitionT(); + *source = s; + Expression e; + Span span = t.span() + i.span(); + if (Space::parseCharacter(&s, '=', &span)) { + e = Expression::parse(&s); + if (e.valid()) { + *source = s; + span += e.span(); + } + } + return create(t, i, e, span); + } + VariableDefinitionT() { } + VariableDefinitionT(TycoSpecifier tycoSpecifier, Identifier identifier) + : Expression(create(tycoSpecifier, identifier, Expression(), + Span())) + { } + VariableDefinitionT(TypeT type, Identifier identifier) + : Expression(create(type, identifier, Expression(), Span())) + { } + IdentifierT identifier() const { return body()->identifier(); } +private: + VariableDefinitionT(Handle other) : Expression(other) { } + + class Body : public Expression::Body + { + public: + Body(TycoSpecifier tycoSpecifier, Identifier identifier, + Expression initializer, Span span) + : Expression::Body(span), _tycoSpecifier(tycoSpecifier), + _identifier(identifier), _initializer(initializer) + { } + Body(TypeT type, Identifier identifier, Expression initializer, + Span span) + : Expression::Body(span), _type(type), _identifier(identifier), + _initializer(initializer) + { } + String toString() const + { + String r = _tycoSpecifier.toString() + " " + + _identifier.toString(); + if (_initializer.valid()) + r += " = " + _initializer.toString(); + return r; + } + ValueT evaluate(Structure* context) const + { + ValueT e = _initializer.evaluate(context); + return e.convertTo(_type); + } + TypeT type() const { return _type; } + void resolve(ScopeT* scope) + { + if (!_type.valid()) + _type = _tycoSpecifier.resolve(scope); + _initializer.resolve(scope); + _scope.setParentScope(scope); + _scope.setFunctionScope(scope->functionScope()); + } + bool mightHaveSideEffect() const { return true; } + IdentifierT identifier() const { return _identifier; } + private: + TycoSpecifier _tycoSpecifier; + TypeT _type; + Identifier _identifier; + Expression _initializer; + Scope _scope; + }; + + const Body* body() const { return as(); } +}; + +template class BinaryExpressionT : public Expression +{ +protected: + class Body : public Expression::Body + { + public: + Body(const Expression& left, const Span& operatorSpan, + const Expression& right) + : Expression::Body(left.span() + right.span()), + _left(left), _right(right), _operatorSpan(operatorSpan) { } + Expression left() const { return _left; } + Expression right() const { return _right; } + void resolve(const Scope* scope) + { + _left.resolve(scope); + _right.resolve(scope); + } + TypeT type() const { return BooleanTypeT(); } + bool mightHaveSideEffect() const + { + return _left.mightHaveSideEffect() || _right.mightHaveSideEffect(); + } + void resolve(Scope* scope) + { + _left.resolve(scope); + _right.resolve(scope); + } + private: + Expression _left; + Expression _right; + Span _operatorSpan; + }; +}; + +typedef BinaryExpressionT BinaryExpression; + +template class LogicalAndExpressionT; +typedef LogicalAndExpressionT LogicalAndExpression; + +template class LogicalAndExpressionT : public BinaryExpression +{ +public: + static Expression parse(CharacterSource* source) + { + Expression e = FunctionCallExpression::parseBitwiseOr(source); + if (!e.valid()) + return e; + do { + Span span; + if (Space::parseOperator(source, "&&", &span)) { + Expression e2 = FunctionCallExpression::parseBitwiseOr(source); + if (!e2.valid()) + throwError(source); + e = create(e, span, e2); + continue; + } + return e; + } while (true); + } +private: + class Body : public BinaryExpression::Body + { + public: + Body(const Expression& left, const Span& operatorSpan, + const Expression& right) + : BinaryExpression::Body(left, operatorSpan, right) { } + ValueT evaluate(Structure* context) const + { + ValueT v = left().evaluate(context); + if (v.type() != BooleanTypeT()) { + left().span().throwError("Logical operator requires operand " + "of type Boolean."); + } + if (!v.template value()) + return false; + v = right().evaluate(context); + if (v.type() != BooleanTypeT()) { + right().span().throwError("Logical operator requires operand " + "of type Boolean."); + } + return v.template value(); + } + String toString() const + { + return "(" + left().toString() + " && " + right().toString() + ")"; + } + Expression stringify() const + { + return ConditionalExpressionT(left(), right().stringify(), + Expression("false", Span())); + } + }; +}; + +template class LogicalOrExpressionT : public BinaryExpression +{ +public: + static Expression parse(CharacterSource* source) + { + Expression e = LogicalAndExpression::parse(source); + if (!e.valid()) + return e; + do { + Span span; + if (Space::parseOperator(source, "||", &span)) { + Expression e2 = LogicalAndExpression::parse(source); + if (!e2.valid()) + throwError(source); + e = create(e, span, e2); + continue; + } + return e; + } while (true); + } +private: + class Body : public BinaryExpression::Body + { + public: + Body(const Expression& left, const Span& operatorSpan, + const Expression& right) + : BinaryExpression::Body(left, operatorSpan, right) { } + ValueT evaluate(Structure* context) const + { + ValueT v = left().evaluate(context); + if (v.type() != BooleanTypeT()) { + left().span().throwError("Logical operator requires operand " + "of type Boolean."); + } + if (!v.template value()) + return false; + v = right().evaluate(context); + if (v.type() != BooleanTypeT()) { + right().span().throwError("Logical operator requires operand " + "of type Boolean."); + } + return v.template value(); + } + String toString() const + { + return "(" + left().toString() + " && " + right().toString() + ")"; + } + Expression stringify() const + { + return ConditionalExpressionT(left(), + Expression("true", Span()), right().stringify()); + } + }; +}; + +template class ConditionalExpressionT : public Expression +{ +public: + static Expression parse(CharacterSource* source) + { + Expression e = LogicalOrExpression::parse(source); + if (!e.valid()) + return e; + Span span1; + if (Space::parseOperator(source, "?", &span1)) { + Expression trueExpression = parse(source); + if (!trueExpression.valid()) + source->throwUnexpected("expression"); + Span span2; + if (!Space::parseOperator(source, ":", &span2)) + source->throwUnexpected(":"); + Expression falseExpression = parse(source); + if (!falseExpression.valid()) + source->throwUnexpected("expression"); + e = create(e, span1, trueExpression, span2, falseExpression); + } + return e; + } + ConditionalExpressionT(Expression condition, Expression trueExpression, + Expression falseExpression) + : Expression(create(condition, Span(), trueExpression, Span(), + falseExpression)) + { } +private: + class Body : public Expression::Body + { + public: + Body(const Expression& condition, const Span& s1, + const Expression& trueExpression, const Span& s2, + const Expression& falseExpression) + : Expression::Body(condition.span() + falseExpression.span()), + _condition(condition), _s1(s1), _trueExpression(trueExpression), + _s2(s2), _falseExpression(falseExpression) + { } + ValueT evaluate(Structure* context) const + { + ValueT v = _condition.evaluate(context).rValue(); + if (v.type() != BooleanTypeT()) { + _condition.span().throwError("Conditional operator requires " + "operand of type Boolean."); + } + if (v.template value()) + return _trueExpression.evaluate(context); + return _falseExpression.evaluate(context); + } + TypeT type() const + { + TypeT tt = _trueExpression.type(); + TypeT ft = _falseExpression.type(); + if (tt != ft) { + span().throwError("True expression has type " + tt.toString() + + " and false expression has type " + ft.toString() + "."); + } + return _trueExpression.type(); + } + bool mightHaveSideEffect() const + { + return _condition.mightHaveSideEffect() || + _trueExpression.mightHaveSideEffect() || + _falseExpression.mightHaveSideEffect(); + } + String toString() const + { + return "(" + _condition.toString() + " ? " + + _trueExpression.toString() + " : " + + _falseExpression.toString() + ")"; + } + void resolve(Scope* scope) + { + _condition.resolve(scope); + _trueExpression.resolve(scope); + _falseExpression.resolve(scope); + } + private: + Expression _condition; + Span _s1; + Expression _trueExpression; + Span _s2; + Expression _falseExpression; + }; +}; + +#endif // INCLUDED_EXPRESSION_H diff --git a/80386/disassembler/include/alfe/fcolour.h b/80386/disassembler/include/alfe/fcolour.h new file mode 100644 index 0000000..efebdcd --- /dev/null +++ b/80386/disassembler/include/alfe/fcolour.h @@ -0,0 +1,104 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_FCOLOUR_H +#define INCLUDED_FCOLOUR_H + +#include "alfe/fix.h" + +typedef Fixed<8, Word> UFix8p8; + +class FColour +{ +public: + FColour() { } + FColour(const FColour& x) : _r(x._r), _g(x._g), _b(x._b) { } + const FColour& operator=(const FColour& x) + { + _r = x._r; + _g = x._g; + _b = x._b; + return *this; + } + const FColour& operator+=(const FColour& x) + { + _r += x._r; + _g += x._g; + _b += x._b; + return *this; + } + const FColour& operator-=(const FColour& x) + { + _r -= x._r; + _g -= x._g; + _b -= x._b; + return *this; + } + const FColour& operator*=(const UFix8p8& x) + { + _r *= x; + _g *= x; + _b *= x; + return *this; + } + const FColour& operator/=(const UFix8p8& x) + { + _r /= x; + _g /= x; + _b /= x; + return *this; + } + const FColour& operator<<=(int n) + { + _r <<= n; + _g <<= n; + _b <<= n; + return *this; + } + const FColour& operator>>=(int n) + { + _r >>= n; + _g >>= n; + _b >>= n; + return *this; + } + FColour operator+(const FColour& x) const + { + FColour y = *this; + return y += x; + } + FColour operator-(const FColour& x) const + { + FColour y = *this; + return y -= x; + } + FColour operator*(const UFix8p8& x) const + { + FColour y = *this; + return y *= x; + } + FColour operator/(const UFix8p8& x) const + { + FColour y = *this; + return y /= x; + } + FColour operator<<(int n) const { FColour y = *this; return y <<= n; } + FColour operator>>(int n) const { FColour y = *this; return y >>= n; } + + DWord asDWord() const + { + return 0xff000000 + | (static_cast(_r.intPart()) ) + | (static_cast(_g.intPart())<< 8) + | (static_cast(_b.intPart())<<16); + } + + static FColour black() { return FColour(0, 0, 0); } + static FColour white() { return FColour(255, 255, 255); } + FColour(UFix8p8 r, UFix8p8 g, UFix8p8 b) : _r(r), _g(g), _b(b) { } +protected: + UFix8p8 _r; + UFix8p8 _g; + UFix8p8 _b; +}; + +#endif // INCLUDED_FCOLOUR_H diff --git a/80386/disassembler/include/alfe/fft.h b/80386/disassembler/include/alfe/fft.h new file mode 100644 index 0000000..91b4ad5 --- /dev/null +++ b/80386/disassembler/include/alfe/fft.h @@ -0,0 +1,189 @@ +#include "alfe/main.h" +#include "alfe/complex.h" + +#ifndef INCLUDED_FFT_H +#define INCLUDED_FFT_H + +#include "fftw3.h" + +template struct FFTW; + +template<> struct FFTW +{ + typedef float Real; + typedef fftwf_complex Complex; + typedef fftwf_plan Plan; + + static void execute(Plan p) { fftwf_execute(p); } + static Plan plan_dft_r2c_1d(int n, Real* in, Complex* out, unsigned flags) + { + return fftwf_plan_dft_r2c_1d(n, in, out, flags); + } + static Plan plan_dft_c2r_1d(int n, Complex* in, Real* out, unsigned flags) + { + return fftwf_plan_dft_c2r_1d(n, in, out, flags); + } + static void execute_dft_r2c(Plan p, Real* in, Complex* out) + { + fftwf_execute_dft_r2c(p, in, out); + } + static void execute_dft_c2r(Plan p, Complex* in, Real* out) + { + fftwf_execute_dft_c2r(p, in, out); + } + static void destroy_plan(Plan p) { fftwf_destroy_plan(p); } + static void cleanup(void) { fftwf_cleanup(); } + static int export_wisdom_to_filename(const char *filename) + { + return fftwf_export_wisdom_to_filename(filename); + } + static int import_wisdom_from_filename(const char *filename) + { + return fftwf_import_wisdom_from_filename(filename); + } + static void print_plan(Plan p) { fftwf_print_plan(p); } + static float* alloc_real(size_t n) { return fftwf_alloc_real(n); } + static Complex* alloc_complex(size_t n) { return fftwf_alloc_complex(n); } + static void free(void* p) { fftwf_free(p); } + static void flops(Plan p, double* add, double* mul, double* fmas) + { + return fftwf_flops(p, add, mul, fmas); + } +}; + +template class FFTWArray : public ConstHandle +{ +protected: + FFTWArray() { } + FFTWArray(const ConstHandle other) : ConstHandle(other) { } + struct Body : public ConstHandle::Body + { + Body(void* data, int n) : _data(data), _n(n) { } + ~Body() { FFTW::free(_data); } + void* _data; + int _n; + }; + + void* data() const { return body()->_data; } + int count() const { return body() == 0 ? 0 : body()->_n; } +private: + const Body* body() const { return as(); } +}; + +template class FFTWRealArray : public FFTWArray +{ +public: + FFTWRealArray() { } + FFTWRealArray(int n) + : FFTWArray(FFTWArray::create::Body>( + FFTW::alloc_real(n), n)) + { } + T& operator[](int i) { return data()[i]; } + const T& operator[](int i) const { return data()[i]; } + void ensure(int n) { if (this->count() < n) *this = FFTWRealArray(n); } +private: + T* data() const { return reinterpret_cast(FFTWArray::data()); } +}; + +template class FFTWComplexArray : public FFTWArray +{ +public: + FFTWComplexArray() { } + FFTWComplexArray(int n) + : FFTWArray(FFTWArray::create::Body>( + FFTW::alloc_complex(n), n)) { } + typename Complex& operator[](int i) + { + return reinterpret_cast*>(data())[i]; + } + const typename Complex& operator[](int i) const + { + return reinterpret_cast*>(data())[i]; + } + void ensure(int n) { if (this->count() < n) *this = FFTWComplexArray(n); } + typename FFTW::Complex* data() const + { + return reinterpret_cast::Complex*>( + FFTWArray::data()); + } +}; + +template class FFTWPlan : public ConstHandle +{ +public: + FFTWPlan() { } + void execute() { FFTW::execute(plan()); } + void print() + { + FFTW::print_plan(plan()); + double add,mul,fmas; + FFTW::flops(plan(), &add, &mul, &fmas); + printf("\n%lf adds, %lf muls, %lf fmas\n", add, mul, fmas); + } +protected: + FFTWPlan(typename FFTW::Plan plan) : ConstHandle(create(plan)) { } + typename FFTW::Plan plan() { return as()->_plan; } +private: + struct Body : public ConstHandle::Body + { + Body(typename FFTW::Plan plan) : _plan(plan) { } + ~Body() { FFTW::destroy_plan(_plan); } + typename FFTW::Plan _plan; + }; +}; + +template class FFTWPlanDFTR2C1D : public FFTWPlan +{ +public: + FFTWPlanDFTR2C1D() { } + FFTWPlanDFTR2C1D(int n, int rigor) + : FFTWPlanDFTR2C1D(n, FFTWRealArray(n), FFTWComplexArray(n/2 + 1), + rigor) + { } + FFTWPlanDFTR2C1D(int n, FFTWRealArray in, FFTWComplexArray out, + int rigor) + : FFTWPlan(FFTW::plan_dft_r2c_1d(n, &in[0], out.data(), rigor)) { } + void execute() { FFTWPlan::execute(); } + void execute(FFTWRealArray in, FFTWComplexArray out) + { + FFTW::execute_dft_r2c(this->plan(), &in[0], out.data()); + } +}; + +template class FFTWPlanDFTC2R1D : public FFTWPlan +{ +public: + FFTWPlanDFTC2R1D() { } + FFTWPlanDFTC2R1D(int n, int rigor) + : FFTWPlanDFTC2R1D(n, FFTWComplexArray(n/2 + 1), FFTWRealArray(n), + rigor) + { } + FFTWPlanDFTC2R1D(int n, FFTWComplexArray in, FFTWRealArray out, + int rigor) + : FFTWPlan(FFTW::plan_dft_c2r_1d(n, in.data(), &out[0], rigor)) { } + void execute() { FFTWPlan::execute(); } + void execute(FFTWComplexArray in, FFTWRealArray out) + { + FFTW::execute_dft_c2r(this->plan(), in.data(), &out[0]); + } +}; + +template class FFTWWisdom +{ +public: + FFTWWisdom(File wisdom) : _wisdom(wisdom) + { + NullTerminatedString data(_wisdom.path()); + FFTW::import_wisdom_from_filename(data); + } + ~FFTWWisdom() + { + NullTerminatedString data(_wisdom.path()); + FFTW::export_wisdom_to_filename(data); + FFTW::cleanup(); + } +private: + File _wisdom; +}; + +#endif // INCLUDED_FFT_H diff --git a/80386/disassembler/include/alfe/file.h b/80386/disassembler/include/alfe/file.h new file mode 100644 index 0000000..5b08ec1 --- /dev/null +++ b/80386/disassembler/include/alfe/file.h @@ -0,0 +1,943 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_FILE_H +#define INCLUDED_FILE_H + +template class CurrentDirectoryT; +typedef CurrentDirectoryT CurrentDirectory; + +template class FileSystemObjectT; +typedef FileSystemObjectT FileSystemObject; + +template class FindHandleT; +typedef FindHandleT FindHandle; + +template class DirectoryT; +typedef DirectoryT Directory; + +template class FileT; +typedef FileT File; + +template class RootDirectoryT; +typedef RootDirectoryT RootDirectory; + +#ifdef _WIN32 +template class DriveRootDirectoryT; +typedef DriveRootDirectoryT DriveRootDirectory; + +template class UNCRootDirectoryT; +typedef UNCRootDirectoryT UNCRootDirectory; + +template class DriveCurrentDirectoryT; +typedef DriveCurrentDirectoryT DriveCurrentDirectory; +#endif + +template class CharacterSourceT; +typedef CharacterSourceT CharacterSource; + +template class FileSystemObjectT : public ConstHandle +{ +public: + FileSystemObjectT() { } + FileSystemObjectT(const ConstHandle& other) : ConstHandle(other) { } + FileSystemObjectT(const String& path, + const DirectoryT& relativeTo = CurrentDirectoryT(), + bool windowsParsing = false) + { + *this = FileSystemObject::parse(path, relativeTo, windowsParsing); + } + + DirectoryT parent() const { return body()->parent(); } + String name() const { return body()->name(); } + bool isRoot() const { return body()->isRoot(); } + String path() const + { + if (!valid()) + return "(unknown path)"; + return body()->path(); + } + + class Body : public ConstHandle::Body + { + public: + virtual DirectoryT parent() const = 0; + virtual String name() const = 0; + virtual String path() const = 0; + virtual bool isRoot() const = 0; + }; + bool exists() + { +#ifdef _WIN32 + NullTerminatedWideString data(path()); + DWORD dwAttr = GetFileAttributes(data); + if (dwAttr == 0xffffffff) { + DWORD dwError = GetLastError(); + if (dwError == ERROR_FILE_NOT_FOUND) + return false; + if (dwError == ERROR_PATH_NOT_FOUND) + return false; + IF_ZERO_CHECK_THROW_LAST_ERROR(0); + } + return true; +#else + NullTerminatedString data(path()); + return access(data, F_OK) == 0; +#endif + } +protected: + const Body* body() const { return as(); } + + class NamedBody : public Body + { + public: + NamedBody(const Directory& parent, const String& name) + : _parent(parent), _name(name) { } +#ifdef _WIN32 + String path() const + { + return _parent.path() + "\\" + _name; + } +#else + String path() const + { + return _parent.path() + "/" + _name; + } +#endif + DirectoryT parent() const { return _parent; } + String name() const { return _name; } + bool isRoot() const { return false; } + Hash hash() const + { + return Body::hash().mixin(_parent.hash()).mixin(_name.hash()); + } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _parent == o->_parent & _name == o->_name; + } + private: + DirectoryT _parent; + String _name; + }; + +private: + static FileSystemObject parse(const String& path, + const Directory& relativeTo, bool windowsParsing) + { + if (path.empty()) + throw Exception("Invalid path"); + +#ifdef _WIN32 + if (windowsParsing) + return windowsParse(path, relativeTo); +#endif + return parse(path, relativeTo); + } + +#ifdef _WIN32 + static DirectoryT windowsParseRoot(const String& path, + const Directory& relativeTo, CharacterSource& s) + { + CharacterSourceT s2 = s; + int c = s2.get(); + DirectoryT dir = relativeTo; + + // Process initial slashes + if (c == '/' || c == '\\') { + s = s2; + dir = RootDirectoryT(); + c = s2.get(); + if (c == -1) + return dir; + if (c == '/' || c == '\\') { + int serverStart = s2.offset(); + int p; + do { + p = s2.offset(); + c = s2.get(); + if (c == -1) + throw Exception("Invalid path"); + // TODO: What characters are actually legal in server + // names? + } while (c != '\\' && c != '/'); + String server = s2.subString(serverStart, p); + int shareStart; + do { + shareStart = s2.offset(); + c = s2.get(); + } while (c == '/' || c == '\\'); + do { + p = s2.offset(); + c = s2.get(); + // TODO: What characters are actually legal in share names? + } while (c != '\\' && c != '/' && c != -1); + String share = s2.subString(shareStart, p); + dir = UNCRootDirectory(server, share); + do { + s = s2; + c = s2.get(); + } while (c == '/' || c == '\\'); + } + // TODO: In paths starting \\?\, only \ and \\ are allowed + // separators, and ?*:"<> are allowed. See + // http://docs.racket-lang.org/reference/windowspaths.html for more + // details. + return dir; + } + int drive = (c >= 'a' ? (c - 'a') : (c - 'A')); + if (drive < 0 || drive >= 26) + return dir; + c = s2.get(); + if (c != ':') + return dir; + s = s2; + c = s2.get(); + if (c == '/' || c == '\\') { + dir = DriveRootDirectory(drive); + while (c == '/' || c == '\\') { + s = s2; + c = s2.get(); + } + return dir; + } + return DriveCurrentDirectory(drive); + } + + static FileSystemObject windowsParse(const String& path, + const Directory& relativeTo) + { + CharacterSourceT s(path); + DirectoryT dir = windowsParseRoot(path, relativeTo, s); + int subDirectoryStart = s.offset(); + int c = s.get(); + + String name; + do { + if (c == -1) + break; + int p; + while (c != '/' && c != '\\') { + if (c < 32 || c == '?' || c == '*' || c == ':' || c == '"' || + c == '<' || c == '>') + throw Exception("Invalid path"); + p = s.offset(); + c = s.get(); + if (c == -1) + break; + } + name = s.subString(subDirectoryStart, p); + if (name == ".") + name = ""; + if (name == "..") { + dir = dir.parent(); + name = ""; + } + if (name != "") { + int l = name[name.length() - 1]; + if (l == '.' || l == ' ') + throw Exception("Invalid path"); + } + if (c == -1) + break; + while (c == '/' || c == '\\') { + subDirectoryStart = s.offset(); + c = s.get(); + if (c == -1) + break; + } + if (c == -1) + break; + if (name != "") + dir = dir.subDirectory(name); + } while (true); + if (name == "") { + if (dir.isRoot()) + return dir; + return FileSystemObject(dir.parent(), dir.name()); + } + return FileSystemObject(dir, name); + } +#endif + + static DirectoryT parseRoot(const String& path, + const DirectoryT& relativeTo, CharacterSource& s) + { + CharacterSourceT s2 = s; + int c = s2.get(); + Directory dir = relativeTo; + + // Process initial slashes + if (c == '/') { + dir = RootDirectoryT(); + while (c == '/') { + s = s2; + c = s2.get(); + } + } + return dir; + } + + static FileSystemObject parse(const String& path, + const Directory& relativeTo) + { + CharacterSourceT s(path); + DirectoryT dir = parseRoot(path, relativeTo, s); + int subDirectoryStart = s.offset(); + int c = s.get(); + + String name; + do { + int p; + while (c != '/') { + if (c == 0) + throw Exception("Invalid path"); + p = s.offset(); + c = s.get(); + if (c == -1) + break; + } + name = s.subString(subDirectoryStart, p); + if (name == String(".")) + name = String(); + if (name == String("..")) { + dir = dir.parent(); + name = String(); + } + if (c == -1) + break; + while (c == '/') { + subDirectoryStart = s.offset(); + c = s.get(); + if (c == -1) + break; + } + if (c == -1) + break; + if (name != "") + dir = dir.subDirectory(name); + } while (true); + if (name == "") { + if (dir.isRoot()) + return dir; + return FileSystemObject(dir.parent(), dir.name()); + } + return FileSystemObject(dir, name); + } + + FileSystemObjectT(const DirectoryT& parent, const String& name) + : ConstHandle(create(parent, name)) { } + + friend class NamedBody; + template friend class CurrentDirectoryT; + template friend class DirectoryT; + friend class Console; + + template friend void applyToWildcard(U& functor, + const String& wildcard, int recurseIntoDirectories, + const DirectoryT& relativeTo); +}; + +template class DirectoryT : public FileSystemObject +{ +public: + DirectoryT() { } + DirectoryT(const ConstHandle& other) : FileSystemObject(other) { } + + DirectoryT(const String& path, + const Directory& relativeTo = CurrentDirectoryT(), + bool windowsParsing = false) + : FileSystemObject(path, relativeTo, windowsParsing) { } + DirectoryT(const String& path, bool windowsParsing) + : FileSystemObject(path, CurrentDirectoryT(), windowsParsing) { } + + FileSystemObject child(const String& name) const + { + return FileSystemObject(*this, name); + } + Directory subDirectory(const String& subDirectoryName) const + { + return Directory(child(subDirectoryName)); + } + FileT file(const String& fileName) const + { + return File(child(fileName)); + } + template void applyToContents(F& functor, bool recursive, + const String& wildcard = "*") const + { + FindHandleT handle(*this, wildcard); + while (!handle.complete()) { + if (handle.isDirectory()) { + if (!handle.isSymlink()) { + Directory child = handle.directory(); + if (recursive) + child.applyToContents(functor, true); + else + functor(child); + } + } + else + functor(handle.file()); + handle.next(); + } + } +}; + +// This is the current directory at the time of first instantiation - avoid +// changing the current directory. +template class CurrentDirectoryT : public Directory +{ +public: + CurrentDirectoryT() : Directory(directory()) { } +private: + CurrentDirectoryT(const FileSystemObject& other) + : Directory(other) { } + static CurrentDirectory directory() + { + static CurrentDirectory d = currentDirectory(); + return d; + } + + static CurrentDirectory currentDirectory() + { +#ifdef _WIN32 + int n = GetCurrentDirectory(0, NULL); + if (n == 0) + throw Exception::systemError("Obtaining current directory"); + Array buf(n); + if (GetCurrentDirectory(n, &buf[0]) == 0) + throw Exception::systemError("Obtaining current directory"); + String path(&buf[0]); + return FileSystemObject::parse(path, RootDirectoryT(), true); +#else + size_t size = 100; + do { + String buffer(size); + char* p = reinterpret_cast(buffer.data()); + if (getcwd(p, size) != 0) { + String path = buffer.subString(0, strlen(p)); + return FileSystemObject::parse(path, RootDirectory(), false); + } + if (errno != ERANGE) + throw Exception::systemError("Obtaining current directory"); + size *= 2; + } while (true); +#endif + } + +#ifdef _WIN32 + template friend class DriveCurrentDirectoryT; +#endif +}; + +#ifdef _WIN32 +template class DriveCurrentDirectoryT : public Directory +{ +public: + DriveCurrentDirectoryT() { } + DriveCurrentDirectoryT(int drive) : Directory(directory(drive)) { } +private: + static Directory _directories[26]; + static Directory directory(int drive) + { + if (!_directories[drive].valid()) { + // Make sure the current directory has been retrieved + CurrentDirectory(); + + // Change to this drive + WCHAR buf[3]; + buf[0] = drive + 'A'; + buf[1] = ':'; + buf[2] = 0; + if (SetCurrentDirectory(&buf[0]) == 0) + throw Exception::systemError("Setting current directory"); + + // Retrieve current directory + _directories[drive] = CurrentDirectory::currentDirectory(); + } + return _directories[drive]; + } +}; + +Directory DriveCurrentDirectory::_directories[26]; + +#endif + +template class RootDirectoryT : public Directory +{ +public: + RootDirectoryT() : Directory(directory()) { } + RootDirectoryT(const ConstHandle& other) : Directory(other) { } + + class Body : public FileSystemObject::Body + { + public: + Body() { } + + Directory parent() const { return RootDirectory(); } + String name() const { return String(); } + String path() const + { +#ifdef _WIN32 + // TODO: Use \\?\ to avoid MAX_PATH limit? + // If we do this we need to know the current drive, which can be + // found from CurrentDirectory(). +#endif + return String(); + } + bool isRoot() const { return true; } + }; +private: + static RootDirectory directory() + { + static RootDirectory d = create(); + return d; + } +}; + + +#ifdef _WIN32 +template class DriveRootDirectoryT : public Directory +{ +public: + DriveRootDirectoryT() { } + DriveRootDirectoryT(int drive) : Directory(directory(drive)) { } + DriveRootDirectoryT(const ConstHandle& other) : Directory(other) { } +private: + static DriveRootDirectory _directories[26]; + static DriveRootDirectory directory(int drive) + { + if (!_directories[drive].valid()) + _directories[drive] = create(drive); + return _directories[drive]; + } + class Body : public RootDirectory::Body + { + public: + Body(int drive) : _drive(drive) { } + + Directory parent() const { return DriveRootDirectory(_drive); } + String path() const + { + // TODO: Use \\?\ to avoid MAX_PATH limit? + return codePoint('A' + _drive) + ":"; + } + + Hash hash() const { return RootDirectory::Body::hash().mixin(_drive); } + + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _drive == o->_drive; + } + private: + int _drive; + }; +}; + +DriveRootDirectory DriveRootDirectory::_directories[26]; + +template class UNCRootDirectoryT : public Directory +{ +public: + UNCRootDirectoryT(const String& server, const String& share) + : Directory(create(server, share)) { } +private: + class Body : public RootDirectory::Body + { + public: + Body(const String& server, const String& share) + : _server(server), _share(share) { } + + Directory parent() const { return UNCRootDirectory(_server, _share); } + String path() const { return "\\\\" + _server + "\\" + _share; } + + Hash hash() const + { + return RootDirectory::Body::hash().mixin(_server.hash()). + mixin(_share.hash()); + } + + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _server == o->_server && _share == o->_share; + } + private: + String _server; + String _share; + }; +}; +#endif + +template class FileStreamT; +typedef FileStreamT FileStream; + +template class FileT : public FileSystemObject +{ +public: + FileT() { } + FileT(const ConstHandle& other) : FileSystemObject(other) { } + FileT(const String& path, + const Directory& relativeTo = CurrentDirectory(), + bool windowsParsing = false) + : FileSystemObject(path, relativeTo, windowsParsing) { } + + FileT(const String& path, bool windowsParsing) + : FileSystemObject(path, CurrentDirectory(), windowsParsing) { } + + String contents() const + { + FileStreamT f = openRead(); + UInt64 size = f.size(); + if (size >= 0x80000000) + throw Exception("2Gb or more in file " + path()); + int intSize = static_cast(size); + String buffer(intSize); + f.read(buffer.data(), intSize); + return buffer; + } + template void readIntoArray(Array* array) + { + FileStreamT f = openRead(); + UInt64 size = f.size(); + if (size >= 0x80000000) + throw Exception("2Gb or more in file " + path()); + int intSize = static_cast(size); + int n = intSize/sizeof(U); + array->allocate(n); + f.read(&(*array)[0], n*sizeof(U)); + } + + template void save(const U& contents) const + { + openWrite().write(contents); + } + void save(const Byte* data, int length) const + { + openWrite().write(data, length); + } + template void secureSave(const U& contents) const + { + // TODO: Backup file? + File temp; + { + FileStreamT f = openWriteTemporary(); + f.write(contents); +#ifndef _WIN32 + f.sync(); +#endif + temp = f.file(); + } +#ifdef _WIN32 + NullTerminatedWideString data(path()); + NullTerminatedWideString tempData(temp.path()); + if (ReplaceFile(data, tempData, NULL, REPLACEFILE_WRITE_THROUGH | + REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL) == 0) { + { + PreserveSystemError p; + DeleteFile(tempData); // Ignore any errors + } + throw Exception::systemError("Replacing file " + path()); + } +#else + NullTerminatedString data(path()); + NullTerminatedString tempData(temp.path()); + if (rename(tempData, data) != 0) { + { + PreserveSystemError p; + unlink(tempData); // Ignore any errors + } + throw Exception::systemError("Replacing file " + path()); + } +#endif + } + template void append(const U& contents) const + { + openAppend().write(contents); + } + FileStreamT openRead() const + { +#ifdef _WIN32 + return open(GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN); +#else + return open(O_RDONLY); +#endif + } + FileStreamT openWrite() const + { +#ifdef _WIN32 + return open(GENERIC_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL); +#else + return openWrite(O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); +#endif + } + FileStreamT tryOpenRead() const + { +#ifdef _WIN32 + return tryOpen(GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN); +#else + return tryOpen(O_RDONLY); +#endif + } + FileStreamT tryOpenWrite() const + { +#ifdef _WIN32 + return tryOpen(GENERIC_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL); +#else + return tryOpenWrite(O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); +#endif + } + FileStreamT openWriteTemporary() const + { + int i = 0; + do { + File temp = parent().file(name() + hex(i, 8, false)); +#ifdef _WIN32 + FileStreamT f = temp.open(GENERIC_WRITE, 0, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, false); +#else + FileStreamT f = temp.open(O_WRONLY | O_CREAT | O_EXCL, + false); +#endif + if (f.valid()) + return f; + ++i; + } while (true); + } + FileStreamT openAppend() const + { +#ifdef _WIN32 + return open(GENERIC_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL); +#else + return open(name(), O_WRONLY | O_APPEND); +#endif + } + void remove() + { +#ifdef _WIN32 + NullTerminatedWideString data(path()); + IF_ZERO_THROW(DeleteFile(data)); +#else + NullTerminatedString data(path()); + IF_MINUS_ONE_THROW(unlink(data)); +#endif + } +private: +#ifdef _WIN32 + FileStreamT open(DWORD dwDesiredAccess, DWORD dwShareMode, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, + bool throwIfExists = true) const + { + FileStream f = tryOpen(dwDesiredAccess, dwShareMode, + dwCreationDisposition, dwFlagsAndAttributes); + if (!f.valid() && + (throwIfExists || GetLastError() == ERROR_FILE_EXISTS)) + throw Exception::systemError("Opening file " + path()); + return f; + } + FileStreamT tryOpen(DWORD dwDesiredAccess, DWORD dwShareMode, + DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes) const + { + NullTerminatedWideString data(path()); + return FileStream(CreateFile( + data, // lpFileName + dwDesiredAccess, + dwShareMode, + NULL, // lpSecurityAttributes + dwCreationDisposition, + dwFlagsAndAttributes, + NULL), // hTemplateFile + *this); + } +public: + StreamT openPipe() + { + StreamT f = tryOpen(GENERIC_READ | GENERIC_WRITE, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); + if (!f.valid()) + throw Exception::systemError("Opening pipe " + path()); + return f; + } + StreamT createPipe(bool overlapped = false) + { + NullTerminatedWideString data(path()); + StreamT f(CreateNamedPipe( + data, // lpName + PIPE_ACCESS_DUPLEX | + (overlapped ? FILE_FLAG_OVERLAPPED : 0), // dwOpenMode + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, // dwPipeMode + PIPE_UNLIMITED_INSTANCES, // nMaxInstances + 512, // nOutBufferSize + 512, // nInBufferSize + 0, // nDefaultTimeOut + NULL), // lpSecurityAttributes + *this); + if (!f.valid()) + throw Exception::systemError("Creating pipe " + path()); + return f; + } +private: +#else + FileStreamT open(int flags, bool throwIfExists = true) const + { + FileStreamT f = tryOpen(flags); + if (!f.valid() && (throwIfExists || errno != EEXIST)) + throw Exception::systemError("Opening file " + path()); + return f; + } + FileStreamT tryOpen(int flags) const + { + NullTerminatedString data(path()); + return FileStream(::open(data, flags), *this); + } + FileStreamT openWrite(int flags, mode_t mode, + bool throwIfExists = true) const + { + FileStreamT f = tryOpenWrite(flags, mode); + if (!f.valid() && (throwIfExists || errno != EEXIST)) + throw Exception::systemError("Opening file " + path()); + return f; + } + FileStreamT tryOpenWrite(int flags, mode_t mode) const + { + NullTerminatedString data(path()); + return FileStream(::open(data, flags, mode), *this); + } +#endif + + friend class DirectoryT; + friend class Console; +}; + +template void applyToWildcard(T& functor, + CharacterSourceT s, int recurseIntoDirectories, Directory directory) +{ + int subDirectoryStart = s.offset(); + int c = s.get(); + int p = s.offset(); +#ifdef _WIN32 + while (c != '/' && c != '\\' && c != -1) { + if (c < 32 || c == ':' || c == '"' || c == '<' || c == '>') + throw Exception("Invalid path"); + p = s.offset(); + c = s.get(); + } + String name = s.subString(subDirectoryStart, p); + CharacterSource s2 = s; + while (c == '/' || c == '\\') { + s = s2; + c = s2.get(); + } + if (name == ".") { + if (c == -1) + if (recurseIntoDirectories) + name = String("*"); + else { + functor(directory); + return; + } + else { + applyToWildcard(functor, s, recurseIntoDirectories, directory); + return; + } + } + if (name == "..") { + if (c == -1) + if (recurseIntoDirectories) { + name = String("*"); + directory = directory.parent(); + } + else { + functor(directory.parent()); + return; + } + else { + applyToWildcard(functor, s, recurseIntoDirectories, + directory.parent()); + return; + } + } + if (name != "") { + int l = name[name.length() - 1]; + if (l == '.' || l == ' ') + throw Exception("Invalid path"); + } + else + if (recurseIntoDirectories) + name = String("*"); + else { + functor(directory); + return; + } +#else + while (c != '/' && c != -1) { + p = s.offset(); + c = s.get(); + } + String name = s.subString(subDirectoryStart, p); + while (c == '/') + c = s.get(); + if (name == ".") { + applyToWildcard(functor, s, recurseIntoDirectories, directory); + return; + } + if (name == "..") { + applyToWildcard(functor, s, recurseIntoDirectories, + directory.parent()); + return; + } +#endif + FindHandleT handle(directory, name); + while (!handle.complete()) { + if (handle.isDirectory() && !handle.isJunction()) { + Directory child = handle.directory(); + if (c == -1) + if (recurseIntoDirectories) + child.applyToContents(functor, true); + else + functor(child); + else + applyToWildcard(functor, s, recurseIntoDirectories, child); + } + else + if (c == -1) + functor((File)handle.file()); + handle.next(); + } +} + +template void applyToWildcard(T& functor, const String& wildcard, + int recurseIntoDirectories = true, + const Directory& relativeTo = CurrentDirectory()) +{ + CharacterSource s(wildcard); +#ifdef _WIN32 + Directory dir = + FileSystemObject::windowsParseRoot(wildcard, relativeTo, s); +#else + Directory dir = FileSystemObject::parseRoot(wildcard, relativeTo, s); +#endif + applyToWildcard(functor, s, recurseIntoDirectories, dir); +} + +class Console : public File +{ +public: + Console() : File(create()) { } +private: + class Body : public FileSystemObject::Body + { + public: + String path() const { return "(console)"; } + Directory parent() const { return RootDirectory(); } + String name() const { return path(); } + bool isRoot() const { return false; } + }; +}; + +#endif // INCLUDED_FILE_H diff --git a/80386/disassembler/include/alfe/file.txt b/80386/disassembler/include/alfe/file.txt new file mode 100644 index 0000000..fd97e94 --- /dev/null +++ b/80386/disassembler/include/alfe/file.txt @@ -0,0 +1,11 @@ +FileSystemObject FileSystemObject::Body + Directory + CurrentDirectory + DriveCurrentDirectory + RootDirectory RootDirectory::Body + DriveRootDirectory DriveRootDirectory::Body + UNCRootDirectory UNCRootDirectory::Body + File + NamedFileSystemObjectBody + +There are also instances of FileSystemObject where we don't know whether they are a File or Directory diff --git a/80386/disassembler/include/alfe/file_stream.h b/80386/disassembler/include/alfe/file_stream.h new file mode 100644 index 0000000..1a77cff --- /dev/null +++ b/80386/disassembler/include/alfe/file_stream.h @@ -0,0 +1,62 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_FILE_STREAM_H +#define INCLUDED_FILE_STREAM_H + +template class FileStreamT : public Stream +{ +public: +#ifdef _WIN32 + FileStreamT(HANDLE handle, const File& file) + : Stream(handle, file, true) { } +#else + FileStreamT(int fileDescriptor, const File& file) + : Stream(fileDescriptor, file, true) { } +#endif +#ifndef _WIN32 + void sync() + { + if (fsync(operator int()) != 0) + throw Exception::systemError( + "Synchronizing file " + file().path()); + } +#endif + UInt64 size() + { +#ifdef _WIN32 + LARGE_INTEGER size; + if (GetFileSizeEx(operator HANDLE(), &size) == 0) + throw Exception::systemError( + "Obtaining length of file " + file().path()); + return size.QuadPart; +#else + off_t o = seek(0, SEEK_CUR); + off_t n = seek(0, SEEK_END); + seek(o, SEEK_SET); + return n; +#endif + } + void seek(UInt64 position) + { +#ifdef _WIN32 + LARGE_INTEGER p; + p.QuadPart = position; + if (SetFilePointerEx(operator HANDLE(), p, NULL, FILE_BEGIN) == 0) + throw Exception::systemError("Seeking file " + file().path()); +#else + seek(position, SEEK_SET); +#endif + } +private: +#ifndef _WIN32 + off_t seek(off_t offset, int whence) + { + off_t n = lseek(operator int(), offset, whence); + if (n == (off_t)(-1)) + throw Exception::systemError("Seeking file " + file().path()); + return n; + } +#endif +}; + +#endif // INCLUDED_FILE_STREAM_H diff --git a/80386/disassembler/include/alfe/find_handle.h b/80386/disassembler/include/alfe/find_handle.h new file mode 100644 index 0000000..61b4ba9 --- /dev/null +++ b/80386/disassembler/include/alfe/find_handle.h @@ -0,0 +1,205 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_FIND_HANDLE_H +#define INCLUDED_FIND_HANDLE_H + +#ifdef _WIN32 +template class FindHandleT +{ +public: + FindHandleT(const Directory& directory, const String& wildcard) + : _directory(directory), _wildcard(wildcard), _complete(false), + _handle(INVALID_HANDLE_VALUE) + { + _path = directory.child(wildcard).path(); + NullTerminatedWideString data(_path); + _handle = FindFirstFile(data, &_data); + if (_handle == INVALID_HANDLE_VALUE) { + DWORD lastError = GetLastError(); + if (lastError == ERROR_FILE_NOT_FOUND || + lastError == ERROR_ACCESS_DENIED || + lastError == ERROR_INVALID_HANDLE) + _complete = true; + else + throwError(); + } + String n = name(); + if (n == "." || n == "..") + next(); + } + void next() + { + do { + if (FindNextFile(_handle, &_data) == 0) { + DWORD lastError = GetLastError(); + if (lastError == ERROR_NO_MORE_FILES || + lastError == ERROR_INVALID_HANDLE) { + _complete = true; + return; + } + else + throwError(); + } + String n = name(); + if (n == "." || n == "..") + continue; + break; + } while (true); + } + ~FindHandleT() + { + if (_handle != INVALID_HANDLE_VALUE) + FindClose(_handle); + } + bool isDirectory() const + { + return (_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + } + bool isJunction() const + { + return (_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0; + } + bool isSymlink() const + { + return isJunction() && _data.dwReserved0 == IO_REPARSE_TAG_SYMLINK; + } + String name() const + { + try { + String n(_data.cFileName); + return n; + } + catch (...) + { + return ""; + } + } + FileSystemObject object() const + { + return _directory.child(name()); + } + DirectoryT directory() const + { + return _directory.subDirectory(name()); + } + FileT file() const + { + return _directory.file(name()); + } + bool complete() { return _complete; } +private: + void throwError() + { + throw Exception::systemError("Finding files " + _path); + } + + HANDLE _handle; + WIN32_FIND_DATA _data; + Directory _directory; + String _wildcard; + String _path; + bool _complete; +}; +#else +template class FindHandleT +{ +public: + FindHandleT(const Directory& directory, const String& wildcard) + : _directory(directory), _wildcard(wildcard), _complete(false), + _dir(NULL) + { + _path = directory.child(wildcard).path(); + NullTerminatedString data(_path); + _dir = opendir(data); + if (_dir == NULL) + throw Exception::systemError("Opening directory " + _path); + next(); + } + void next() + { + do { + errno = 0; + _data = readdir(_dir); + if (_data == NULL) + if (errno == 0) + _complete = true; + else + throw Exception::systemError("Reading directory " + _path); + String n = name(); + if (n == "." || n == "..") + continue; + if (!matches(n, _wildcard)) + continue; + break; + } while (true); + } + ~FindHandleT() + { + if (_dir != NULL) + closedir(_dir); + } + bool isDirectory() const + { + return _data->d_type == DT_DIR; + } + String name() const + { + return _data->d_name; + } + FileSystemObject object() const + { + return _directory.child(name()); + } + Directory directory() const + { + return _directory.subDirectory(name()); + } + File file() const + { + return _directory.file(name()); + } + bool complete() { return _complete; } +private: + static bool matches(String name, String wildcard) + { + CharacterSourceT sw(wildcard); + CharacterSourceT sn(name); + do { + int cs = sw.get(); + int cn = sn.get(); + switch (cs) { + case '?': + if (cn == -1) + return false; + continue; + case '*': + // TODO: this code is O(n^p) where p is number of stars, we + // can do better using dynamic programming. + if (cn == -1) + continue; + do { + if (matches(name.subString(sn.offset(), + name.length() - sn.offset()), sw.offset(), + wildcard.length() - sw.offset())) + return true; + cn = sn.get(); + } while (cn != -1); + return false; + case -1: + return (cn == -1); + default: + return (cn == cs); + } + } while (true); + } + + struct dirent* _data; + DIR* _dir; + Directory _directory; + String _wildcard; + String _path; + bool _complete; +}; +#endif + +#endif // INCLUDED_FIND_HANDLE_H diff --git a/80386/disassembler/include/alfe/fix.h b/80386/disassembler/include/alfe/fix.h new file mode 100644 index 0000000..57fb438 --- /dev/null +++ b/80386/disassembler/include/alfe/fix.h @@ -0,0 +1,382 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_FIX_H +#define INCLUDED_FIX_H + +#include +#pragma intrinsic(__emul) +#pragma intrinsic(__emulu) +#pragma intrinsic(__ll_lshift) + +template class Fixed; + +template class DoublePrecisionArithmeticHelper +{ +private: + template friend class Fixed; + + // Convert double precision to single precision + static T sp(const TT& d) { return static_cast(d); } + + // Convert single precision to double precision + static TT dp(const T& s) { return static_cast(s); } + + static T MultiplyShiftRight(T x, T y) + { + return sp((dp(x)*dp(y) /*+ (1 << (N - 1))*/) >> N); + } + static T ShiftLeftDivide(T x, T y) + { + return sp(((dp(x) << N) /*+ (1 << (N - 1))*/) / dp(y)); + } + static T MultiplyShiftLeftDivide(T x, T y, T z) + { + return sp((dp(x)*dp((y << N) /*+ (1 << (N - 1))*/)) / dp(z)); + } + static T MultiplyDivide(T x, T y, T z) + { + return sp((dp(x)*dp(y))/dp(z)); + } + static TT lmul(T x, T y) { return dp(x)*dp(y); } +}; + +template class ArithmeticHelper +{ +private: + friend class Fixed >; + static T MultiplyShiftRight(T x, T y) { } + static T ShiftLeftDivide(T x, T y) { } + static T MultiplyShiftLeftDivide(T x, T y, T z) { } + static T MultiplyDivide(T x, T y, T z) { } +}; + +template class ArithmeticHelper + : DoublePrecisionArithmeticHelper +{ + friend class Fixed >; +public: + typedef Int16 DoubleType; +}; + +template class ArithmeticHelper + : DoublePrecisionArithmeticHelper +{ + friend class Fixed >; +public: + typedef Int32 DoubleType; +}; + +template class ArithmeticHelper + : DoublePrecisionArithmeticHelper +{ + friend class Fixed >; +public: + typedef Word DoubleType; +}; + +template class ArithmeticHelper + : DoublePrecisionArithmeticHelper +{ + friend class Fixed >; +public: + typedef DWord DoubleType; +}; + +#ifdef _WIN32 + +template class ArithmeticHelper +{ +private: + friend class Fixed >; + + // VC's inline asm doesn't allow "shl eax, N" directly, but this works... + static const int nn[N]; + static const int n2[1 << (N - 1)]; + + static Int32 MultiplyShiftRight(Int32 x, Int32 y) + { + __asm { + mov eax, x + imul y + add eax, length n2 + shrd eax, edx, length nn + } + } + static Int32 ShiftLeftDivide(Int32 x, Int32 y) + { + __asm { + mov eax, x + cdq + shld edx, eax, length nn + add eax, length n2 + adc edx, 0 + idiv y + } + } + static Int32 MultiplyShiftLeftDivide(Int32 x, Int32 y, Int32 z) + { + __asm { + mov eax, y + shl eax, length nn + add eax, length n2 + imul x + idiv z + } + } + static Int32 MultiplyDivide(Int32 x, Int32 y, Int32 z) + { + __asm { + mov eax, y + imul x + idiv z + } + } +}; + +template class ArithmeticHelper +{ +private: + friend class Fixed >; + + // VC's inline asm doesn't allow "shl eax, N" directly, but this works... + static const int nn[N]; + static const int n2[1 << (N - 1)]; + + static DWord MultiplyShiftRight(DWord x, DWord y) + { + __asm { + mov eax, x + mul y + add eax, length n2 + shrd eax, edx, length nn + } + } + static DWord ShiftLeftDivide(DWord x, DWord y) + { + __asm { + mov eax, x + mov edx, 0 + shld edx, eax, length nn + add eax, length n2 + adc edx, 0 + div y + } + } + static DWord MultiplyShiftLeftDivide(DWord x, DWord y, DWord z) + { + __asm { + mov eax, y + shl eax, length nn + add eax, length n2 + mul y + div z + } + } + static DWord MultiplyDivide(DWord x, DWord y, DWord z) + { + __asm { + mov eax, y + mul y + div z + } + } +}; + +#else // _WIN32 + +template class ArithmeticHelper + : DoublePrecisionArithmeticHelper +{ + friend class Fixed >; +}; + +template class ArithmeticHelper + : DoublePrecisionArithmeticHelper +{ + friend class Fixed >; +}; + +#endif + +template > class Fixed +{ +public: + Fixed() { } + Fixed(int x) : _x(x<(x*static_cast(1<(x*static_cast(1< Fixed(const Fixed& x) + : _x(N>(N2-N)) : (x._x<<(N-N2))) + { } + Fixed(T x, T m, T d) : _x(M::MultiplyShiftLeftDivide(x, m, d)) { } + static Fixed fromRepresentation(T x) { Fixed r; r._x = x; return r; } + T representation() const { return _x; } + const Fixed& operator=(const Fixed& x) { _x = x._x; return *this; } + const Fixed& operator=(T x) { _x = x<(x*static_cast(1<(x*static_cast(1<>=(int n) { _x >>= n; return *this; } + const Fixed& operator&=(const Fixed& x) { _x &= x._x; return *this; } + Fixed operator+(const Fixed& x) const { Fixed y = *this; return y += x; } + Fixed operator-(const Fixed& x) const { Fixed y = *this; return y -= x; } + Fixed operator*(const Fixed& x) const { Fixed y = *this; return y *= x; } + Fixed operator/(const Fixed& x) const { Fixed y = *this; return y /= x; } + Fixed operator<<(int n) const { Fixed y = *this; return y <<= n; } + Fixed operator>>(int n) const { Fixed y = *this; return y >>= n; } + Fixed operator&(const Fixed& x) const { Fixed y=*this; return y &= x; } + bool operator<(const Fixed& x) const { return _x < x._x; } + bool operator>(const Fixed& x) const { return _x > x._x; } + bool operator<=(const Fixed& x) const { return _x <= x._x; } + bool operator>=(const Fixed& x) const { return _x >= x._x; } + bool operator==(const Fixed& x) const { return _x == x._x; } + bool operator!=(const Fixed& x) const { return _x != x._x; } + int intFloor() const { return static_cast(_x>>N); } + int intCeiling() const + { + return static_cast((_x + ((1 << N) - 1)) >> N); + } + int intRound() const + { + return static_cast((_x + (1 << (N - 1))) >> N); + } + Fixed floor() const { Fixed x; x._x = _x & ((-1) << N); return x; } + Fixed ceiling() const + { + Fixed x; + x._x = (_x + (1 << N) - 1) & ((-1) << N); + return x; + } + Fixed round() const + { + Fixed x; + x._x = (_x + (1 << (N - 1))) & ((-1) << N); + return x; + } + float toFloat() const + { + return static_cast(_x)/static_cast(1<(_x)/static_cast(1<(_x >> N); } + Fixed muld(const Fixed& y, const Fixed& z) const + { + Fixed x; + x._x = M::MultiplyDivide(_x, y._x, z._x); + return x; + } + template::DoubleType, + class M2 = ArithmeticHelper> + Fixed lmul(const Fixed& x) const + { + Fixed r; + r._x = M::lmul(_x, x._x); + const int s = N + N - N2; + if (s < 0) + r._x <<= -s; + else + r._x >>= s; + return r; + } + +private: + T _x; + + // This says that different instantiations of this template are friends + // with each other, allowing the constructor which converts between + // instances to access the raw value. + template friend class Fixed; +}; + +template Fixed + operator*(const T& x, const Fixed& y) +{ + return y*x; +} + +template Fixed + operator/(const T& x, const Fixed& y) +{ + return static_cast>(x)/y; +} + +template Fixed + operator-(const T& x, const Fixed& y) +{ + return static_cast>(x) - y; +} + +template Fixed + operator-(int x, const Fixed& y) +{ + return static_cast>(x) - y; +} + +template Fixed + operator-(const Fixed& x, const T& y) +{ + return x - static_cast>(y); +} + +template Fixed + operator+(const T& x, const Fixed& y) +{ + return y + x; +} + +template Fixed + floor(const Fixed& x) +{ + return x.floor(); +} + +template Fixed + ceil(const Fixed& x) +{ + return x.ceil(); +} + +template::DoubleType, + class M2 = ArithmeticHelper> + Fixed + lmul(const Fixed& x, const Fixed& y) +{ + return x.lmul(y); +} + +template Fixed + muld(const Fixed& a, const Fixed& b, + const Fixed& c) +{ + return a.muld(b, c); +} + +#endif // INCLUDED_FIX_H diff --git a/80386/disassembler/include/alfe/fractal.h b/80386/disassembler/include/alfe/fractal.h new file mode 100644 index 0000000..dd51a8f --- /dev/null +++ b/80386/disassembler/include/alfe/fractal.h @@ -0,0 +1,793 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_FRACTAL_H +#define INCLUDED_FRACTAL_H + +#include "alfe/complex.h" +#include "alfe/user.h" +#include "alfe/fix.h" +#include "alfe/thread.h" + +typedef Fixed<16, Int32, Int64> Fix16p16; + +class Region +{ +public: + Region(Vector2 min, Vector2 max, Vector2 size) + : _min(min), + _max(max), + _size(size) + { + recalculate(); + } + void resize(Vector2 size) + { + _size = size; + recalculate(); + } + + // Zoom function for ZoomableWindow (zoom box) + void zoom(Vector2 topLeft, Vector2 bottomRight, bool in) + { + if (topLeft.x==bottomRight.x || topLeft.y==bottomRight.y) + return; + if (in) { + _max = cFromS(bottomRight); + _min = cFromS(topLeft); + } + else { + Vector2 tl = Vector2(topLeft) / _size; + Vector2 br = Vector2(bottomRight) / _size; + Vector2 s = br-tl; + _min = Complex( + (br*Vector2(_min) - tl*Vector2(_max))/s); + _max = _min + Complex(_range/s); + } + recalculate(); + } + + // Zoom function for ZoomingWindow (position and magnification) + void zoom(Region original, Fix16p16 zoomLevel, Vector2 s, + Vector2 zoomPoint) + { + if (_size.x>1 && _size.y>1) { + double z = sqrt( + original._range.modulus2()) * exp(-zoomLevel.toDouble()); + double p = sqrt(static_cast(_size.modulus2())); + _range = Vector2(_size)*z/p; + recalculateDelta(); + _min = zoomPoint - Vector2(s)*_delta; + _max = _min + _range; + } + } + + Complex cFromS(Vector2 s) const + { + return Complex(Vector2(s)*_delta + _min); + } + Complex cFromS(Vector2 s) const + { + return Complex(s*_delta + _min); + } + Complex cFromP(Vector2 p) const + { + return Complex(p*_range + _min); + } + + Vector2 sFromC(Complex c) const + { + return Vector2Cast((Vector2(c)-_min)/_delta); + } + Vector2 getDelta() const { return _delta; } + int pixels() const { return _size.x*_size.y; } + Vector2 getSize() const { return _size; } + Vector2 getMin() const { return _min; } + Vector2 getMax() const { return _max; } + int syFromCy(double y) const + { + return static_cast((y-_min.y)/_delta.y); + } + double cxFromSx(double x) const { return _delta.x*x + _min.x; } + +private: + void recalculateDelta() + { + if (_size.x>0 && _size.y>0) + _delta = _range/_size; + } + void recalculate() + { + _range = _max-_min; + recalculateDelta(); + } + + Vector2 _min; + Vector2 _max; + Vector2 _size; + Vector2 _range; + Vector2 _delta; +}; + +class PointGenerator +{ +public: + PointGenerator() + : _c(0, 0), + _dc(sqrt(2.0)-1.0, pow(3.0, 1.0/3.0)-1.0) + { } + Complex getC(const Region& region) + { + _c += _dc; + if (_c.x >= 1.0) + _c.x -= 1; + if (_c.y >= 1.0) + _c.y -= 1; + return region.cFromP(_c); + } +private: + Vector2 _c; + Vector2 _dc; +}; + +template class ZoomableWindow : public Base +{ +public: + class Params + { + friend class ZoomableWindow; + public: + Params(typename Base::Params bp) : _bp(bp) { } + private: + typename Base::Params _bp; + }; + + ZoomableWindow(Params p) + : Base(p._bp), + _region(_image->region()), + _zoomingIn(false), + _zoomingOut(false), + _bandDrawn(false) + { } + +protected: + virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + switch (uMsg) { + case WM_LBUTTONDOWN: + _zoomingIn = true; + SetCapture(_hWnd); + _zoomPosition = vectorFromLParam(lParam); + break; + case WM_LBUTTONUP: + ReleaseCapture(); + if (_zoomingIn) { + _zoomingIn = _zoomingOut = false; + doZoom(_zoomPosition, vectorFromLParam(lParam), true); + eraseBand(); + } + break; + case WM_RBUTTONDOWN: + _zoomingOut = true; + SetCapture(_hWnd); + _zoomPosition = vectorFromLParam(lParam); + break; + case WM_RBUTTONUP: + ReleaseCapture(); + if (_zoomingOut) { + _zoomingIn = _zoomingOut = false; + doZoom(_zoomPosition, vectorFromLParam(lParam), false); + eraseBand(); + } + break; + case WM_MOUSEMOVE: + eraseBand(); + if (_zoomingIn || _zoomingOut) + drawBand(vectorFromLParam(lParam)); + break; + case WM_SIZE: + onResize(vectorFromLParam(lParam)); + return 0; + case WM_KILLFOCUS: + ReleaseCapture(); + if (_zoomingIn || _zoomingOut) + eraseBand(); + _zoomingIn = _zoomingOut = false; + break; + } + + return Base::handleMessage(uMsg, wParam, lParam); + } + +private: + static Vector vectorFromLParam(LPARAM lParam) + { + return Vector(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + + void onResize(Vector s) + { + if (s.zeroArea()) + return; + _region.resize(s); + _image->changeCoords(_region); + IF_ZERO_THROW(InvalidateRect(_hWnd, NULL, FALSE)); + } + + void doZoom(Vector topLeft, Vector bottomRight, bool in) + { + if (bottomRight.xchangeCoords(_region); + IF_ZERO_THROW(InvalidateRect(_hWnd, NULL, FALSE)); + } + + void invalidateBand() + { + RECT r; + r.left = _bandPosition.x; + r.right = _bandPosition.x; + r.top = min(_bandPosition.y, _zoomPosition.y); + r.bottom = max(_bandPosition.y, _zoomPosition.y); + IF_ZERO_THROW(InvalidateRect(_hWnd, &r, FALSE)); + r.left = _zoomPosition.x; + r.right = _zoomPosition.x; + r.top = min(_bandPosition.y, _zoomPosition.y); + r.bottom = max(_bandPosition.y, _zoomPosition.y); + IF_ZERO_THROW(InvalidateRect(_hWnd, &r, FALSE)); + r.left = min(_bandPosition.x, _zoomPosition.x); + r.right = max(_bandPosition.x, _zoomPosition.x); + r.top = _bandPosition.y; r.bottom = _bandPosition.y; + IF_ZERO_THROW(InvalidateRect(_hWnd, &r, FALSE)); + r.left = min(_bandPosition.x, _zoomPosition.x); + r.right = max(_bandPosition.x, _zoomPosition.x); + r.top = _zoomPosition.y; r.bottom = _zoomPosition.y; + IF_ZERO_THROW(InvalidateRect(_hWnd, &r, FALSE)); + } + + void drawBand(DeviceContext* dc) + { + Pen pen(PS_DOT, 0, BLACK_PEN); + SelectedObject sp(dc, pen); + + POINT points[5]; + points[0].x = _zoomPosition.x; points[0].y = _zoomPosition.y; + points[1].x = _zoomPosition.x; points[1].y = _bandPosition.y; + points[2].x = _bandPosition.x; points[2].y = _bandPosition.y; + points[3].x = _bandPosition.x; points[3].y = _zoomPosition.y; + points[4].x = _zoomPosition.x; points[4].y = _zoomPosition.y; + + dc->SetROP2(R2_XORPEN); + dc->Polyline(points, 5); + } + + void eraseBand() + { + if (!_bandDrawn) + return; + _bandDrawn = false; + WindowDeviceContext dc(*this); + drawBand(&dc); + } + + void drawBand(Vector position) + { + eraseBand(); + _bandPosition = position; + _bandDrawn = true; + WindowDeviceContext dc(*this); + drawBand(&dc); + } + + void doPaint(PaintHandle* paint) + { + //if (_bandDrawn) + // drawBand(paint); + Base::doPaint(paint); + if (_bandDrawn) + drawBand(paint); + } + + Region _region; + Vector2 _bandPosition; + Vector2 _zoomPosition; + bool _bandDrawn; + bool _zoomingIn; + bool _zoomingOut; +}; + +class CalcThread : public Thread +{ +public: + CalcThread(Region region) + : _ending(false), + _region(region), + _newRegion(region) + { } + + void initialize() + { + doRestart(); + } + + Region region() const { return _region; } + + void changeCoords(Region region) + { + _newRegion = region; + if (!_restartRequested) { + _restartRequested = true; + _event.wait(); + } + } + + void end() + { + _ending = true; + join(); + } + +protected: + Region _region; + +private: + void doRestart() + { + _region = _newRegion; + restart(); + _restartRequested = false; + } + + void threadProc() + { + do { + if (_restartRequested) { + doRestart(); + _event.signal(); + } + if (_region.pixels() == 0) + Sleep(100); + else + calculate(); + } while (!_ending); + } + + virtual void restart() = 0; + virtual void calculate() = 0; + + Region _newRegion; + bool _restartRequested; + bool _ending; + Event _event; +}; + +template class ZoomingWindow : public Base +{ +public: + class Params + { + friend class ZoomingWindow; + public: + Params(typename Base::Params bp) : _bp(bp) { } + private: + typename Base::Params _bp; + }; + + ZoomingWindow(Params p) + : Base(p._bp), + _region(_image->region()), + _region0(_image->region()), + _zoomPosition(0,0), + _zoomPoint(0,0), + _lbutton(false), + _rbutton(false), + _mbutton(false), + _zoomLevel(0), + _zoomVelocity(0), + _maxZoomVelocity(10000/65536.0), + _zoomAcceleration(1000/65536.0) + { } + +protected: + virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + switch (uMsg) { + case WM_LBUTTONDOWN: + buttonDown(&_lbutton, lParam); + break; + case WM_LBUTTONUP: + buttonUp(&_lbutton); + break; + case WM_RBUTTONDOWN: + buttonDown(&_rbutton, lParam); + break; + case WM_RBUTTONUP: + buttonUp(&_rbutton); + break; + case WM_MBUTTONDOWN: + buttonDown(&_mbutton, lParam); + break; + case WM_MBUTTONUP: + buttonUp(&_mbutton); + break; + case WM_MOUSEMOVE: + if (_lbutton || _rbutton || _mbutton) + zoomPos(vectorFromLParam(lParam)); + break; + case WM_SIZE: + { + Vector size = vectorFromLParam(lParam); + if (!size.zeroArea()) { + _region.resize(size); + _zoomPosition = size/2; + _zoomPoint = _region.cFromS(_zoomPosition); + recalculateRegion(); + } + } + return 0; + case WM_KILLFOCUS: + _lbutton = _rbutton = _mbutton = false; + ReleaseCapture(); + break; + } + + return Base::handleMessage(uMsg, wParam, lParam); + } + +private: + static Vector2 vectorFromLParam(LPARAM lParam) + { + return Vector2(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + + void buttonDown(bool* button, LPARAM lParam) + { + zoomPos(vectorFromLParam(lParam)); + *button = true; + SetCapture(_hWnd); + } + void buttonUp(bool* button) + { + *button = false; + if (!_lbutton && !_rbutton && !_mbutton) + ReleaseCapture(); + } + + // Recalculate the region - called whenever we zoom or pan. + void recalculateRegion() + { + _region.zoom(_region0, _zoomLevel, _zoomPosition, _zoomPoint); + _image->changeCoords(_region); + } + + // Recalculate the zoom level and (if necessary) the region + void recalculateZoom() + { + if (!_lbutton) + if (!_rbutton) { + // No buttons pressed - slow to a stop + if (_zoomVelocity > static_cast(0)) { + // Decelerate from zooming in + _zoomVelocity -= _zoomAcceleration; + } + if (_zoomVelocity < static_cast(0)) { + // Decelerate from zooming out + _zoomVelocity += _zoomAcceleration; + } + } + else { + // Right button pressed only - zoom out + if (_zoomVelocity > -_maxZoomVelocity) { + // Accelerate to zoom out + _zoomVelocity -= _zoomAcceleration; + } + } + else + if (!_rbutton) { + // Left button pressed only - zoom in + if (_zoomVelocity < _maxZoomVelocity) { + // Accelerate to zoom in + _zoomVelocity += _zoomAcceleration; + } + } + else { + // Both buttons pressed, keep same velocity + } + _zoomLevel += _zoomVelocity; + recalculateRegion(); + } + + // Change the zoom position. Called whenever the mouse is moved. + void zoomPos(Vector2 s) + { + if (s == _zoomPosition) + return; + _zoomPosition = s; + + // If the middle button is held down we want to pan, which means we + // want to move _zoomPoint to the new mouse position, i.e. don't + // change it as we move the mouse. + if (!_mbutton) + _zoomPoint = _region.cFromS(s); + } + + virtual void doPaint(PaintHandle* paint) + { + // Render the fractal data to a bitmap (only done when the timer has + // expired, not on every redraw). This needs to be done before the + // paint operation so that we paint the most up-to-date possible image. + //if (_timerExpired) { + // Update the coordinates for the next frame. This will result in + // restart() getting called, which will render and then change + // coordinates. + recalculateZoom(); + //} + + // Paint the image to the window + Base::doPaint(paint); + + //if (_timerExpired) + // resetTimer(); + + //return painted; + } + + Region _region; + Region _region0; + Vector2 _zoomPosition; + Complex _zoomPoint; + bool _lbutton, _rbutton, _mbutton; + Fix16p16 _zoomLevel; + Fix16p16 _zoomVelocity; + Fix16p16 _maxZoomVelocity; + Fix16p16 _zoomAcceleration; + + // _zoomLevel is a number describing how zoomed in we are. It increases by + // a constant whenever you zoom in by a constant factor. So it is related + // to zoomFactor by zoomFactor = A*exp(k*_zoomLevel) for some constants A + // and k. + + // A is easy to set because at zoom level 0 we want zoomFactor = 1 so A=1 + + // We want increasing _zoomLevel by 1 to be around the smallest noticable + // zoom, say 1/16 of a pixel in a 4096 pixel wide image. This works out as + // a zoomFactor of 1/65536. + + // To compute k, look at the ratio of zoomFactors for two consecutive zoom + // levels zL1 = zL2+1 + // zF1/zF2 = exp(k*zL1) / exp(k*zL2) = exp(k*(zL1-zL2)) = exp(k) + // so k = log(1+1/65536) ~= 1/65536 + + // If your maximum zoom level is 0 it means your precision at 2 is 1/65536 + + // float has a precision at 1 of 1/8388607 = 1/2^23 (1/2^(mantissa bits-1)) + // so precision at 2 is 1/2^22 so can support a zoom factor of 2^6 + // (2^(mantissa bits-18)). This is a zoom level of ln(2^6) = 4.16 = + // l_2(2^6) / l_2(e) = 6/l_2(e) = 6 * log(2) + // + // double has a max zoom level of (53-18) * log(2) = 24.3 + // + // long double has a max zoom level of (65-18) * log(2) = 32.6 + + // 32-bit integer arithmetic: need to go from -512 to 511.9999 - 10 bits to + // the left of the point, 22 bits to the right, so precision is 1/2^22 - + // same as float at 2. + + // In fractint, precision is 1/2^29 because the bailout radius is fixed at + // 2 and there are clever bailout optimizations to minimize magnitude of + // numbers needed. + + // type bits lg(zl) zoomLevel + // float 22 6 4.16 + // int 22 6 4.16 + // fractint 29 13 9.01 + // double 51 35 24.3 + // 2*int 54 38 26.3 + // long double 63 47 32.6 + // 3*int 86 70 48.5 + // 4*int 118 102 70.7 + // 1477*int 47254 47238 32743 + + // So, to max out the zoom level we need 47264-bit integers (5.7Kb for a + // single number)! Clearly such numbers will take too long to calculate + // with, so this limit is unlikely to be reached in practice. + + // Also, at 60Hz with a zoomLevel velocity of 2048/65536 per frame, it will + // take us nearly 5 hours of zooming! +}; + +// Designed for use with ZoomableWindow. With this window. We render to the +// bits right before painting (in draw()) and resize the region after calling +// changeCoords(). Otherwise when draw() is called by changeCoords(), the size +// of the bits array will be the wrong one. +template class FractalImage : public Image +{ +public: + FractalImage(Region region) : _thread(region) { _thread.start(); } + void paint(const PaintHandle& paint) + { + _thread.draw(getBits(), _byteWidth); + Image::paint(paint); + } + void changeCoords(const Region& region) + { + _thread.changeCoords(region); + resize(region.getSize()); + } + ~FractalImage() { _thread.end(); } + Region region() const { return _thread.region(); } + template void setImageWindow(WindowType* iw) + { + _thread.setImageWindow(iw); + } + void destroy() { } +private: + FractalCalcThread _thread; +}; + +// Designed for use with ZoomingWindow. With this window, we need to resize the +// region first so that the thread has the latest data when changeCoords() is +// called. There is no draw() here, because changeCoords() will render to +// the bits. +template class FractalImage2 + : public Base +{ +public: + FractalImage2(Region region) : _thread(region) { _thread.start(); } + void changeCoords(const Region& region) + { + resize(region.getSize()); + _thread.setImageParameters(getBits(), _byteWidth); + _thread.changeCoords(region); + } + ~FractalImage2() { _thread.end(); } + Region region() const { return _thread.region(); } + template void setImageWindow(WindowType* iw) + { + _thread.setImageWindow(iw); + } +private: + FractalCalcThread _thread; +}; + +Byte sinewave[0x400] = { + 128,128,129,130,131,131,132,133,134,135,135,136,137,138,138,139, + 140,141,142,142,143,144,145,145,146,147,148,149,149,150,151,152, + 152,153,154,155,155,156,157,158,158,159,160,161,162,162,163,164, + 165,165,166,167,167,168,169,170,170,171,172,173,173,174,175,176, + 176,177,178,178,179,180,181,181,182,183,183,184,185,186,186,187, + 188,188,189,190,190,191,192,192,193,194,194,195,196,196,197,198, + 198,199,200,200,201,202,202,203,203,204,205,205,206,207,207,208, + 208,209,210,210,211,211,212,213,213,214,214,215,215,216,217,217, + 218,218,219,219,220,220,221,221,222,222,223,224,224,225,225,226, + 226,227,227,228,228,228,229,229,230,230,231,231,232,232,233,233, + 234,234,234,235,235,236,236,236,237,237,238,238,238,239,239,240, + 240,240,241,241,241,242,242,242,243,243,243,244,244,244,245,245, + 245,246,246,246,246,247,247,247,248,248,248,248,249,249,249,249, + 250,250,250,250,250,251,251,251,251,251,252,252,252,252,252,252, + 253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254, + 254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254, + 254,254,254,254,254,254,254,254,254,254,253,253,253,253,253,253, + 253,252,252,252,252,252,252,251,251,251,251,251,250,250,250,250, + 250,249,249,249,249,248,248,248,248,247,247,247,246,246,246,246, + 245,245,245,244,244,244,243,243,243,242,242,242,241,241,241,240, + 240,240,239,239,238,238,238,237,237,236,236,236,235,235,234,234, + 234,233,233,232,232,231,231,230,230,229,229,228,228,228,227,227, + 226,226,225,225,224,224,223,222,222,221,221,220,220,219,219,218, + 218,217,217,216,215,215,214,214,213,213,212,211,211,210,210,209, + 208,208,207,207,206,205,205,204,203,203,202,202,201,200,200,199, + 198,198,197,196,196,195,194,194,193,192,192,191,190,190,189,188, + 188,187,186,186,185,184,183,183,182,181,181,180,179,178,178,177, + 176,176,175,174,173,173,172,171,170,170,169,168,167,167,166,165, + 165,164,163,162,162,161,160,159,158,158,157,156,155,155,154,153, + 152,152,151,150,149,149,148,147,146,145,145,144,143,142,142,141, + 140,139,138,138,137,136,135,135,134,133,132,131,131,130,129,128, + 128,127,126,125,124,124,123,122,121,120,120,119,118,117,117,116, + 115,114,113,113,112,111,110,110,109,108,107,106,106,105,104,103, + 103,102,101,100,100, 99, 98, 97, 97, 96, 95, 94, 93, 93, 92, 91, + 90, 90, 89, 88, 88, 87, 86, 85, 85, 84, 83, 82, 82, 81, 80, 79, + 79, 78, 77, 77, 76, 75, 74, 74, 73, 72, 72, 71, 70, 69, 69, 68, + 67, 67, 66, 65, 65, 64, 63, 63, 62, 61, 61, 60, 59, 59, 58, 57, + 57, 56, 55, 55, 54, 53, 53, 52, 52, 51, 50, 50, 49, 48, 48, 47, + 47, 46, 45, 45, 44, 44, 43, 42, 42, 41, 41, 40, 40, 39, 38, 38, + 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 32, 31, 31, 30, 30, 29, + 29, 28, 28, 27, 27, 27, 26, 26, 25, 25, 24, 24, 23, 23, 22, 22, + 21, 21, 21, 20, 20, 19, 19, 19, 18, 18, 17, 17, 17, 16, 16, 15, + 15, 15, 14, 14, 14, 13, 13, 13, 12, 12, 12, 11, 11, 11, 10, 10, + 10, 9, 9, 9, 9, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, + 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, + 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, + 15, 15, 16, 16, 17, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21, + 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 27, 28, 28, + 29, 29, 30, 30, 31, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, + 37, 38, 38, 39, 40, 40, 41, 41, 42, 42, 43, 44, 44, 45, 45, 46, + 47, 47, 48, 48, 49, 50, 50, 51, 52, 52, 53, 53, 54, 55, 55, 56, + 57, 57, 58, 59, 59, 60, 61, 61, 62, 63, 63, 64, 65, 65, 66, 67, + 67, 68, 69, 69, 70, 71, 72, 72, 73, 74, 74, 75, 76, 77, 77, 78, + 79, 79, 80, 81, 82, 82, 83, 84, 85, 85, 86, 87, 88, 88, 89, 90, + 90, 91, 92, 93, 93, 94, 95, 96, 97, 97, 98, 99,100,100,101,102, + 103,103,104,105,106,106,107,108,109,110,110,111,112,113,113,114, + 115,116,117,117,118,119,120,120,121,122,123,124,124,125,126,127}; + +Byte gammaSinewave[0x400] = { + 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 63, 64, 64, 65, 66, 67, + 68, 69, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,112, + 113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128, + 129,130,131,132,134,135,136,137,138,139,140,141,142,143,144,145, + 146,147,148,149,150,151,153,154,155,156,157,158,159,160,161,162, + 163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178, + 179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194, + 195,196,197,198,199,200,201,202,203,203,204,205,206,207,208,209, + 210,210,211,212,213,214,215,215,216,217,218,219,219,220,221,222, + 223,223,224,225,226,226,227,228,228,229,230,230,231,232,232,233, + 234,234,235,235,236,237,237,238,238,239,239,240,241,241,242,242, + 243,243,244,244,244,245,245,246,246,247,247,247,248,248,248,249, + 249,249,250,250,250,251,251,251,251,252,252,252,252,253,253,253, + 253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,254, + 255,254,254,254,254,254,254,254,254,254,254,254,254,254,253,253, + 253,253,253,253,252,252,252,252,251,251,251,251,250,250,250,249, + 249,249,248,248,248,247,247,247,246,246,245,245,244,244,244,243, + 243,242,242,241,241,240,239,239,238,238,237,237,236,235,235,234, + 234,233,232,232,231,230,230,229,228,228,227,226,226,225,224,223, + 223,222,221,220,219,219,218,217,216,215,215,214,213,212,211,210, + 210,209,208,207,206,205,204,203,203,202,201,200,199,198,197,196, + 195,194,193,192,191,190,189,188,187,186,185,184,183,182,181,180, + 179,178,177,176,175,174,173,172,171,170,169,168,167,166,165,164, + 163,162,161,160,159,158,157,156,155,154,153,151,150,149,148,147, + 146,145,144,143,142,141,140,139,138,137,136,135,134,132,131,130, + 129,128,127,126,125,124,123,122,121,120,119,118,117,116,115,114, + 113,112,111,110,109,108,107,106,105,104,103,102,101,100, 99, 98, + 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 83, + 82, 81, 80, 79, 78, 77, 76, 75, 75, 74, 73, 72, 71, 70, 69, 69, + 68, 67, 66, 65, 64, 64, 63, 62, 61, 60, 60, 59, 58, 57, 57, 56, + 55, 54, 54, 53, 52, 51, 51, 50, 49, 48, 48, 47, 46, 46, 45, 44, + 44, 43, 42, 42, 41, 41, 40, 39, 39, 38, 37, 37, 36, 36, 35, 34, + 34, 33, 33, 32, 32, 31, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, + 26, 25, 25, 24, 24, 23, 23, 22, 22, 22, 21, 21, 20, 20, 19, 19, + 19, 18, 18, 18, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14, 13, + 13, 13, 13, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 9, + 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, + 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 18, 18, 18, + 19, 19, 19, 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, + 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, + 34, 34, 35, 36, 36, 37, 37, 38, 39, 39, 40, 41, 41, 42, 42, 43, + 44, 44, 45, 46, 46, 47, 48, 48, 49, 50, 51, 51, 52, 53, 54, 54}; + +#endif // INCLUDED_FRACTAL_H diff --git a/80386/disassembler/include/alfe/function.h b/80386/disassembler/include/alfe/function.h new file mode 100644 index 0000000..a51ca72 --- /dev/null +++ b/80386/disassembler/include/alfe/function.h @@ -0,0 +1,215 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_FUNCTION_H +#define INCLUDED_FUNCTION_H + +#include "alfe/type.h" +#include "alfe/identifier.h" +#include "alfe/concrete.h" + +// This is not a real type - we can't do anything with it. A funco does not +// in general have a type (or even a tyco, because we can't do kind checking). +// However, OverloadedFunctionSet needs to be wrapped in a Value and placed in +// a symbol table (e.g. in ConfigFile), so this is the stub type for that. +template class FuncoTypeT : public NamedNullary> +{ +public: + static String name() { return "@FunctionConstructor"; } +}; + +template class FuncoT; +typedef FuncoT Funco; + +template class FuncoT : public Handle +{ +protected: + class Body : public Handle::Body + { + public: + virtual FunctionType type() const { return FuncoType(); }; + virtual Value evaluate(List arguments, Span span) const = 0; + virtual Identifier identifier() const = 0; + virtual bool argumentsMatch(List argumentTypes) const = 0; + virtual int compareTo(Funco other) const + { + List fTycos = parameterTycos(); + List bTycos = other.parameterTycos(); + assert(fTycos.count() == bTycos.count()); + auto bIterator = bTycos.begin(); + int r = 0; + for (auto fTyco : fTycos) { + Tyco bTyco = *bIterator; + Type fType = fTyco; + Type bType = bTyco; + if (fType.valid() && bType.valid()) { + if (!fType.canConvertTo(bType)) + r |= 2; + if (!bType.canConvertTo(fType)) + r |= 1; + } + else { + // This is enough for Berapa's built-in concrete functions, + // but eventually we'll want to generalize this. + if (bTyco == ConcreteTyco() && + (fTyco == IntegerType() || fTyco == RationalType())) + r |= 1; + if (fTyco == ConcreteTyco() && + (bTyco == IntegerType() || bTyco == RationalType())) + r |= 2; + } + ++bIterator; + } + return r; + } + virtual List parameterTycos() const = 0; + virtual String toString() const { return type().toString(); } + }; + const Body* body() const { return as(); } +public: + FuncoT() { } + FuncoT(const Handle& other) : Handle(other) { } + Value evaluate(List arguments, Span span) const + { + return body()->evaluate(arguments, span); + } + Identifier identifier() const { return body()->identifier(); } + bool argumentsMatch(List argumentTypes) const + { + return body()->argumentsMatch(argumentTypes); + } + int compareTo(Funco other) const { return body()->compareTo(other); } + String toString() const { return body()->toString(); } + FunctionType type() const { return body()->type(); } + List parameterTycos() const { return body()->parameterTycos(); } +}; + +class Function : public Funco +{ +public: + Function(const Handle& other) : Funco(other) { } + Function(const Funco& other) : Funco(to(other)) { } +protected: + class Body : public Funco::Body + { + public: + bool argumentsMatch(List argumentTypes) const + { + return type().argumentsMatch(argumentTypes.begin()); + } + List parameterTycos() const + { + List tycos; + type().addParameterTycos(&tycos); + return tycos; + } + }; +}; + +template class OverloadedFunctionSetT : public Handle +{ + class Body : public Handle::Body + { + public: + Body(Identifier identifier) : _identifier(identifier) { } + void add(Funco funco) { _funcos.add(funco); } + Value evaluate(List arguments, Span span) const + { + List<::Type> argumentTypes; + for (auto i : arguments) + argumentTypes.add(i.type()); + List bestCandidates; + for (auto f : _funcos) { + if (!f.argumentsMatch(argumentTypes)) + continue; + List newBestCandidates; + bool newBest = true; + for (auto b : bestCandidates) { + int r = f.compareTo(b); + if (r == 2) { + // b better than f + newBest = false; + break; + } + if (r != 1) + newBestCandidates.add(b); + } + if (newBest) { + bestCandidates = newBestCandidates; + bestCandidates.add(f); + } + } + for (auto f : bestCandidates) { + for (auto b : bestCandidates) { + int r = f.compareTo(b); + if (r == 3) { + span.throwError("Ambiguous function call of " + + _identifier.toString() + " with argument types " + + argumentTypesString(argumentTypes) + + ". Could be " + b.toString() + " or " + + f.toString() + "."); + } + } + } + if (bestCandidates.count() == 0) { + span.throwError("No matches for function " + + _identifier.toString() + " with argument types " + + argumentTypesString(argumentTypes) + "."); + } + // We have a choice of possible funcos here. Logically they should + // be equivalent, but some may be more optimal. For now we'll just + // choose the first one, but later we may want to try to figure out + // which one is most optimal. + auto i = *bestCandidates.begin(); + + List convertedArguments; + if (Function(i).valid()) { + List parameterTycos = i.parameterTycos(); + auto ii = parameterTycos.begin(); + for (auto a : arguments) { + Type type = *ii; + if (!type.valid()) { + a.span().throwError("Function parameter's type " + "constructor is not a type."); + } + convertedArguments.add(a.convertTo(type)); + ++ii; + } + } + else { + // Funcos that are not functions don't get their arguments + // converted. + convertedArguments = arguments; + } + return i.evaluate(convertedArguments, span); + } + private: + String argumentTypesString(List<::Type> argumentTypes) const + { + String s; + bool needComma = false; + for (auto t : argumentTypes) { + if (needComma) + s += ", "; + needComma = true; + s += t.toString(); + } + return s; + } + + List _funcos; + Identifier _identifier; + }; + Body* body() { return as(); } + const Body* body() const { return as(); } +public: + OverloadedFunctionSetT(Identifier identifier) + : Handle(create(identifier)) { } + void add(Funco funco) { body()->add(funco); } + static Type type() { return FuncoType(); } + Value evaluate(List arguments, Span span) const + { + return body()->evaluate(arguments, span); + } +}; + +#endif // INCLUDED_FUNCTION_H diff --git a/80386/disassembler/include/alfe/gcd.h b/80386/disassembler/include/alfe/gcd.h new file mode 100644 index 0000000..3507268 --- /dev/null +++ b/80386/disassembler/include/alfe/gcd.h @@ -0,0 +1,21 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_GCD_H +#define INCLUDED_GCD_H + +template T gcd(T x, T y) +{ + while (y != 0) { + T t = y; + y = x % y; + x = t; + } + return x; +} + +template T lcm(T x, T y) +{ + return (x/gcd(x,y))*y; +} + +#endif // INCLUDED_GCD_H diff --git a/80386/disassembler/include/alfe/handle.h b/80386/disassembler/include/alfe/handle.h new file mode 100644 index 0000000..8c575ed --- /dev/null +++ b/80386/disassembler/include/alfe/handle.h @@ -0,0 +1,172 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_HANDLE_H +#define INCLUDED_HANDLE_H + +// Base classes for reference-counted objects. Unlike std::shared_ptr, these +// are not thread-safe, so you must do your own locking if you want to copy +// and destruct handles from separate threads. + +class ConstHandle +{ +public: + ConstHandle() : _body(0) { } + ~ConstHandle() { reset(); } + ConstHandle(const ConstHandle& other) { set(other._body); } + template static ConstHandle to(const ConstHandle& other) + { + ConstHandle r; + r.set(dynamic_cast(other._body)); + return r; + } + const ConstHandle& operator=(const ConstHandle& other) + { + modify(other._body); + return *this; + } + bool valid() const { return _body != 0; } + UInt32 hash() const { return _body != 0 ? _body->hash() : 0; } + bool operator==(const ConstHandle& other) const + { + if (_body == 0) + return other._body == 0; + if (other._body == 0) + return false; + return _body == other._body || _body->equals(other._body); + } + bool operator!=(const ConstHandle& other) const + { + return !(*this == other); + } + template static ConstHandle + create(Args&&... args) + { + return ConstHandle(new B(std::forward(args)...), false); + } + +protected: + class Body : Uncopyable + { + public: + // A Body always start off with count 1, so that if handle() is called + // from the child constructor, the Body won't be deleted when that + // handle goes away. The owner during construction is the constructor + // itself, since that will delete the Body if an exception is thrown. + Body() : _count(1) { } + template T* as() { return static_cast(this); } + template const T* as() const + { + return static_cast(this); + } + template T* to() { return dynamic_cast(this); } + template const T* to() const + { + return dynamic_cast(this); + } + protected: + virtual ~Body() { }; + virtual void preDestroy() const { } // for HashTable::Body + virtual void destroy() const { delete this; } // for Array::Body + virtual Hash hash() const { return typeid(*this); } + virtual bool equals(const Body* other) const { return false; } + template T handle() const + { + return T(ConstHandle(this, true)); + } + private: + void release() const + { + --_count; + if (_count == 0) + destroy(); + } + void acquire() const { ++_count; } + mutable int _count; + friend class ConstHandle; + }; + + template const T* as() const { return _body->as(); } + template const T* to() const { return _body->to(); } +private: + void reset() { if (valid()) _body->release(); } + void set(const Body* body, bool acquire = true) + { + _body = body; + if (acquire && valid()) + _body->acquire(); + } + void modify(const Body* body) + { + if (body == _body) + return; + reset(); + set(body); + } + const Body* _body; + ConstHandle(const Body* body, bool acquire) { set(body, acquire); } + + friend class Handle; + friend class Any; + template friend class Array; +}; + +class Handle : private ConstHandle +{ +public: + Handle() { } + Handle(const Handle& other) : ConstHandle(other) { } + const Handle& operator=(const Handle& other) + { + ConstHandle::operator=(other); + return *this; + } + bool valid() const { return ConstHandle::valid(); } + UInt32 hash() const { return ConstHandle::hash(); } + bool operator==(const Handle& other) const + { + return ConstHandle::operator==(other); + } + bool operator!=(const Handle& other) const + { + return ConstHandle::operator!=(other); + } + template static Handle create(Args&&... args) + { + return Handle(new B(std::forward(args)...), false); + } + template static Handle to(const Handle& other) + { + Handle r; + r.set(dynamic_cast(other._body)); + return r; + } +protected: + class Body : public ConstHandle::Body + { + protected: + template T handle() { return T(ConstHandle(this, true)); } + template const T handle() const + { + return T(ConstHandle(this, true)); + } + virtual bool equals(const Body* other) const { return false; } + private: + bool equals(const ConstHandle::Body* other) const + { + return equals(static_cast(other)); + } + }; + Body* body() { return const_cast(_body)->as(); } + template const T* as() const { return ConstHandle::as(); } + template T* as() { return body()->as(); } + template const T* to() const { return ConstHandle::to(); } + template T* to() { return body()->to(); } +private: + Handle(Body* body, bool acquire) { set(body, acquire); } + Handle(ConstHandle other) : ConstHandle(other) { } + friend class ConstHandle::Body; + friend class Any; + template friend class Array; +}; + +#endif // INCLUDED_HANDLE_H diff --git a/80386/disassembler/include/alfe/hash.h b/80386/disassembler/include/alfe/hash.h new file mode 100644 index 0000000..8453674 --- /dev/null +++ b/80386/disassembler/include/alfe/hash.h @@ -0,0 +1,34 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_HASH_H +#define INCLUDED_HASH_H + +#include + +class Hash +{ +public: + // FNV-1a hash + Hash(const std::type_info& t) : _h(0x811c9dc5) + { + mixin(static_cast(t.hash_code())); + } + Hash& mixin(UInt8 v) { _h = (_h ^ v) * 0x01000193; return *this; } + Hash& mixin(UInt16 v) { return mixin(static_cast(v)).mixin(static_cast(v >> 8)); } + Hash& mixin(UInt32 v) { return mixin(static_cast(v)).mixin(static_cast(v >> 16)); } + Hash& mixin(int v) { return mixin(static_cast(v)); } + operator UInt32() const { return _h; } +private: + UInt32 _h; +}; + +template UInt32 hash(const T& t) { return t.hash(); } +UInt32 hash(int t) { return Hash(typeid(int)).mixin(t); } +UInt32 hash(DWord t) { return Hash(typeid(int)).mixin(t); } +UInt32 hash(UInt64 t) +{ + return Hash(typeid(UInt64)).mixin(static_cast(t)). + mixin(static_cast(t >> 32)); +} + +#endif // INCLUDED_HASH_H diff --git a/80386/disassembler/include/alfe/hash_table.h b/80386/disassembler/include/alfe/hash_table.h new file mode 100644 index 0000000..e38d9d7 --- /dev/null +++ b/80386/disassembler/include/alfe/hash_table.h @@ -0,0 +1,225 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_HASH_TABLE_H +#define INCLUDED_HASH_TABLE_H + +#include "alfe/tuple.h" + +// HashTable is not quite a value type, since changing an element in one table +// will affect copies of the same table. Adding an element may cause it to +// become a deep copy, if more storage space was needed. +// +// Note that the default-constructed Key should not be used for real entries. + +template class HashTableEntry +{ +public: + HashTableEntry() : _key(Key()), _value(Value()) { } + HashTableEntry(const Key& key, const Value& value) + : _key(key), _value(value) { } + const Key& key() const { return _key; } + const Value& value() const { return _value; } + Key& key() { return _key; } + Value& value() { return _value; } +private: + Key _key; + Value _value; +}; + +template class HashTableBody + : public Array>::AppendableBaseBody +{ +public: + virtual void justSetSize(int size) const = 0; + void preDestroy() const { justSetSize(this->_allocated); } + + //HashTableBody() : _misses(0) { } + + //mutable uint64_t _misses; +}; + +template class HashTable + : private AppendableArray, + HashTableBody> +{ + typedef HashTableEntry Entry; +public: + bool hasKey(const Key& key) const + { + auto e = lookup(key); + if (e != 0) + return e->key() == key; + return false; + } + Value& operator[](const Key& key) + { + auto e = lookup(key); + if (e != 0 && e->key() == key) + return e->value(); + if (count() >= this->allocated()/2) { + //dumpStats(File("tempHash.dat")); + + int n = this->allocated()*2; + if (n == 0) + n = 1; + HashTable other; + other.allocate(n); + n = other.allocated(); + other.expand(n); + other.body()->_size = 0; + for (auto i : *this) + other[i.key()] = i.value(); + *this = other; + e = lookup(key); + } + ++this->body()->_size; + e->key() = key; + return e->value(); + } + Value operator[](const Key& key) const + { + auto e = lookup(key); + if (e != 0) + return e->value(); + return Value(); + } + void add(const Key& key, const Value& value) { (*this)[key] = value; } + int count() const { return this->body() == 0 ? 0 : this->body()->_size; } + class Iterator + { + public: + const Entry& operator*() const { return *_entry; } + const Entry* operator->() const { return _entry; } + bool operator==(const Iterator& other) const + { + return _entry == other._entry; + } + bool operator!=(const Iterator& other) const + { + return !operator==(other); + } + void operator++() + { + do { + ++_entry; + if ((*this) == _table.end()) + return; + } while (_entry->key() == Key()); + } + private: + Iterator(const Entry* entry, const HashTable& table) + : _entry(entry), _table(table) { } + const Entry* _entry; + const HashTable _table; + + friend class HashTable; + }; + Iterator begin() const + { + if (this->allocated() == 0) + return Iterator(0, *this); + Iterator i(data(0), *this); + if (i->key() == Key()) + ++i; + return i; + } + Iterator end() const + { + if (this->allocated() == 0) + return Iterator(0, *this); + return Iterator(data(this->allocated()), *this); + } + template bool operator==(HashTable other) const + { + if (count() != other.count()) + return false; + for (auto i : *this) { + Key k = i.key(); + if (!other.hasKey(k)) + return false; + if (i.value() != other[k]) + return false; + } + return true; + } + template bool operator==(HashTable other) const + { + if (count() != other.count()) + return false; + for (auto i : *this) { + Key k = i.key(); + if (!other.hasKey(k)) + return false; + if (i.value() != other[k]) + return false; + } + for (auto i : other) { + K1 k = i.key(); + if (!hasKey(k)) + return false; + if (i.value() != (*this)[k]) + return false; + } + return true; + } + void dumpStats(File file) + { + //if (this->body() == 0) + // return; + //console.write("Misses: " + decimal(static_cast(this->body()->_misses)) + "," + decimal(static_cast(this->body()->_misses >> 32)) + "\n"); + //console.write("Entries: " + decimal(count()) + "\n"); + //int n = this->allocated(); + //console.write("Size: " + decimal(n) + "\n"); + //auto o = file.openWrite(); + //for (int i = 0; i < n; ++i) { + // UInt8 present = !(data(i)->key() == Key()) ? 255 : 0; + // o.write(present); + //} + } +private: + int row(const Key& key) const { return ::hash(key) % this->allocated(); } + Entry* lookup(const Key& key) + { + int n = this->allocated(); + if (n == 0) + return 0; + int r = row(key); + for (int i = 0; i < n; ++i) { + Entry* e = data(r); + if (e->key() == key || e->key() == Key()) + return e; + // We have a decent hash function so linear probing should work + // fine. + r = (r + 1)%n; + //++this->body()->_misses; + } + return 0; + } + const Entry* lookup(const Key& key) const + { + int n = this->allocated(); + if (n == 0) + return 0; + int r = row(key); + for (int i = 0; i < n; ++i) { + const Entry* e = data(r); + if (e->key() == key || e->key() == Key()) + return e; + r = (r + 1)%n; + //++this->body()->_misses; + } + return 0; + } + Entry* data(int row) + { + return &static_cast>&>(*this)[row]; + } + const Entry* data(int row) const + { + return &static_cast>&>(*this)[row]; + } +}; + +#endif // INCLUDED_HASH_TABLE_H diff --git a/80386/disassembler/include/alfe/identifier.h b/80386/disassembler/include/alfe/identifier.h new file mode 100644 index 0000000..02b0867 --- /dev/null +++ b/80386/disassembler/include/alfe/identifier.h @@ -0,0 +1,219 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_IDENTIFIER_H +#define INCLUDED_IDENTIFIER_H + +#include "alfe/operator.h" +#include "alfe/expression.h" +#include "alfe/type_specifier.h" +#include "alfe/statement.h" + +template class ResolutionPathT; +typedef ResolutionPathT ResolutionPath; + +template class IdentifierT : public ExpressionT +{ + class Body : public ExpressionT::Body + { + public: + Body(const Span& span) : Expression::Body(span) { } + Identifier identifier() const { return this->handle(); } + ValueT evaluate(Structure* context) const + { + return _path.evaluate(context, identifier()); + } + virtual bool isOperator() const = 0; + void resolve(ScopeT* scope) + { + _definition = scope->resolveVariable(identifier(), &_path); + } + TypeT type() const { return _definition.type(); } + bool mightHaveSideEffect() const { return false; } + private: + VariableDefinition _definition; + ResolutionPath _path; + }; + class NameBody : public Body + { + public: + NameBody(const String& name, const Span& span) + : Body(span), _name(name) { } + String toString() const { return _name; } + bool isOperator() const { return false; } + Hash hash() const { return Body::hash().mixin(_name.hash()); } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _name == o->_name; + } + private: + String _name; + }; + class OperatorBody : public Body + { + public: + OperatorBody(const Operator& op, const Span& span) + : Body(span), _op(op) { } + String toString() const { return "operator" + _op.toString(); } + bool isOperator() const { return true; } + Hash hash() const { return Body::hash().mixin(_op.hash()); } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _op == o->_op; + } + private: + Operator _op; + }; + +public: + IdentifierT() { } + IdentifierT(Handle other) : ExpressionT(other) { } + IdentifierT(const String& name) + : ExpressionT(IdentifierT::template create(name, Span())) + { } + IdentifierT(const char* name) + : ExpressionT(IdentifierT::template create(name, Span())) + { } + + static Identifier parse(CharacterSource* source) + { + CharacterSource s = *source; + Location location = s.location(); + int start = s.offset(); + int c = s.get(); + if (c < 'a' || c > 'z') + return Identifier(); + CharacterSource s2; + do { + s2 = s; + c = s.get(); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c == '_') + continue; + break; + } while (true); + int end = s2.offset(); + Location endLocation = s2.location(); + Space::parse(&s2); + String name = s2.subString(start, end); + static String keywords[] = { + "assembly", + "break", + "case", + "catch", + "continue", + "default", + "delete", + "do", + "done", + "else", + "elseIf", + "elseUnless", + "false", + "finally", + "from", + "for", + "forever", + "if", + "in", + "include", + "new", + "nothing", + "return", + "switch", + "this", + "throw", + "true", + "try", + "unless", + "until", + "while"}; + for (int i = 0; i < sizeof(keywords)/sizeof(keywords[0]); ++i) + if (name == keywords[i]) + return Identifier(); + Span span(location, endLocation); + if (name != "operator") { + *source = s2; + return IdentifierT::template create(name, span); + } + Span endSpan; + Span span3; + Operator o; + if (Space::parseCharacter(&s2, '(', &endSpan)) { + if (Space::parseCharacter(&s2, ')', &endSpan)) + o = OperatorFunctionCall(); + else + s2.location().throwError("Expected )"); + } + else if (Space::parseCharacter(&s2, '[', &endSpan)) { + if (Space::parseCharacter(&s2, ']', &endSpan)) + o = OperatorIndex(); + else + s2.location().throwError("Expected ]"); + } + + static const Operator ops[] = { + OperatorEqualTo(), OperatorAssignment(), OperatorAddAssignment(), + OperatorSubtractAssignment(), OperatorMultiplyAssignment(), + OperatorDivideAssignment(), OperatorModuloAssignment(), + OperatorShiftLeftAssignment(), OperatorShiftRightAssignment(), + OperatorBitwiseAndAssignment(), OperatorBitwiseOrAssignment(), + OperatorBitwiseXorAssignment(), OperatorPowerAssignment(), + OperatorBitwiseOr(), OperatorTwiddle(), OperatorNot(), + OperatorAmpersand(), OperatorNotEqualTo(), + OperatorLessThanOrEqualTo(), OperatorShiftRight(), Operator()}; + + for (const Operator* op = ops; op->valid(); ++op) { + if (o.valid()) + break; + o = op->parse(&s2, &endSpan); + } + if (!o.valid()) { + CharacterSource s3 = s2; + o = OperatorLessThan().parse(&s3, &endSpan); + if (o.valid()) { + // Only if we know it's not operator<() can we try + // operator<<() + CharacterSource s4 = s3; + TemplateArguments templateArguments = + TemplateArguments::parse(&s4); + if (templateArguments.count() == 0) { + Operator o2 = OperatorShiftLeft().parse(&s2, &endSpan); + if (o2.valid()) + o = o2; + else + s2 = s3; + } + else + s2 = s3; + } + } + + static const Operator ops2[] = { + OperatorGreaterThanOrEqualTo(), OperatorGreaterThan(), + OperatorPlus(), OperatorMinus(), OperatorDivide(), OperatorStar(), + OperatorModulo(), OperatorPower(), Operator()}; + + for (const Operator* op = ops2; op->valid(); ++op) { + if (o.valid()) + break; + o = op->parse(&s2, &endSpan); + } + if (!o.valid()) + s2.location().throwError("Expected an operator"); + *source = s2; + return Identifier(o, span + endSpan); + } + + IdentifierT(const Operator& op, const Span& span = Span()) + : Expression(IdentifierT::template create(op, span)) + { } + + bool isOperator() const { return body()->isOperator(); } + +private: + const Body* body() const { return this->template as(); } +}; + +#endif // INCLUDED_IDENTIFIER_H diff --git a/80386/disassembler/include/alfe/image_filter.h b/80386/disassembler/include/alfe/image_filter.h new file mode 100644 index 0000000..a0359ac --- /dev/null +++ b/80386/disassembler/include/alfe/image_filter.h @@ -0,0 +1,790 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_IMAGE_FILTER_H +#define INCLUDED_IMAGE_FILTER_H + +#include +#include +#include +#include "alfe/tuple.h" +#include + +float sinint(float x) +{ + float mr = 1; + if (x < 0) { + x = -x; + mr = -1; + } + if (x < 10) { + float i = 3; + float r = x; + float x2 = -x*x; + float t = x; + static const float eps = 1.0f/(1 << 16); + do { + t *= x2/(i*(i - 1)); + r += t/i; + i += 2; + } while (t < -eps || t > eps); + return r * mr; + } + float cr = 1; + float sr = 1/x; + float ct = 1; + float st = 1/x; + float i = 2; + float x2 = -1/(x*x); + do { + float lct = ct; + ct *= x2*i*(i - 1); + st *= x2*i*(i + 1); + if (abs(ct) > abs(lct) || ct == 0) + break; + cr += ct; + sr += st; + i += 2; + } while (true); + return (static_cast(tau)/4.0f - (cos(x)/x)*cr - (sin(x)/x)*sr) * mr; +} + +bool useSSE2() +{ + //return false; + + int cpuInfo[4]; + __cpuid(cpuInfo, 0); + if (cpuInfo[0] < 1) + return false; + __cpuid(cpuInfo, 1); + return (cpuInfo[3] & (1 << 26)) != 0; +} + +class AlignedBuffer +{ +public: + AlignedBuffer() { } + AlignedBuffer(int x, int y = 1) { ensure(x, y); } + // Ensure we have y suitably-aligned rows of x bytes each + void ensure(int x, int y = 1) + { + int alignment = useSSE2() ? 16 : 4; + _stride = (x + alignment - 1) & ~(alignment - 1); + size_t size = _stride*y; + size_t space = size + alignment - 1; + _buffer.ensure(space); + void* b = static_cast(&_buffer[0]); + std::align(alignment, size, b, space); + _aligned = static_cast(b); + } + Byte* data() { return _aligned; } + int stride() { return _stride; } +private: + Array _buffer; + Byte* _aligned; + int _stride; +}; + +// Filters and resamples an image horizontally using 16-bit integer arithmetic. +class ImageFilter16 +{ +public: + ImageFilter16() : _shift(6) { } + void execute() + { + Byte* inputRow = _input.data() + _inputOffset; + Byte* outputRow = _output.data(); + int* kernelSizes = &_kernelSizes[0]; + if (useSSE2()) { + for (int y = 0; y < _height; ++y) { + __m128i* kernel = + reinterpret_cast<__m128i*>(_kernelBuffer.data()); + __m128i* output = reinterpret_cast<__m128i*>(outputRow); + int* offsets = &_offsets[0]; + for (int x = 0; x < _width; ++x) { + __m128i total = _mm_set1_epi16(0); + int kernelSize = kernelSizes[x]; + for (int k = 0; k < kernelSize; ++k) { + // We need to use an unaligned load here because we + // need it to be possible for any input position to + // affect any output position. We could do this by + // duplicating each input position eight times, but + // this would probably be slower than the unaligned + // loads. + total = _mm_add_epi16(total, _mm_mullo_epi16(*kernel, + _mm_castps_si128(_mm_loadu_ps( + reinterpret_cast(inputRow + *offsets))))); + ++kernel; + ++offsets; + } + output[x] = total; + } + inputRow += _input.stride(); + outputRow += _output.stride(); + } + } + else { + for (int y = 0; y < _height; ++y) { + UInt16* kernel = + reinterpret_cast(_kernelBuffer.data()); + UInt16* output = reinterpret_cast(outputRow); + int* offsets = &_offsets[0]; + for (int x = 0; x < _width; ++x) { + UInt16 total = 0; + int kernelSize = kernelSizes[x]; + for (int k = 0; k < kernelSize; ++k) { + total += *kernel * + *reinterpret_cast(inputRow + *offsets); + ++kernel; + ++offsets; + } + output[x] = total; + } + inputRow += _input.stride(); + outputRow += _output.stride(); + } + } + } + // outputSize.x is measured in output pixels + // inputChannels is number of channels in input data + // inputChannelPositions are input pixel positions of input channels. + // outputChannels is number of channels in output data + // outputChannelPositions are output pixel positions of output channels. + // The kernel spans range -kernelRadius to kernelRadius input pixels. + // kernelFunction's arguments are distance, inputChannel, outputChannel. + // distance is outputPixel - inputPixel in input pixels + // The first value returned by the kernelFunction is the actual + // coefficient. The second value is a normalization value - the + // coefficients will be scaled by the scale factor that makes the + // scaled normalization values total to 1 for each output pixel channel. + // In inputLeft we return the leftmost input pixel that will be accessed. + // In inputRight we return the rightmost input pixel that will be + // accessed plus one. + // zoom is number of output pixels per input pixel + // offset is input position of output pixel 0. + void generate(Vector outputSize, int inputChannels, + const float* inputChannelPositions, int outputChannels, + const float* outputChannelPositions, float kernelRadius, + std::function(float, int, int)> kernelFunction, + int* inputLeft, int* inputRight, float zoom, float offset) + { + float minInputChannelPosition = std::numeric_limits::max(); + float maxInputChannelPosition = -minInputChannelPosition; + for (int c = 0; c < inputChannels; ++c) { + float p = inputChannelPositions[c]; + minInputChannelPosition = min(minInputChannelPosition, p); + maxInputChannelPosition = max(maxInputChannelPosition, p); + } + float minOutputChannelPosition = std::numeric_limits::max(); + float maxOutputChannelPosition = -minOutputChannelPosition; + for (int c = 0; c < outputChannels; ++c) { + float p = outputChannelPositions[c]; + minOutputChannelPosition = min(minOutputChannelPosition, p); + maxOutputChannelPosition = max(maxOutputChannelPosition, p); + } + + int channelsPerUnit = (useSSE2() ? 8 : 1); + _height = outputSize.y; + _width = (outputSize.x*outputChannels + channelsPerUnit - 1)/ + channelsPerUnit; + _kernelSizes.ensure(_width); + int kWidth = (static_cast(kernelRadius*2 + 1 + +maxInputChannelPosition - minInputChannelPosition + +((channelsPerUnit - 1)/outputChannels + +maxOutputChannelPosition - minOutputChannelPosition + )/zoom)*inputChannels + + channelsPerUnit - 1)/channelsPerUnit; + _kernelBuffer.ensure( + kWidth*channelsPerUnit*_width*channelsPerUnit*sizeof(UInt16)); + UInt16* kernel = reinterpret_cast(_kernelBuffer.data()); + _offsets.ensure(kWidth*_width*channelsPerUnit); + _kernelSizes.ensure(_width); + int* offsets = &_offsets[0]; + int* sizes = &_kernelSizes[0]; + float scale = static_cast(1 << _shift); + _tempKernel.ensure( + (channelsPerUnit + kWidth*channelsPerUnit)*channelsPerUnit); + _totals.ensure(inputChannels*channelsPerUnit); + + _outputLeft = std::numeric_limits::max(); + _outputRight = std::numeric_limits::min(); + + int left = std::numeric_limits::max(); + int right = std::numeric_limits::min(); + for (int x = 0; x < _width; ++x) { + int o = x*channelsPerUnit; + int kernelSize = 0; + + // Compute leftmost and rightmost possible input positions + float lp = offset - kernelRadius + 1 + + (static_cast(o / outputChannels) + + minOutputChannelPosition)/zoom + minInputChannelPosition; + if (lp < 0) + lp -= 1; + int leftInput = static_cast(lp)*inputChannels + 1 + - channelsPerUnit; + + float rp = offset + kernelRadius + + (static_cast((o + channelsPerUnit - 1) / outputChannels) + + maxOutputChannelPosition)/zoom + maxInputChannelPosition; + if (rp < 0) + rp -= 1; + int rightInput = static_cast(rp)*inputChannels + inputChannels + - 1; + + int multiple = 0; + if (leftInput < 0) + multiple = -leftInput*inputChannels; + + for (int c = 0; c < inputChannels*channelsPerUnit; ++c) + _totals[c] = 0; + int realLeftInput = leftInput; + for (int i = leftInput; i <= rightInput; ++i) { + for (int c = 0; c < channelsPerUnit; ++c) { + int ic = i + c; + int inputChannel = (ic + multiple) % inputChannels; + float inputPosition = inputChannelPositions[inputChannel] + + static_cast( + (ic - inputChannel) / inputChannels); + int oc = o + c; + int outputChannel = oc % outputChannels; + float centerInputPixel = + (static_cast(oc / outputChannels) + + outputChannelPositions[outputChannel])/zoom + offset; + float dist = centerInputPixel - inputPosition; + Tuple v(0, 0); + if (dist >= -kernelRadius && dist <= kernelRadius) + v = kernelFunction(dist, ic, outputChannel); + _totals[inputChannel*channelsPerUnit + c] += v.second(); + _tempKernel[(i - leftInput)*channelsPerUnit + c] = + v.first(); + } + } + for (int c = 0; c < channelsPerUnit*inputChannels; ++c) + _totals[c] = 1/_totals[c]; + for (int i = leftInput; i <= rightInput; ++i) { + int lastC = 0; + for (int c = 0; c < channelsPerUnit; ++c) { + int v = static_cast(round(scale* + _tempKernel[(i - leftInput)*channelsPerUnit + c]* + _totals[((i + c + multiple) % inputChannels)* + channelsPerUnit + c])); + if (v != 0) { + int op = (o + c + outputChannels - 1)/outputChannels; + if (op >= 0) + _outputLeft = min(_outputLeft, op); + if (op < outputSize.x) + _outputRight = max(_outputRight, op + 1); + if (lastC == 0) { + realLeftInput = i; + left = min(left, realLeftInput); + *offsets = realLeftInput*sizeof(UInt16); + ++offsets; + ++kernelSize; + } + for (; lastC < c; ++lastC) { + *kernel = 0; + ++kernel; + } + *kernel = v; + ++kernel; + ++lastC; + } + } + if (lastC != 0) { + for (; lastC < channelsPerUnit; ++lastC) { + *kernel = 0; + ++kernel; + } + right = max(right, i); + } + } + sizes[x] = kernelSize; + } + if (left < 0) + *inputLeft = (left - (inputChannels - 1))/inputChannels; + else + *inputLeft = left/inputChannels; + if (right < 0) + *inputRight = (right - (inputChannels - 1))/inputChannels + 1; + else + *inputRight = right/inputChannels + 1; + + _inputOffset = -*inputLeft*inputChannels*sizeof(UInt16); + } + void setBuffers(AlignedBuffer input, AlignedBuffer output) + { + _input = input; + _output = output; + } + int outputLeft() const { return _outputLeft; } + int outputRight() const { return _outputRight; } + void setShift(int shift) { _shift = shift; } + int shift() const { return _shift; } + +private: + // Buffers + AlignedBuffer _kernelBuffer; + Array _offsets; + Array _kernelSizes; + AlignedBuffer _input; + AlignedBuffer _output; + Array _tempKernel; + Array _totals; + + // Parameters + int _width; + int _height; + int _inputStride; + int _outputStride; + int _inputOffset; + int _shift; + + int _outputLeft; + int _outputRight; +}; + +// Filters and resamples an image horizontally using single-precision +// floating-point arithmetic. +class ImageFilterHorizontal +{ +public: + void execute() + { + Byte* inputRow = _input.data() + _inputOffset; + Byte* outputRow = _output.data(); + int* kernelSizes = &_kernelSizes[0]; + if (useSSE2()) { + for (int y = 0; y < _height; ++y) { + __m128* kernel = + reinterpret_cast<__m128*>(_kernelBuffer.data()); + __m128* output = reinterpret_cast<__m128*>(outputRow); + int* offsets = &_offsets[0]; + for (int x = 0; x < _width; ++x) { + __m128 total = _mm_set1_ps(0.0f); + int kernelSize = kernelSizes[x]; + for (int k = 0; k < kernelSize; ++k) { + // We need to use an unaligned load here because we + // need it to be possible for any input position to + // affect any output position. We could do this by + // duplicating each input position four times, but this + // would probably be slower than the unaligned loads. + total = _mm_add_ps(total, _mm_mul_ps(*kernel, + _mm_loadu_ps(reinterpret_cast(inputRow + + *offsets)))); + ++kernel; + ++offsets; + } + output[x] = total; + } + inputRow += _input.stride(); + outputRow += _output.stride(); + } + } + else { + for (int y = 0; y < _height; ++y) { + float* kernel = reinterpret_cast(_kernelBuffer.data()); + float* output = reinterpret_cast(outputRow); + int* offsets = &_offsets[0]; + for (int x = 0; x < _width; ++x) { + float total = 0; + int kernelSize = kernelSizes[x]; + for (int k = 0; k < kernelSize; ++k) { + total += *kernel * + *reinterpret_cast(inputRow + *offsets); + ++kernel; + ++offsets; + } + output[x] = total; + } + inputRow += _input.stride(); + outputRow += _output.stride(); + } + } + } + // outputSize.x is measured in output pixels + // inputChannels is number of channels in input data + // inputChannelPositions are input pixel positions of input channels. + // outputChannels is number of channels in output data + // outputChannelPositions are output pixel positions of output channels. + // The kernel spans range -kernelRadius to kernelRadius input pixels. + // kernelFunction's arguments are distance, inputChannel, outputChannel. + // distance is outputPixel - inputPixel in input pixels + // The first value returned by the kernelFunction is the actual + // coefficient. The second value is a normalization value - the + // coefficients will be scaled by the scale factor that makes the + // scaled normalization values total to 1 for each output pixel channel. + // In inputLeft we return the leftmost input pixel that will be accessed. + // In inputRight we return the rightmost input pixel that will be + // accessed plus one. + // zoom is number of output pixels per input pixel + // offset is input position of output pixel 0. + void generate(Vector outputSize, int inputChannels, + const float* inputChannelPositions, int outputChannels, + const float* outputChannelPositions, float kernelRadius, + std::function(float, int, int)> kernelFunction, + int* inputLeft, int* inputRight, float zoom, float offset) + { + float minInputChannelPosition = std::numeric_limits::max(); + float maxInputChannelPosition = -minInputChannelPosition; + for (int c = 0; c < inputChannels; ++c) { + float p = inputChannelPositions[c]; + minInputChannelPosition = min(minInputChannelPosition, p); + maxInputChannelPosition = max(maxInputChannelPosition, p); + } + float minOutputChannelPosition = std::numeric_limits::max(); + float maxOutputChannelPosition = -minOutputChannelPosition; + for (int c = 0; c < outputChannels; ++c) { + float p = outputChannelPositions[c]; + minOutputChannelPosition = min(minOutputChannelPosition, p); + maxOutputChannelPosition = max(maxOutputChannelPosition, p); + } + int channelsPerUnit = (useSSE2() ? 4 : 1); + _totals.ensure(inputChannels*channelsPerUnit); + _height = outputSize.y; + _width = (outputSize.x*outputChannels + channelsPerUnit - 1)/ + channelsPerUnit; + _kernelSizes.ensure(_width); + int kWidth = (static_cast(kernelRadius*2 + 1 + +maxInputChannelPosition - minInputChannelPosition + +((channelsPerUnit - 1)/outputChannels + +maxOutputChannelPosition - minOutputChannelPosition + )/zoom)*inputChannels + + channelsPerUnit - 1)/channelsPerUnit; + _kernelBuffer.ensure( + kWidth*channelsPerUnit*_width*channelsPerUnit*sizeof(float)); + float* kernel = reinterpret_cast(_kernelBuffer.data()); + _offsets.ensure(kWidth*_width*channelsPerUnit); + _kernelSizes.ensure(_width); + int* offsets = &_offsets[0]; + int* sizes = &_kernelSizes[0]; + + _outputLeft = std::numeric_limits::max(); + _outputRight = std::numeric_limits::min(); + + int left = std::numeric_limits::max(); + int right = std::numeric_limits::min(); + for (int x = 0; x < _width; ++x) { + int o = x*channelsPerUnit; + int kernelSize = 0; + + // Compute leftmost and rightmost possible input positions + float lp = offset - kernelRadius + 1 + + (static_cast(o / outputChannels) + + minOutputChannelPosition)/zoom + minInputChannelPosition; + if (lp < 0) + lp -= 1; + int leftInput = static_cast(lp)*inputChannels + 1 + - channelsPerUnit; + + float rp = offset + kernelRadius + + (static_cast((o + channelsPerUnit - 1) / outputChannels) + + maxOutputChannelPosition)/zoom + maxInputChannelPosition; + if (rp < 0) + rp -= 1; + int rightInput = static_cast(rp)*inputChannels + inputChannels + - 1; + + int multiple = 0; + if (leftInput < 0) + multiple = -leftInput*inputChannels; + + for (int c = 0; c < inputChannels*channelsPerUnit; ++c) + _totals[c] = 0; + float* kernelStart = kernel; + int* offsetsStart = offsets; + for (int i = leftInput; i <= rightInput; ++i) { + int lastC = 0; + for (int c = 0; c < channelsPerUnit; ++c) { + int ic = i + c; + int inputChannel = (ic + multiple) % inputChannels; + float inputPosition = inputChannelPositions[inputChannel] + + static_cast( + (ic - inputChannel) / inputChannels); + int oc = o + c; + int outputChannel = oc % outputChannels; + float centerInputPixel = + (static_cast(oc / outputChannels) + + outputChannelPositions[outputChannel])/zoom + offset; + float dist = centerInputPixel - inputPosition; + Tuple v(0, 0); + if (dist >= -kernelRadius && dist <= kernelRadius) + v = kernelFunction(dist, ic, outputChannel); + _totals[inputChannel*channelsPerUnit + c] += v.second(); + if (v.first() != 0) { + int op = (oc + outputChannels - 1)/outputChannels; + if (op >= 0) + _outputLeft = min(_outputLeft, op); + if (op < outputSize.x) + _outputRight = max(_outputRight, op + 1); + if (lastC == 0) { + left = min(left, i); + *offsets = i*sizeof(float); + ++offsets; + ++kernelSize; + } + for (; lastC < c; ++lastC) { + *kernel = 0; + ++kernel; + } + *kernel = v.first(); + ++kernel; + ++lastC; + } + } + if (lastC != 0) { + for (; lastC < channelsPerUnit; ++lastC) { + *kernel = 0; + ++kernel; + } + right = max(right, i); + } + } + for (int c = 0; c < channelsPerUnit*inputChannels; ++c) + _totals[c] = 1/_totals[c]; + for (;kernelStart != kernel; kernelStart += channelsPerUnit) { + int i = *offsetsStart/static_cast(sizeof(float)) + + multiple; + for (int c = 0; c < channelsPerUnit; ++c) { + kernelStart[c] *= _totals[c + + channelsPerUnit*((i + c) % inputChannels)]; + } + ++offsetsStart; + } + sizes[x] = kernelSize; + } + if (left < 0) + *inputLeft = (left - (inputChannels - 1))/inputChannels; + else + *inputLeft = left/inputChannels; + if (right < 0) + *inputRight = (right - (inputChannels - 1))/inputChannels + 1; + else + *inputRight = right/inputChannels + 1; + + _inputOffset = -*inputLeft*inputChannels*sizeof(float); + } + void setBuffers(AlignedBuffer input, AlignedBuffer output) + { + _input = input; + _output = output; + } + int outputLeft() const { return _outputLeft; } + int outputRight() const { return _outputRight; } + +private: + // Buffers + AlignedBuffer _kernelBuffer; + Array _offsets; + Array _kernelSizes; + AlignedBuffer _input; + AlignedBuffer _output; + Array _totals; + + // Parameters + int _width; + int _height; + int _inputStride; + int _outputStride; + int _inputOffset; + + int _outputLeft; + int _outputRight; +}; + +// Filters and resamples an image vertically using single-precision +// floating-point arithmetic. +class ImageFilterVertical +{ +public: + void execute() + { + Byte* inputStart = _input.data() + _inputOffset; + Byte* outputRow = _output.data(); + Byte* kernel = _kernelBuffer.data(); + int* offsets = &_offsets[0]; + int* kernelSizes = &_kernelSizes[0]; + if (useSSE2()) { + for (int y = 0; y < _height; ++y) { + int kernelSize = kernelSizes[y]; + int offset = offsets[y]; + Byte* inputColumn = inputStart; + for (int x = 0; x < _width; ++x) { + Byte* input = inputColumn + offset; + __m128 total = _mm_set1_ps(0.0f); + for (int k = 0; k < kernelSize; ++k) { + total = _mm_add_ps(total, _mm_mul_ps( + reinterpret_cast<__m128*>(kernel)[k], + *reinterpret_cast<__m128*>(input))); + input += _input.stride(); + } + inputColumn += sizeof(__m128); + reinterpret_cast<__m128*>(outputRow)[x] = total; + } + outputRow += _output.stride(); + kernel += kernelSize*sizeof(__m128); + } + } + else { + for (int y = 0; y < _height; ++y) { + int kernelSize = kernelSizes[y]; + int offset = offsets[y]; + Byte* inputColumn = inputStart; + for (int x = 0; x < _width; ++x) { + Byte* input = inputColumn + offset; + float total = 0; + for (int k = 0; k < kernelSize; ++k) { + total += reinterpret_cast(kernel)[k] * + *reinterpret_cast(input); + input += _input.stride(); + } + inputColumn += sizeof(float); + reinterpret_cast(outputRow)[x] = total; + } + outputRow += _output.stride(); + kernel += kernelSize*sizeof(float); + } + } + } + // outputSize.x is measured in output channels and should be a multiple of + // channelsPerUnit + // outputSize.y is measured in output pixels + // The kernel spans range -kernelRadius to kernelRadius input pixels. + // kernelFunction's argument is outputPixel - inputPixel in input pixels + // The first value returned by the kernelFunction is the actual + // coefficient. The second value is a normalization value - the + // coefficients will be scaled by the scale factor that makes the + // scaled normalization values total to 1 for each output pixel channel. + // In inputTop we return the topmost input pixel that will be accessed. + // In inputBottom we return the bottommost input pixel that will be + // accessed plus one. + // zoom is number of output pixels per input pixel + // offset is input position of output pixel 0. + void generate(Vector outputSize, int channels, float kernelRadius, + std::function(float)> kernelFunction, int* inputTop, + int* inputBottom, float zoom, float offset) + { + _height = outputSize.y; + + int nTotals = 4 + static_cast(kernelRadius)*2 + + static_cast(static_cast(_height - 1)/zoom); + Array totals(nTotals); + int totalsOffset = 1 + static_cast(kernelRadius) - static_cast(offset); + for (int i = 0; i < nTotals; ++i) { + float ii = static_cast(i - totalsOffset); + float total = 0; + float tp = (ii - kernelRadius - offset)*zoom; + int topOutput = static_cast(tp); + float bp = (ii + kernelRadius - offset)*zoom; + int bottomOutput = static_cast(bp); + for (int y = topOutput; y <= bottomOutput; ++y) { + float dist = static_cast(y)/zoom + offset - ii; + if (dist >= -kernelRadius && dist <= kernelRadius) + total += kernelFunction(dist).second(); + } + totals[i] = total; + } + + int channelsPerUnit = (useSSE2() ? 4 : 1); + _width = (outputSize.x*channels + channelsPerUnit - 1)/ + channelsPerUnit; + _kernelSizes.ensure(_height); + int kWidth = static_cast(kernelRadius*2 + 1); + _kernelBuffer.ensure(kWidth*channelsPerUnit*_height*sizeof(float)); + float* kernel = reinterpret_cast(_kernelBuffer.data()); + _offsetCounts.ensure(_height); + _offsets.ensure(_height); + _kernelSizes.ensure(_height); + int* offsets = &_offsetCounts[0]; + int* sizes = &_kernelSizes[0]; + + int top = std::numeric_limits::max(); + int bottom = std::numeric_limits::min(); + for (int y = 0; y < _height; ++y) { + // Compute topmost and bottommost possible input positions + float tp = offset - kernelRadius + 1 + static_cast(y)/zoom; + if (tp < 0) + tp -= 1; + int topInput = static_cast(tp); + + float bp = offset + kernelRadius + static_cast(y)/zoom; + if (bp < 0) + bp -= 1; + int bottomInput = static_cast(bp); + + float centerInputPixel = static_cast(y)/zoom + offset; + + float* kernelStart = kernel; + int realTop = bottomInput + 1; + int realBottom; + for (int i = topInput; i <= bottomInput; ++i) { + float dist = centerInputPixel - static_cast(i); + Tuple v(0, 0); + if (dist >= -kernelRadius && dist <= kernelRadius) + v = kernelFunction(dist); + if (v.first() != 0) { + v.first() *= zoom/totals[i + totalsOffset]; + if (realTop <= bottomInput) { + ++realBottom; + for (;realBottom < i; ++realBottom) { + for (int x = 0; x < channelsPerUnit; ++x) { + *kernel = v.first(); + ++kernel; + } + } + } + else + realTop = i; + realBottom = i; + for (int x = 0; x < channelsPerUnit; ++x) { + *kernel = v.first(); + ++kernel; + } + } + } + if (realTop > bottomInput) { + realTop = bottomInput; + realBottom = bottomInput; + for (int x = 0; x < channelsPerUnit; ++x) { + *kernel = 0; + ++kernel; + } + } + sizes[y] = 1 + realBottom - realTop; + offsets[y] = realTop; + top = min(top, realTop); + bottom = max(bottom, realBottom); + } + *inputTop = top; + *inputBottom = bottom + 1; + + _inputOffsetCount = -top; + } + void setBuffers(AlignedBuffer input, AlignedBuffer output) + { + _input = input; + _output = output; + for (int y = 0; y < _height; ++y) + _offsets[y] = _offsetCounts[y]*_input.stride(); + _inputOffset = _inputOffsetCount * _input.stride(); + } + +private: + // Buffers + AlignedBuffer _kernelBuffer; + Array _offsetCounts; + Array _offsets; + Array _kernelSizes; + AlignedBuffer _input; + AlignedBuffer _output; + + // Parameters + int _width; + int _height; + int _inputStride; + int _outputStride; + int _inputOffsetCount; + int _inputOffset; +}; + +#endif // INCLUDED_IMAGE_FILTER_H diff --git a/80386/disassembler/include/alfe/integer_functions.h b/80386/disassembler/include/alfe/integer_functions.h new file mode 100644 index 0000000..f090bf3 --- /dev/null +++ b/80386/disassembler/include/alfe/integer_functions.h @@ -0,0 +1,229 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_INTEGER_FUNCTIONS_H +#define INCLUDED_INTEGER_FUNCTIONS_H + +#include "alfe/function.h" + +class AddIntegerInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l + i->value()); + } + Identifier identifier() const { return OperatorPlus(); } + FunctionType type() const + { + return FunctionType(IntegerType(), IntegerType(), IntegerType()); + } + }; +}; + +class SubtractIntegerInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l - i->value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return FunctionType(IntegerType(), IntegerType(), IntegerType()); + } + }; +}; + +class MultiplyIntegerInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l * i->value()); + } + Identifier identifier() const { return OperatorStar(); } + FunctionType type() const + { + return FunctionType(IntegerType(), IntegerType(), IntegerType()); + } + }; +}; + +class ShiftLeftIntegerInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + int r = i->value(); + if (r < 0) + return Rational(l, 1 << -r); + return l << r; + } + Identifier identifier() const { return OperatorShiftLeft(); } + FunctionType type() const + { + return FunctionType(RationalType(), IntegerType(), IntegerType()); + } + }; +}; + +class ShiftRightIntegerInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + int r = i->value(); + if (r < 0) + return l << -r; + return Rational(l, 1 << r); + } + Identifier identifier() const { return OperatorShiftRight(); } + FunctionType type() const + { + return FunctionType(RationalType(), IntegerType(), IntegerType()); + } + }; +}; + +class LessThanIntegerInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l < i->value()); + } + Identifier identifier() const { return OperatorLessThan(); } + FunctionType type() const + { + return FunctionType(BooleanType(), IntegerType(), IntegerType()); + } + }; +}; + +class GreaterThanIntegerInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l > i->value()); + } + Identifier identifier() const { return OperatorGreaterThan(); } + FunctionType type() const + { + return FunctionType(BooleanType(), IntegerType(), IntegerType()); + } + }; +}; + +class LessThanOrEqualToIntegerInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l <= i->value()); + } + Identifier identifier() const { return OperatorLessThanOrEqualTo(); } + FunctionType type() const + { + return FunctionType(BooleanType(), IntegerType(), IntegerType()); + } + }; +}; + +class GreaterThanOrEqualToIntegerInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l >= i->value()); + } + Identifier identifier() const + { + return OperatorGreaterThanOrEqualTo(); + } + FunctionType type() const + { + return FunctionType(BooleanType(), IntegerType(), IntegerType()); + } + }; +}; + +class NegativeInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + return Value( - arguments.begin()->value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return FunctionType(IntegerType(), IntegerType()); + } + }; +}; + +#endif // INCLUDED_INTEGER_FUNCTIONS_H \ No newline at end of file diff --git a/80386/disassembler/include/alfe/integer_types.h b/80386/disassembler/include/alfe/integer_types.h new file mode 100644 index 0000000..e9f3589 --- /dev/null +++ b/80386/disassembler/include/alfe/integer_types.h @@ -0,0 +1,37 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_INTEGER_TYPES_H +#define INCLUDED_INTEGER_TYPES_H + +typedef unsigned char UInt8; +typedef signed char SInt8; +typedef char Int8; +typedef unsigned short int UInt16; +typedef signed short int SInt16; +typedef short int Int16; +typedef unsigned int UInt32; +typedef signed int SInt32; +typedef int Int32; +#ifdef _WIN32 +typedef unsigned _int64 UInt64; +typedef signed _int64 SInt64; +typedef _int64 Int64; +#else +#include +typedef uint64_t UInt64; +typedef int64_t SInt64; +typedef int64_t Int64; +#endif + +typedef UInt8 Byte; +typedef UInt16 Word; +typedef UInt32 DWord; +typedef UInt64 QWord; + +typedef void Void; + +typedef SInt32 PSInt; +typedef UInt32 PUInt; +typedef PSInt PointerDifference; + +#endif // INCLUDED_INTEGER_TYPES_H diff --git a/80386/disassembler/include/alfe/io_dispatch.h b/80386/disassembler/include/alfe/io_dispatch.h new file mode 100644 index 0000000..d16cc7c --- /dev/null +++ b/80386/disassembler/include/alfe/io_dispatch.h @@ -0,0 +1,57 @@ +#ifndef INCLUDED_IO_DISPATCH_H +#define INCLUDED_IO_DISPATCH_H + +class IODispatch : Uncopyable +{ +public: + IODispatch() : _n(0) { } + class Task : Uncopyable + { + public: + virtual void signalled() = 0; + virtual WindowsHandle handle() = 0; + void remove() { _dispatch->remove(this); } + private: + void setDispatch(IODispatch* dispatch) { _dispatch = dispatch; } + IODispatch* _dispatch; + friend class IODispatch; + }; + + void run() + { + while (_n > 0) { + int r = WaitForMultipleObjects(_n, &_handles[0], FALSE, INFINITE); + _tasks[r]->signalled(); + } + } + void add(Task* task) + { + if (_handles.count() > _n) { + _handles[_n] = task->handle(); + _tasks[_n] = task; + } + else { + _handles.append(task->handle()); + _tasks.append(task); + } + task->setDispatch(this); + ++_n; + } + void remove(Task* task) + { + for (int i = 0; i < _n; ++i) { + if (_tasks[i] == task) { + swap(_tasks[i], _tasks[_n - 1]); + swap(_handles[i], _handles[_n - 1]); + --_n; + break; + } + } + } +private: + AppendableArray _handles; + AppendableArray _tasks; + int _n; +}; + +#endif // INCLUDED_IO_DISPATCH_H diff --git a/80386/disassembler/include/alfe/julian.h b/80386/disassembler/include/alfe/julian.h new file mode 100644 index 0000000..0871cef --- /dev/null +++ b/80386/disassembler/include/alfe/julian.h @@ -0,0 +1,47 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_JULIAN_H +#define INCLUDED_JULIAN_H + +/* This function returns TRUE if year is a leap year, FALSE otherwise */ +bool isleapyear(int year) +{ + return (((year % 400) == 0) || (((year % 4) == 0) && ((year % 100) != 0))); +} /* isleapyear */ + +/* This function determines if the number of days in month month. Fleap is TRUE + if the year is a leap year. */ +int daysinmonth(int month, bool fleap) +{ + if (month == 2) + if (fleap) + return 29; + else + return 28; + else + if (((month & 8) >> 3) != (month & 1)) + return 31; + else + return 30; +} /* daysinmonth */ + +/* This function returns the Julian equivalent of the date (day, month, year) +*/ +long int greg2jul(int day, int month, int year) +{ + long int j; + int dim; + long int numleaps; + bool fleap = isleapyear(year); + j = day; + for (dim = 1; dim < month; dim++) + j += daysinmonth(dim, false); + if (fleap && month > 2) + j++; + year--; + numleaps = (year / 4) - (year / 100) + (year / 400); + j += ((long)year * 365 + numleaps); + return j; +} /* greg2jul */ + +#endif // INCLUDED_JULIAN_H diff --git a/80386/disassembler/include/alfe/kind.h b/80386/disassembler/include/alfe/kind.h new file mode 100644 index 0000000..1e959ca --- /dev/null +++ b/80386/disassembler/include/alfe/kind.h @@ -0,0 +1,141 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_KIND_H +#define INCLUDED_KIND_H + +#include "alfe/nullary.h" +#include "alfe/string.h" +#include "alfe/handle.h" + +// Kind constructors. See: +// http://www.reenigne.org/blog/templates-and-kinds-in-alfe +// http://www.reenigne.org/blog/variadic-templates-in-alfe +// for more information. + +class Kind : public ConstHandle +{ +public: + Kind() { } + Kind(const ConstHandle other) : ConstHandle(other) { } + String toString() const { return body()->toString(); } + bool operator!=(const Kind& other) const { return !operator==(other); } + Kind instantiate(Kind argument) const + { + return body()->instantiate(argument); + } +protected: + class Body : public ConstHandle::Body + { + public: + virtual String toString() const = 0; + virtual Kind instantiate(Kind argument) const = 0; + Kind kind() const { return handle(); } + }; + const Body* body() const { return as(); } +private: + friend class TemplateKind; +}; + +// TypeKind is the kind of tycos that describe the types of variables, values +// and expressions. +class TypeKind : public NamedNullary +{ +public: + static String name() { return String(); } + + class Body : public NamedNullary::Body + { + public: + Kind instantiate(Kind argument) const { return Kind(); } + }; +}; + +// VariadicTemplateKind is the kind of a template with a variable number of +// arguments that are not kind-checked before use. +class VariadicTemplateKind : public NamedNullary +{ +public: + static String name() { return "<...>"; } + + class Body : public NamedNullary::Body + { + public: + Kind instantiate(Kind argument) const + { + return VariadicTemplateKind(); + } + }; +}; + +// TemplateKind(first, rest) is the kind of a template that yields a tyco of +// kind "rest" when instantiated with a tyco of kind "first". +class TemplateKind : public Kind +{ +public: + TemplateKind(const Kind& firstParameterKind, const Kind& restParameterKind) + : Kind(create(firstParameterKind, restParameterKind)) { } + TemplateKind(const Kind& kind) : Kind(kind) { } + Kind first() const { return body()->first(); } + Kind rest() const { return body()->rest(); } +protected: + class Body : public Kind::Body + { + public: + Body(const Kind& firstParameterKind, + const Kind& restParameterKind) + : _firstParameterKind(firstParameterKind), + _restParameterKind(restParameterKind) { } + String toString() const { return "<" + toString2(); } + String toString2() const + { + Kind k = kind(); + bool needComma = false; + String s; + do { + if (needComma) + s += ", "; + if (k == VariadicTemplateKind()) + return s + "...>"; + if (k == TypeKind()) + return s + ">"; + TemplateKind t = kind(); + s += t.first().toString(); + k = t.rest(); + needComma = true; + } while (true); + } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _firstParameterKind == o->_firstParameterKind && + _restParameterKind == o->_restParameterKind; + } + Hash hash() const + { + return Kind::Body::hash().mixin(_firstParameterKind.hash()). + mixin((_restParameterKind.hash())); + } + Kind first() const { return _firstParameterKind; } + Kind rest() const { return _restParameterKind; } + Kind instantiate(Kind argument) const + { + // A tyco of kind VariadicTemplateKind can act as a type or a + // template of any kind so (for the purposes of initial kind + // checking) such a tyco can be passed to any template. Note that + // the tyco will probably perform its own kind checking when + // instantiated, so that there will be a suitable error when, say, + // a Tuple is passed to a template of kind <<<>>>. + + if (argument == _firstParameterKind || + argument == VariadicTemplateKind()) + return _restParameterKind; + return Kind(); + } + private: + Kind _firstParameterKind; + Kind _restParameterKind; + }; + const Body* body() const { return as(); } +}; + +#endif // INCLUDED_KIND_H diff --git a/80386/disassembler/include/alfe/knob.h b/80386/disassembler/include/alfe/knob.h new file mode 100644 index 0000000..855b98d --- /dev/null +++ b/80386/disassembler/include/alfe/knob.h @@ -0,0 +1,754 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_KNOB_H +#define INCLUDED_KNOB_H + +const COLORREF chromaKey = RGB(0xff, 0x0, 0xff); + +template class KnobSliderT; +typedef KnobSliderT KnobSlider; + +template class KnobSlidersT; +typedef KnobSlidersT KnobSliders; + +template class KnobSlidersT : public WindowsWindow +{ +public: + KnobSlidersT() + : _delta(0, -1), _hdcScreen(NULL), + _hdcSrc(CreateCompatibleDC(_hdcScreen)), _renderTask(this), + _useChromaKey(false), _sliding(false) + { + setStyle(WS_POPUP); + setExtendedStyle(WS_EX_LAYERED); + _hbmBackBuffer = + GDIObject(CreateCompatibleBitmap(_hdcScreen, 100, 100)); + _hbmOld = SelectedObject(&_hdcSrc, _hbmBackBuffer); + } +protected: + void create() + { + ZeroMemory(&_bmi, sizeof(BITMAPINFO)); + _bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + _bmi.bmiHeader.biPlanes = 1; + _bmi.bmiHeader.biBitCount = 32; + _bmi.bmiHeader.biCompression = BI_RGB; + _bmi.bmiHeader.biSizeImage = 0; + _bmi.bmiHeader.biXPelsPerMeter = 0; + _bmi.bmiHeader.biYPelsPerMeter = 0; + _bmi.bmiHeader.biClrUsed = 0; + _bmi.bmiHeader.biClrImportant = 0; + WindowsWindow::create(); + } + virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + if (uMsg == WM_PAINT) { + Lock lock(&_mutex); + if (_useChromaKey) { + PaintHandle p(this); + setDIBits(p, p.topLeft(), p.bottomRight(), _s); + return 0; + } + } + return WindowsWindow::handleMessage(uMsg, wParam, lParam); + } +private: + bool knobEvent(KnobSlider* slider, Vector drag, bool buttonDown) + { + _slider = slider; + if (!slider->_enabled) + buttonDown = false; + if (buttonDown) { + if (!_sliding) { + _dragStart = drag; + _positionStart = slider->position(); + show(SW_SHOW); + update(drag); + } + else + update(drag); + } + if (!buttonDown && _sliding) + show(SW_HIDE); + _sliding = buttonDown; + return buttonDown; // Capture when button is down + } + void drawKnob(KnobSlider* slider) + { + _slider = slider; + _renderTask.restart(); + _renderTask.join(); + } + void update(Vector drag) + { + { + Lock lock(&_mutex); + int length = _slider->_popupLength; + Vector2 delta = Vector2Cast(drag - _dragStart); + double distance = sqrt(delta.modulus2()); + double position; + if (distance < 40) { + position = _positionStart + dot(delta, _delta)/length; + _a = _delta*length; + } + else { + _delta = delta/sqrt(delta.modulus2()); + if (delta.x < delta.y) { + distance = -distance; + _delta = -_delta; + } + position = _positionStart + distance/length; + _a = delta/(position - _positionStart); + } + _slider->setPosition(clamp(0.0, position, 1.0)); + } + + _renderTask.restart(); + } + void render() + { + Vector2 corners[4]; + Vector2 low; + Vector2 high; + Vector topLeft; + int length; + double position; + bool sliding; + { + Lock lock(&_mutex); + position = _slider->position(); + sliding = _sliding; + if (sliding) { + length = _slider->_popupLength; + + low = Vector2Cast(_dragStart) - _a*_positionStart; + high = _a + low; + + double endPadding = _slider->outerSize().y/4; + Vector2 x = (high - low)*endPadding/length; + Vector2 y = 2.0*Vector2(x.y, -x.x); + corners[0] = Vector2Cast(low - x - y); + corners[1] = Vector2Cast(low - x + y); + corners[2] = Vector2Cast(high + x - y); + corners[3] = Vector2Cast(high + x + y); + + topLeft = Vector2Cast(corners[0]); + Vector bottomRight = topLeft + Vector(1, 1); + for (int i = 1; i < 4; ++i) { + Vector c = Vector2Cast(corners[i]); + topLeft.x = min(topLeft.x, c.x); + topLeft.y = min(topLeft.y, c.y); + bottomRight.x = max(bottomRight.x, c.x + 1); + bottomRight.y = max(bottomRight.y, c.y + 1); + } + + _s = bottomRight - topLeft; + if (_s.x > _bitmap.size().x || _s.y > _bitmap.size().y) { + _bitmap = Bitmap(Vector(max(_s.x, _bitmap.size().x), + max(_s.y, _bitmap.size().y))); + _hbmOld = SelectedObject(); + _hbmBackBuffer = GDIObject(CreateCompatibleBitmap( + _hdcScreen, _bitmap.size().x, _bitmap.size().y)); + _hbmOld = SelectedObject(&_hdcSrc, _hbmBackBuffer); + } + } + } + + KnobSlider::KnobWindow* knob = &_slider->_knob; + Vector ks = knob->innerSize(); + Vector2 c = Vector2Cast(ks)/2.0; + Bitmap b = knob->bitmap(); + b.fill(_slider->_lightGrey); + fillCircle(b, + _slider->_enabled ? _slider->_darkGrey : _slider->_disabledGrey, + Vector2Cast(c), static_cast(ks.x/2.0)); + Rotor2 r(-clamp(0.0, position, 1.0)*3/4); + Vector2 o = Vector2(-1, 1)*r*ks.x/sqrt(8) + c; + Vector2 w = Vector2(1, 1)*r; + Vector2 points[4]; + points[0] = Vector2Cast(c - w); + points[1] = Vector2Cast(c + w); + points[2] = Vector2Cast(o - w); + points[3] = Vector2Cast(o + w); + fillParallelogram(b, &points[0], + _slider->_enabled ? _slider->_black : _slider->_darkGrey); + knob->invalidate(); + + if (!sliding) + return; + + for (int i = 0; i < 4; ++i) + corners[i] -= Vector2Cast(topLeft); + low -= topLeft; + high -= topLeft; + // Transparent + if (_useChromaKey) + _bitmap.fill(0xff000000 | chromaKey); + else + _bitmap.fill(0); + + // Background + fillParallelogram(_bitmap, &corners[0], _slider->_lightGrey, + !_useChromaKey); + + // Track + Vector2 x = (high - low)*2/length; + Vector2 y = Vector2(x.y, -x.x); + corners[0] = Vector2Cast(low - y); + corners[1] = Vector2Cast(low + y); + corners[2] = Vector2Cast(high - y); + corners[3] = Vector2Cast(high + y); + fillParallelogram(_bitmap, &corners[0], _slider->_darkGrey); + + // Handle + double endPadding = _slider->outerSize().y/4; + x = (high - low)*endPadding/(length*2); + y = 2.0*Vector2(x.y, -x.x); + Vector2 p = low + position*(high - low); + corners[0] = Vector2Cast(p - x - y); + corners[1] = Vector2Cast(p - x + y); + corners[2] = Vector2Cast(p + x - y); + corners[3] = Vector2Cast(p + x + y); + fillParallelogram(_bitmap, &corners[0], _slider->_black); + + setInnerSize(_s); + if (_useChromaKey) { + setTopLeft(topLeft); + invalidate(); + return; + } + + setDIBits(_hdcSrc, Vector(0, 0), _s, _s); + POINT ptSrc; + ptSrc.x = 0; + ptSrc.y = 0; + SIZE size; + size.cx = _s.x; + size.cy = _s.y; + POINT ptDst; + ptDst.x = topLeft.x; + ptDst.y = topLeft.y; + BLENDFUNCTION blend; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 255; + blend.AlphaFormat = AC_SRC_ALPHA; + BOOL result = UpdateLayeredWindow(_hWnd, NULL, &ptDst, &size, _hdcSrc, + &ptSrc, 0, &blend, ULW_ALPHA); + if (result == 0) { + { + Lock lock(&_mutex); + _useChromaKey = true; + } + IF_ZERO_THROW(SetLayeredWindowAttributes(_hWnd, chromaKey, 255, + LWA_COLORKEY)); + _renderTask.restart(); + } + } + class RenderTask : public ThreadTask + { + public: + RenderTask(KnobSliders* window) : _window(window) { } + void run() { _window->render(); } + private: + KnobSliders* _window; + }; + void setDIBits(HDC hdc, Vector ptl, Vector pbr, Vector s) + { + pbr = Vector(min(pbr.x, s.x), min(pbr.y, s.y)); + Vector ps = pbr - ptl; + if (ps.x <= 0 || ps.y <= 0 || !_bitmap.valid()) + return; + _bmi.bmiHeader.biWidth = _bitmap.stride() / sizeof(DWORD); + _bmi.bmiHeader.biHeight = -s.y; + IF_ZERO_THROW(SetDIBitsToDevice( + hdc, + ptl.x, + ptl.y, + ps.x, + ps.y, + ptl.x, + s.y - pbr.y, + 0, + s.y, + _bitmap.data(), + &_bmi, + DIB_RGB_COLORS)); + } + + WindowDeviceContext _hdcScreen; + OwnedDeviceContext _hdcSrc; + GDIObject _hbmBackBuffer; + SelectedObject _hbmOld; + Bitmap _bitmap; + BITMAPINFO _bmi; + Vector2 _delta; + RenderTask _renderTask; + Vector _s; + Mutex _mutex; + bool _useChromaKey; + Vector _dragStart; + double _positionStart; + KnobSlider* _slider; + bool _sliding; + Vector2 _a; + + template friend class KnobSliderT; + + static bool insideParallelogram(Vector2 p, Vector2* points) + { + float d = cross(points[1] - points[0], points[2] - points[0]); + float ud = cross(p - points[0], points[2] - points[0]); + float vd = cross(points[1] - points[0], p - points[0]); + return ud >= 0 && vd >= 0 && ud <= d && vd <= d; + } + static bool lineSegmentsIntersect(Vector2 a0, Vector2 a1, + Vector2 b0, Vector2 b1) + { + float d = cross(a1 - a0, b1 - b0); + float ud = cross(b0 - a0, b1 - b0); + float vd = cross(b0 - a0, a1 - a0); + return ud >= 0 && vd >= 0 && ud <= d && vd <= d; + } + + static void fillParallelogram(Bitmap bitmap, + Vector2* points, DWORD colour, bool antiAlias = true) + { + Vector topLeft = Vector2Cast(points[0]); + Vector bottomRight = topLeft + Vector(1, 1); + for (int i = 1; i < 4; ++i) { + topLeft.x = min(topLeft.x, static_cast(points[i].x)); + topLeft.y = min(topLeft.y, static_cast(points[i].y)); + bottomRight.x = + max(bottomRight.x, static_cast(points[i].x + 1)); + bottomRight.y = + max(bottomRight.y, static_cast(points[i].y + 1)); + } + Vector s = bottomRight - topLeft; + bitmap = bitmap.subBitmap(topLeft, s); + Vector2 corners[4]; + for (int i = 0; i < 4; ++i) + corners[i] = points[i] - Vector2Cast(topLeft); + + if (s.x > s.y) { + float sx2 = static_cast(s.x/2); + Vector2 s2(sx2, static_cast(s.y)); + fillParallelogram(bitmap, corners, colour, Vector2(0, 0), + s2, antiAlias); + fillParallelogram(bitmap, corners, colour, Vector2(sx2, 0), + s2, antiAlias); + } + else { + float sy2 = static_cast(s.y/2); + Vector2 s2(static_cast(s.x), sy2); + fillParallelogram(bitmap, corners, colour, Vector2(0, 0), + s2, antiAlias); + fillParallelogram(bitmap, corners, colour, Vector2(0, sy2), + s2, antiAlias); + } + } + + static int fillParallelogram(Bitmap bitmap, Vector2* points, + DWORD colour, Vector2 tl, Vector2 size, bool antiAlias) + { + Vector2 rect[4]; + rect[0] = tl; + rect[1] = tl + Vector2(size.x, 0); + rect[2] = tl + Vector2(0, size.y); + rect[3] = tl + size; + int i; + bool allInside = true; + bool allOutside = true; + for (i = 0; i < 4; ++i) { + if (insideParallelogram(rect[i], points)) { + allOutside = false; + if (!allInside) + break; + } + else { + allInside = false; + if (!allOutside) + break; + } + } + if (allInside) { + if (size.x >= 1 && size.y >= 1) { + bitmap.subBitmap(Vector2Cast(tl), + Vector2Cast(size)).fill(colour | 0xff000000); + } + return static_cast(size.x * size.y * 256); + } + if (allOutside) { + bool intersects = false; + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + if (lineSegmentsIntersect(points[i], points[(i + 1) & 3], + rect[j], rect[(j + 1) & 3])) { + intersects = true; + i = 4; + j = 4; + } + } + } + if (!intersects) + return 0; + } + if (size.x <= 1.0f/8 && size.y <= 1.0f/8) + return 4; + if (size.x > 1 || size.y > 1) { + Vector2 s; + if (size.x > size.y) { + s = Vector2( + static_cast(static_cast(size.x)/2), 0); + fillParallelogram(bitmap, points, colour, tl, + Vector2(s.x, size.y), antiAlias); + } + else { + s = Vector2(0, + static_cast(static_cast(size.y)/2)); + fillParallelogram(bitmap, points, colour, tl, + Vector2(size.x, s.y), antiAlias); + } + fillParallelogram(bitmap, points, colour, tl + s, size - s, + antiAlias); + return 0; + } + if (!antiAlias) { + bitmap[Vector2Cast(tl)] = colour | 0xff000000; + return 0; + } + Vector2 s; + if (size.x > size.y) + s = Vector2(size.x/2, 0); + else + s = Vector2(0, size.y/2); + int area = fillParallelogram(bitmap, points, colour, tl, size - s, + antiAlias) + fillParallelogram(bitmap, points, colour, tl + s, + size - s, antiAlias); + if (size.x == 1 && size.y == 1) + plot(&bitmap[Vector2Cast(tl)], colour, area); + return area; + } + + // area/256 of the pixel *p is to be covered by colour + static void plot(DWORD* p, DWORD colour, int area) + { + float coverage = static_cast(area)/256.0f; + float gamma = 2.2f; + float rLinear = pow(((colour >> 16) & 0xff)*coverage/255.0f, gamma); + float gLinear = pow(((colour >> 8) & 0xff)*coverage/255.0f, gamma); + float bLinear = pow((colour & 0xff)*coverage/255.0f, gamma); + DWORD b = *p; + float bCoverage = ((b >> 24) & 0xff)/255.0f; + float bRLinear = pow(((b >> 16) & 0xff)/255.0f, gamma); + float bGLinear = pow(((b >> 8) & 0xff)/255.0f, gamma); + float bBLinear = pow((b & 0xff)/255.0f, gamma); + bRLinear = bRLinear*(1 - coverage) + rLinear; + bGLinear = bGLinear*(1 - coverage) + gLinear; + bBLinear = bBLinear*(1 - coverage) + bLinear; + bCoverage = bCoverage*(1 - coverage) + coverage; + int rSRGB = static_cast(pow(bRLinear, 1/gamma)*255.0f + 0.5f); + int gSRGB = static_cast(pow(bGLinear, 1/gamma)*255.0f + 0.5f); + int bSRGB = static_cast(pow(bBLinear, 1/gamma)*255.0f + 0.5f); + int alpha = static_cast(bCoverage*255.0f + 0.5f); + *p = (byteClamp(alpha) << 24) | (byteClamp(rSRGB) << 16) | + (byteClamp(gSRGB) << 8) | byteClamp(bSRGB); + } + + static void fillCircle(Bitmap bitmap, DWORD colour, + Vector2 c, float r) + { + r *= r; + Vector2 s = Vector2Cast(bitmap.size()); + Vector2 m = Vector2Cast(bitmap.size()/2); + Vector2 z(0, 0); + fillCircle(bitmap, colour, c, r, Vector2(0, 0), m); + fillCircle(bitmap, colour, c, r, Vector2(m.x, 0), + Vector2(s.x - m.x, m.y)); + fillCircle(bitmap, colour, c, r, Vector2(0, m.y), + Vector2(m.x, s.y - m.y)); + fillCircle(bitmap, colour, c, r, m, s - m); + } + + static int fillCircle(Bitmap bitmap, DWORD colour, + Vector2 c, float r2, Vector2 tl, Vector2 size) + { + Vector2 rect[4]; + rect[0] = tl; + rect[1] = tl + Vector2(size.x, 0); + rect[2] = tl + Vector2(0, size.y); + rect[3] = tl + size; + int i; + bool allInside = true; + bool allOutside = true; + for (i = 0; i < 4; ++i) { + if ((rect[i] - c).modulus2() < r2) { + allOutside = false; + if (!allInside) + break; + } + else { + allInside = false; + if (!allOutside) + break; + } + } + if (allInside) { + if (size.x >= 1 && size.y >= 1) { + bitmap.subBitmap(Vector2Cast(tl), + Vector2Cast(size)).fill(colour | 0xff000000); + } + return static_cast(size.x * size.y * 256); + } + if (allOutside) + return 0; + if (size.x <= 1.0f/16 && size.y <= 1.0f/16) + return 1; + if (size.x > 1 || size.y > 1) { + Vector2 s; + if (size.x > size.y) { + s = Vector2( + static_cast(static_cast(size.x)/2), 0); + fillCircle(bitmap, colour, c, r2, tl, + Vector2(s.x, size.y)); + } + else { + s = Vector2(0, + static_cast(static_cast(size.y)/2)); + fillCircle(bitmap, colour, c, r2, tl, + Vector2(size.x, s.y)); + } + fillCircle(bitmap, colour, c, r2, tl + s, size - s); + return 0; + } + Vector2 s; + if (size.x > size.y) + s = Vector2(size.x/2, 0); + else + s = Vector2(0, size.y/2); + int area = fillCircle(bitmap, colour, c, r2, tl, size - s) + + fillCircle(bitmap, colour, c, r2, tl + s, size - s); + if (size.x == 1 && size.y == 1) + plot(&bitmap[Vector2Cast(tl)], colour, area); + return area; + } +}; + +template class KnobSliderT : public ContainerWindow +{ +public: + KnobSliderT() + : _config(0), _knobDiameter(24), _popupLength(301), _captionWidth(112), + _logarithmic(false), _settingEdit(false), _enabled(true) + { + add(&_caption); + add(&_knob); + add(&_edit); + _lightGrey = getSysColor(COLOR_BTNFACE, 0xc0c0c0); + _darkGrey = getSysColor(COLOR_GRAYTEXT, 0x7f7f7f); + _disabledGrey = (((_lightGrey & 0xff) + (_darkGrey & 0xff))/2) | + (((_lightGrey & 0xff00) + (_darkGrey & 0xff00))/2) | + (((_lightGrey & 0xff0000) + (_darkGrey & 0xff0000))/2); + _black = getSysColor(COLOR_WINDOWTEXT, 0x000000); + } + void setSliders(KnobSliders* sliders) { _sliders = sliders; } + void setText(String text) { _caption.setText(text); } + void setCaptionWidth(int width) { _captionWidth = width; } + void layout() + { + _knob.setInnerSize(Vector(_knobDiameter, _knobDiameter)); + int height = max(_caption.outerSize().y, max(_knobDiameter, + _edit.outerSize().y)); + _caption.setTopLeft(Vector(0, (height - _caption.outerSize().y)/2)); + _knob.setTopLeft(Vector( + max(_captionWidth, _caption.right() + _knobDiameter/2), + (height - _knobDiameter)/2)); + _edit.setTopLeft(Vector(_knob.right() + _knobDiameter/2, + (height - _edit.outerSize().y)/2)); + setInnerSize(Vector(_edit.right(), height)); + } + void setTopLeft(Vector topLeft) + { + ContainerWindow::setTopLeft(topLeft); + repositionChildren(); + } + void create() + { + ContainerWindow::create(); + setValue(_value); + } + void setRange(double low, double high) + { + _min = low; + _max = high; + } + virtual void valueSet(double value) { _valueSet(value); } + void setValueSet(std::function valueSet) + { + _valueSet = valueSet; + } + void setValue(double value) + { + setValueInternal(value, true); + } + double getValue() const { return _value; } + void setConfig(ConfigFile* config) { _config = config; } + virtual double positionFromValue(double value) + { + return _logarithmic ? log(value) : value; + } + virtual double valueFromPosition(double position) + { + return _logarithmic ? exp(position) : position; + } + void setLogarithmic(bool logarithmic) { _logarithmic = logarithmic; } + void enableWindow(bool enabled) + { + if (enabled != _enabled) { + _enabled = enabled; + _knob.draw(); + } + ContainerWindow::enableWindow(enabled); + } + void changeValue(double amount) + { + setPosition(clamp(0.0, position() + amount, 1.0)); + } +private: + void setValueInternal(double value, bool drawKnob) + { + double dp; + if (_logarithmic) + dp = log(value/_popupLength)/log(10); + else + dp = log((_max - _min)/_popupLength)/log(10); + int dps = max(0, static_cast(1 - dp)); + if (_popupLength < 0) + dps = 1; + _settingEdit = true; + _edit.setText(format("%.*f", dps, value)); + _settingEdit = false; + setValueFromEdit(value, drawKnob); + } + void setValueFromEdit(double value, bool drawKnob = true) + { + _value = value; + valueSet(value); + if (drawKnob) + _knob.draw(); + } + double position() + { + double m = positionFromValue(_min); + return (positionFromValue(_value) - m)/(positionFromValue(_max) - m); + } + void setPosition(double p) + { + double m = positionFromValue(_min); + setValueInternal( + valueFromPosition(p*(positionFromValue(_max) - m) + m), false); + } + + static DWORD getSysColor(int nIndex, DWORD def) + { + // The values returned from GetSysColor have the red channel in the + // low 8 bits, not the blue channel as with our Bitmap objects. + DWORD c = GetSysColor(nIndex); + if (c != 0) { + return 0xff000000 | (GetRValue(c) << 16) | (GetGValue(c) << 8) | + GetBValue(c); + } + return 0xff000000 | def; + } + + class KnobWindow : public BitmapWindow + { + public: + void draw2() + { + if (_hWnd == NULL) + return; + host()->_sliders->drawKnob(host()); + } + bool mouseInput(Vector position, int buttons, int wheel) + { + if (_hWnd == 0) + return false; + bool lButton = (buttons & MK_LBUTTON) != 0; + POINT point; + point.x = position.x; + point.y = position.y; + IF_ZERO_THROW(ClientToScreen(_hWnd, &point)); + return host()->_sliders->knobEvent(host(), + Vector(point.x, point.y), lButton); + } + private: + KnobSlider* host() { return static_cast(parent()); } + }; + + class EditControl : public EditWindow + { + public: + EditControl() + { + setExtendedStyle(WS_EX_CLIENTEDGE); + setStyle(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP); + } + void changed() + { + if (host()->_settingEdit) + return; + String t = getText(); + double v = host()->_config->evaluate(t, host()->_value); + host()->setValueFromEdit(v); + } + virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + if (uMsg == WM_KEYDOWN) { + switch (wParam) { + case VK_UP: + host()->changeValue(0.01); + return 0; + case VK_DOWN: + host()->changeValue(-0.01); + return 0; + case VK_PRIOR: + host()->changeValue(0.1); + return 0; + case VK_NEXT: + host()->changeValue(-0.1); + return 0; + } + } + return EditWindow::handleMessage(uMsg, wParam, lParam); + } + private: + KnobSlider* host() { return static_cast(parent()); } + }; + + TextWindow _caption; + KnobWindow _knob; + EditControl _edit; + KnobSliders* _sliders; + double _value; + double _min; + double _max; + int _knobDiameter; + int _popupLength; + int _captionWidth; + DWORD _disabledGrey; + DWORD _lightGrey; + DWORD _darkGrey; + DWORD _black; + ConfigFile* _config; + bool _logarithmic; + bool _settingEdit; + std::function _valueSet; + bool _enabled; + + friend class KnobWindow; + template friend class KnobSlidersT; + friend class EditWindow; +}; + +#endif // INCLUDED_KNOB_H diff --git a/80386/disassembler/include/alfe/linked_list.h b/80386/disassembler/include/alfe/linked_list.h new file mode 100644 index 0000000..bcbe2e4 --- /dev/null +++ b/80386/disassembler/include/alfe/linked_list.h @@ -0,0 +1,120 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_LINKED_LIST_H +#define INCLUDED_LINKED_LIST_H + +template class LinkedList; +template class OwningLinkedList; + +template class LinkedListMember : Uncopyable +{ +public: + LinkedListMember() : _next(this), _prev(this) { } + + void remove() + { + _next->_prev = _prev; + _prev->_next = _next; + } + + void moveFrom(LinkedListMember* oldLocation) + { + _next = oldLocation->_next; + _prev = oldLocation->_prev; + _next->_prev = this; + _prev->_next = this; + } + + LinkedListMember* next() { return _next; } + LinkedListMember* previous() { return _prev; } + void insertBefore(T* item) + { + item->_prev = _prev; + _prev->_next = item; + item->_next = this; + _prev = item; + } + void insertAfter(T* item) + { + item->_prev = this; + _next->_prev = item; + item->_next = _next; + _next = item; + } + +private: + LinkedListMember* _next; + LinkedListMember* _prev; + friend class LinkedList; + //friend class LinkedList::Iterator; + //template<> friend class OwningLinkedList; +}; + +template class LinkedList : public LinkedListMember +{ +public: + void add(T* item) { this->insertBefore(item); } + + T* getNext(LinkedListMember* c = 0) + { + if (c == 0) + c = this; + LinkedListMember* n = c->next(); + if (n == this) + return 0; + return static_cast(n); + } + + void release() + { + this->_next = this; + this->_prev = this; + } + + bool empty() const { return this->_next == this; } + + class Iterator + { + public: + T& operator*() const { return *static_cast(_node); } + T* operator->() const { return static_cast(_node); } + const Iterator& operator++() + { + _node = _node->_next; + return *this; + } + bool operator==(const Iterator& other) const + { + return _node == other._node; + } + bool operator!=(const Iterator& other) const + { + return !operator==(other); + } + private: + LinkedListMember* _node; + + Iterator(LinkedListMember* node) : _node(node) { } + + friend class LinkedList; + }; + Iterator begin() { return Iterator(this->_next); } + Iterator end() { return Iterator(this); } +}; + +template class OwningLinkedList : LinkedList +{ +public: + ~OwningLinkedList() { release(); } + + void release() + { + while (this->_next != this) { + T* t = static_cast(this->_next); + t->remove(); + delete t; + } + } +}; + +#endif // INCLUDED_LINKED_LIST_H diff --git a/80386/disassembler/include/alfe/main.h b/80386/disassembler/include/alfe/main.h new file mode 100644 index 0000000..c32503b --- /dev/null +++ b/80386/disassembler/include/alfe/main.h @@ -0,0 +1,334 @@ +#ifndef INCLUDED_MAIN_H +#define INCLUDED_MAIN_H + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN +#include +#ifdef _WINDOWS +#define UTF16_MESSAGES +#endif +#include "shellapi.h" +#else +#include +#include +#include +#include +#endif + +#define _USE_MATH_DEFINES +#include +static const double tau = 2*M_PI; + + +bool alerting = false; + +#include "alfe/integer_types.h" +#include "alfe/uncopyable.h" +#include "alfe/hash.h" +#include "alfe/handle.h" +#include "alfe/swap.h" +#include "alfe/array.h" +#include "alfe/minimum_maximum.h" +#include "alfe/string.h" +#include "alfe/exception.h" +#include "alfe/file.h" +#include "alfe/find_handle.h" +#include "alfe/circular_buffer.h" +#include "alfe/windows_handle.h" +#include "alfe/stream.h" +#include "alfe/file_stream.h" +#include "alfe/character_source.h" +#if defined(_WIN32) && defined(_WINDOWS) +#include "alfe/vectors.h" +#include "alfe/colour_space.h" +#include "alfe/bitmap.h" +#include "alfe/linked_list.h" +#include "alfe/thread.h" +#include "alfe/user.h" +#endif + +Stream console; +Stream errorConsole; + +class ProgramBase : public Uncopyable +{ +public: + ProgramBase() : _returnValue(0) { } +#ifdef _WIN32 +#ifdef _WINDOWS + int initialize(HINSTANCE hInst, INT nCmdShow) + { + _hInst = hInst; + _nCmdShow = nCmdShow; + initializeMain(); + return _returnValue; + } +#else + int initialize() + { + initializeMain(); + return _returnValue; + } +#endif +#else + int initialize(int argc, char* argv[]) + { + BEGIN_CHECKED { + console = Stream(STDOUT_FILENO, Console()); + errorConsole = Stream(STDERR_FILENO, Console()); + BEGIN_CHECKED { + _arguments.allocate(argc); + for (int i = 0; i < argc; ++i) + _arguments[i] = String(argv[i]); + run(); + } + END_CHECKED(Exception& e) { + console.write(e); + } + } + END_CHECKED(Exception&) { + // Can't even display an error + } + return _returnValue; + } +#endif +protected: +#if defined(_WIN32) && defined(_WINDOWS) + Windows _windows; + INT _nCmdShow; + +#endif + virtual void run() = 0; + Array _arguments; + int _returnValue; + HINSTANCE _hInst; +private: +#ifdef _WIN32 +#ifdef _WINDOWS + + void initializeWindows() + { + BEGIN_CHECKED { + initializeWindowsCommandLine(); + } + END_CHECKED(Exception& e) { + NullTerminatedWideString s(e.message()); + MessageBox(NULL, s, L"Error", MB_OK | MB_ICONERROR); + } + } + +#endif + void initializeMain() + { + // Disable exception swallowing on 64-bit Windows. + typedef BOOL (WINAPI* getType)(LPDWORD lpFlags); + typedef BOOL (WINAPI* setType)(DWORD dwFlags); +#ifndef PROCESS_CALLBACK_FILTER_ENABLED +#define PROCESS_CALLBACK_FILTER_ENABLED 1 +#endif + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + if (kernel32 != NULL) { + getType getProcessUserModeExceptionPolicy = + reinterpret_cast(GetProcAddress(kernel32, + "GetProcessUserModeExceptionPolicy")); + setType setProcessUserModeExceptionPolicy = + reinterpret_cast(GetProcAddress(kernel32, + "SetProcessUserModeExceptionPolicy")); + if (getProcessUserModeExceptionPolicy != 0 && + setProcessUserModeExceptionPolicy != 0) { + DWORD dwFlags; + if (getProcessUserModeExceptionPolicy(&dwFlags)) + setProcessUserModeExceptionPolicy(dwFlags & + ~PROCESS_CALLBACK_FILTER_ENABLED); + } + } + + BEGIN_CHECKED { + console = Stream(GetStdHandle(STD_OUTPUT_HANDLE), Console(), + false); + errorConsole = Stream(GetStdHandle(STD_ERROR_HANDLE), Console(), + false); + // We can't validate console here because we might be in a GUI + // program where there is no console. + //if (!console.valid()) + // throw Exception::systemError("Getting console handle"); + BEGIN_CHECKED { +#ifdef _WINDOWS + initializeWindows(); +#else + initializeWindowsCommandLine(); +#endif + } + END_CHECKED(Exception& e) { + if (console.valid()) + console.write(e); + } + } + END_CHECKED(...) { + // Can't even display an error + } + } + + void initializeWindowsCommandLine() + { + class WindowsCommandLine + { + public: + WindowsCommandLine() + { + _szArglist = CommandLineToArgvW(GetCommandLineW(), &_nArgs); + if (_szArglist == NULL) + throw Exception::systemError("Parsing command line"); + } + ~WindowsCommandLine() + { + LocalFree(static_cast(_szArglist)); + } + const LPWSTR* arguments() const { return _szArglist; } + int nArgs() const { return _nArgs; } + private: + LPWSTR* _szArglist; + int _nArgs; + }; + WindowsCommandLine windowsCommandLine; + int nArgs = windowsCommandLine.nArgs(); + const LPWSTR* szArglist = windowsCommandLine.arguments(); + _arguments.allocate(nArgs); + int nBytes = 0; + for (int i = 0; i < nArgs; ++i) + nBytes += String::bytes(szArglist[i]); + String buffer(nBytes); + int start = 0; + Byte* p = buffer.data(); + for (int i = 0; i < nArgs; ++i) { + p = String::write(p, szArglist[i]); + int end = static_cast(p - buffer.data()); + _arguments[i] = buffer.subString(start, end - start); + start = end; + } + run(); + } +#endif +}; + +#if defined(_WIN32) && defined(_WINDOWS) +template class WindowProgram : public ProgramBase +{ +public: + WindowProgram() : _quitting(false) { } + void createWindow() + { + _window.setParent(0); + _window.setWindows(&_windows); + _window.create(); + _window.show(_nCmdShow); + } + void pumpMessages() + { + if (_quitting) + return; + MSG msg; + do { + BOOL fMessage = PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE); + if (fMessage == 0) + break; + if (msg.message == WM_QUIT) + break; + if (!IsDialogMessage(_window.hWnd(), &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + _windows.check(); + } while (true); + if (msg.message == WM_QUIT) { + _quitting = true; + _returnValue = static_cast(msg.wParam); + } + } + void run() + { + createWindow(); + do { + bool more = idle(); + if (!more) { + HANDLE handle = _interruptMessageLoop; + DWORD r = MsgWaitForMultipleObjects(1, &handle, FALSE, + INFINITE, QS_ALLINPUT); + IF_FALSE_THROW(r != WAIT_FAILED); + } + pumpMessages(); + } while (!_quitting); + } +protected: + // idle() returns true if there is more idle processing to do, false if + // there isn't and we should wait for a message before calling again. + virtual bool idle() { return false; } + + bool _quitting; + Event _interruptMessageLoop; + WindowClass _window; +}; +#endif + +// Put Program in a template because it's not declared yet. +#ifdef _WIN32 +#ifdef _WINDOWS +template INT APIENTRY WinMainTemplate(HINSTANCE hInst, + INT nCmdShow) +#else +template int mainTemplate() +#endif +#else +template int mainTemplate(int argc, char* argv[]) +#endif +{ + Program program; +#ifdef _WIN32 +#ifdef _WINDOWS + return program.initialize(hInst, nCmdShow); +#else + return program.initialize(); +#endif +#else + return program.initialize(argc, argv); +#endif +} + +class Program; + +#ifdef _WIN32 +#ifdef _WINDOWS +INT APIENTRY WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT nCmdShow) +{ + return WinMainTemplate(hInst, nCmdShow); +} + +// Define main() as well in case we want to make a Windows program linked as +// a Console subsystem program (for debugging purposes). +int __cdecl main() +{ + return WinMainTemplate(GetModuleHandle(NULL), SW_SHOWNORMAL); +} + +#else +int main() +{ + return mainTemplate(); +} +#endif +#else +int main(int argc, char* argv[]) +{ + return mainTemplate(argc, argv); +} +#endif + + +#endif // INCLUDED_MAIN_H diff --git a/80386/disassembler/include/alfe/main.txt b/80386/disassembler/include/alfe/main.txt new file mode 100644 index 0000000..00f817e --- /dev/null +++ b/80386/disassembler/include/alfe/main.txt @@ -0,0 +1,31 @@ +Windows GUI + WinMain + WinMainTemplate + Program::initialize() + Program::initializeMain() <- We get console here but fail + Program::initializeWindows() + Program::initializeWindowsCommandLine() + Program::run() + +Windows Console + main + mainTemplate + Program::initialize() + Program::initializeMain() + Program::initializeWindowsCommandLine() + Program::run() + +Windows Console with GUI + main + WinMainTemplate + Program::initialize() + Program::initializeMain() + Program::initializeWindows() + Program::initializeWindowsCommandLine() + Program::run() + +Unix + main + mainTemplate + Program::initialize() + Program::run() diff --git a/80386/disassembler/include/alfe/minimum_maximum.h b/80386/disassembler/include/alfe/minimum_maximum.h new file mode 100644 index 0000000..39dd3e8 --- /dev/null +++ b/80386/disassembler/include/alfe/minimum_maximum.h @@ -0,0 +1,43 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_MININUM_MAXIMUM_H +#define INCLUDED_MININUM_MAXIMUM_H + +template T max(const T& a, const T& b) { return a > b ? a : b; } + +template T min(const T& a, const T& b) { return a < b ? a : b; } + +template T clamp(T low, T value, T high) +{ + return min(max(low, value), high); +} + +template Byte byteClamp(T value) +{ + return clamp(0, static_cast(value), 0xff); +} + +template T max(const T& a, const T& b, const T& c) +{ + return max(a, max(b, c)); +} + + +template T min(const T& a, const T& b, const T& c) +{ + return min(a, min(b, c)); +} + + +template T max(const T& a, const T& b, const T& c, const T& d) +{ + return max(a, max(b, c, d)); +} + + +template T min(const T& a, const T& b, const T& c, const T& d) +{ + return min(a, min(b, c, d)); +} + +#endif // INCLUDED_MININUM_MAXIMUM_H diff --git a/80386/disassembler/include/alfe/named_pipe.h b/80386/disassembler/include/alfe/named_pipe.h new file mode 100644 index 0000000..6b1262d --- /dev/null +++ b/80386/disassembler/include/alfe/named_pipe.h @@ -0,0 +1,56 @@ +#ifndef INCLUDED_NAMED_PIPE_H +#define INCLUDED_NAMED_PIPE_H + +#include "alfe/windows_handle.h" + +class NamedPipe +{ +public: + NamedPipe(String name = "", int size = 4096, int timeOut = 120, + bool overlappedRead = false, bool overlappedWrite = false) + { + if (name == "") { + static volatile long unique; + name = format("\\\\.\\Pipe\\ALFEAnonymousPipe.%08x.%08x", + GetCurrentProcessId(), InterlockedIncrement(&unique)); + } + + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + NullTerminatedWideString data(name); + HANDLE r = CreateNamedPipe( + data, + PIPE_ACCESS_INBOUND | (overlappedRead ? FILE_FLAG_OVERLAPPED : 0), + PIPE_TYPE_BYTE | PIPE_WAIT, + 1, + size, + size, + timeOut * 1000, + &sa); + IF_FALSE_THROW(r != INVALID_HANDLE_VALUE); + _read = Stream(r, File(name)); + + HANDLE w = CreateFile( + data, + GENERIC_WRITE, + 0, // No sharing + &sa, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL + | (overlappedWrite ? FILE_FLAG_OVERLAPPED : 0), + NULL // Template file + ); + IF_FALSE_THROW(w != INVALID_HANDLE_VALUE); + _write = Stream(w, File(name)); + } + Stream read() { return _read; } + Stream write() { return _write; } +private: + Stream _read; + Stream _write; +}; + +#endif // INCLUDED_NAMED_PIPE_H diff --git a/80386/disassembler/include/alfe/ntsc_decode.h b/80386/disassembler/include/alfe/ntsc_decode.h new file mode 100644 index 0000000..1a9669b --- /dev/null +++ b/80386/disassembler/include/alfe/ntsc_decode.h @@ -0,0 +1,895 @@ +#ifndef INCLUDED_NTSC_DECODE_H +#define INCLUDED_NTSC_DECODE_H + +#include "alfe/main.h" +#include "alfe/bitmap.h" +#include "alfe/complex.h" +#include "alfe/fft.h" +#include "alfe/image_filter.h" +#include "alfe/colour_space.h" +#include + +float sinc(float z) +{ + if (z == 0.0f) + return 1.0f; + z *= static_cast(M_PI); + return sin(z)/z; +} + +static const int lobes = 3; + +float lanczos(float z) +{ + return sinc(z)*sinc(z/lobes); +} + +template Byte checkClamp(T x) +{ + return byteClamp(x); +// return x; +} + +Complex rotor(float phase) +{ + float angle = static_cast(phase*tau); + return Complex(cos(angle), sin(angle)); +} + +template class NTSCCaptureDecoder +{ +public: + NTSCCaptureDecoder() + { + _contrast = 2.3; + _brightness = -33.0; + _saturation = 0.34; + _hue = 0; + _outputPixelsPerLine = 760; + _yScale = 1; + _doDecode = true; + _chromaSamples = 8; + + for (int i = 8; i < 40; ++i) + _burstWeights[i] = 1; + for (int i = 0; i < 8; ++i) { + _burstWeights[i] = 1 - (cos(tau*i/16) + 1)/2; + _burstWeights[i + 40] = (cos(tau*i/16) + 1)/2; + } + } + void setOutputPixelsPerLine(int outputPixelsPerLine) + { + // outputPixelsPerLine active width with 20% overscan per color carrier cycle active scanlines with 20% overscan + // 380 266+2/3 320 1+2/3 200 240 + // 456 320 384 2 240 288 + // 570 400 480 2.5 300 360 + // 760 533+1/3 640 3+1/3 400 480 + // 912 640 768 4 480 576 + // 1140 800 960 5 600 720 + _outputPixelsPerLine = outputPixelsPerLine; + } + void setInputBuffer(Byte* input) { _input = input; } + void setOutputBuffer(Bitmap output) { _output = output; } + void setContrast(float contrast) { _contrast = contrast; } + void setBrightness(float brightness) { _brightness = brightness; } + void setSaturation(float saturation) { _saturation = saturation; } + void setHue(float hue) { _hue = hue; } + void setYScale(int yscale) { _yScale = yscale; } + void setDoDecode(bool doDecode) { _doDecode = doDecode; } + void setChromaSamples(float samples) { _chromaSamples = samples; } + + void decode() + { + if (!_doDecode) { + outputRaw(); + return; + } + // Settings + + static const int firstScanline = 0; // 9 + static const int lines = 240 + firstScanline; + static const int nominalSamplesPerLine = 1820; + static const int firstSyncSample = -40; // Assumed position of previous hsync before our samples started (was -130) + static const float kernelSize = lobes; // Lanczos parameter + static const int nominalSamplesPerCycle = 8; + static const int driftSamples = 40; + static const int burstSamples = 48; // Central 6 of 8-10 cycles + static const int firstBurstSample = 32 + driftSamples; // == 72 + static const int burstCenter = firstBurstSample + burstSamples/2; + + Byte* b = _input; + + + // Pass 1 - find sync and burst pulses, compute wobble amplitude and phase + + float deltaSamplesPerCycle = 0; + + int syncPositions[lines + 1]; + int fracSyncPositions[lines + 1]; + int oldP = firstSyncSample - driftSamples; // == -80 + int p = oldP + nominalSamplesPerLine; + float samplesPerLine = nominalSamplesPerLine; + Complex bursts[lines + 1]; + float burstDCs[lines + 1]; + Complex hueRotor = rotor((33 + _hue)/360); + float burstDCAverage = 0; + float x = 0; + for (int line = 0; line < lines + 1; ++line) { + Complex burst = 0; + float burstDC = 0; + float t = 0; + for (int i = firstBurstSample; i < firstBurstSample + burstSamples; ++i) { + int j = oldP + i; // == -8 + int sample = b[j]; + float phase = (j&7)/8.0f; + float w = 1; //_burstWeights[ i - firstBurstSample]; + burst += rotor(phase)*sample*w; + t += w; + burstDC += sample; + } + + float burstAmplitude = burst.modulus()/burstSamples; + bursts[line] = burst*hueRotor/burstSamples; + burstDC /= t; + burstDCs[line] = burstDC; + + syncPositions[line] = p; + fracSyncPositions[line] = x; + oldP = p; + int i; + for (i = 0; i < driftSamples*2; ++i) { + if (b[p] < 9) + break; + ++p; + } + for (; i < driftSamples*2; ++i) { + if (b[p] >= 12) + break; + ++p; + } + // b[p] >= 12 + // b[p - 1] < 12 + // b[p - 1]*x + b[p]*(1 - x) == 12 + // x == (b[p] - 12)/(b[p] - b[p-1]) + // 12 position is b[p - x] + int d = b[p] - b[p - 1]; + if (d == 0) + x = 0; + else + x = (b[p] - 12)/d; + + p += nominalSamplesPerLine - driftSamples; + + if (line < 200) { + samplesPerLine = (2*samplesPerLine + p - oldP)/3; + burstDCAverage = (2*burstDCAverage + burstDC)/3; + } + } + + float deltaSamplesPerLine = samplesPerLine - nominalSamplesPerLine; + + + // Pass 2 - render + + Byte* outputRow = _output.data(); + + float q = syncPositions[1] - samplesPerLine; + syncPositions[0] = q; + Complex burst = bursts[0]; + float rotorTable[8]; + for (int i = 0; i < 8; ++i) + rotorTable[i] = rotor(static_cast(i)/8).x; + Complex expectedBurst = burst; + int oldActualSamplesPerLine = nominalSamplesPerLine; + float contrast1 = _contrast; + float saturation1 = _saturation*100; + for (int line = 0; line < lines; ++line) { + // Determine the phase, amplitude and DC offset of the color signal + // from the color burst, which starts shortly after the horizontal + // sync pulse ends. The color burst is 9 cycles long, and we look + // at the middle 5 cycles. + + Complex actualBurst = bursts[line]; + burst = (expectedBurst*2 + actualBurst)/3; + //burst = actualBurst; + + float phaseDifference = (actualBurst*(expectedBurst.conjugate())).argument()/tau; + float adjust = -phaseDifference/_outputPixelsPerLine; + + float bm2 = burst.modulus2(); + Complex chromaAdjust; + // TODO: Implement proper colour-killer logic (100 scanlines hysterisis?) + if (bm2 < 50) + chromaAdjust = 0; + else + chromaAdjust = burst.conjugate()*contrast1*saturation1 / bm2; + burstDCAverage = (2*burstDCAverage + burstDCs[line])/3; + float brightness1 = _brightness + 65 - burstDCAverage; + + // Resample the image data + + T* output = reinterpret_cast(outputRow); + int xStart = 65*_outputPixelsPerLine/760; + for (int x = xStart; x < xStart + _output.size().x; ++x) { + float y = 0; + Complex c = 0; + float t = 0; + + float kFrac0 = x*samplesPerLine/_outputPixelsPerLine; + float kFrac = q + kFrac0; + int k = static_cast(kFrac); + kFrac -= k; + float samplesPerCycle = nominalSamplesPerCycle + deltaSamplesPerCycle; + float z0 = -kFrac/_chromaSamples; + int firstInput = -kernelSize*_chromaSamples + kFrac; + int lastInput = kernelSize*_chromaSamples + kFrac; + + for (int j = firstInput; j <= lastInput; ++j) { + // The input sample corresponding to the output pixel is k+kFrac + // The sample we're looking at in this iteration is j+k + // The difference is j-kFrac + // So the value we pass to lanczos() is (j-kFrac)/_chromaSamples + // So z0 = -kFrac/_chromaSamples; + + float s = lanczos(j/_chromaSamples + z0); + int i = j + k; + float z = s*b[i]; + c.x += rotorTable[i & 7]*z; + c.y += rotorTable[(i + 6) & 7]*z; + t += s; + } + c /= t; + + //float lumaSamples = samplesPerLine/_outputPixelsPerLine; + float lumaSamples = samplesPerCycle/2; // i.e. 7.16MHz + firstInput = -kernelSize*lumaSamples + kFrac; + lastInput = kernelSize*lumaSamples + kFrac; + + Complex cc = c*2; + + t = 0; + z0 = -kFrac/lumaSamples; + for (int j = firstInput; j <= lastInput; ++j) { + // The input sample corresponding to the output pixel is k+kFrac + // The sample we're looking at in this iteration is j+k + // The difference is j-kFrac + // So the value we pass to lanczos() is (j-kFrac)/lumaSamples + // So z0 = -kFrac/lumaSamples; + + float s = lanczos(j/lumaSamples + z0); + int i = j + k; + float z = s*(b[i] - (cc.x*rotorTable[i & 7] + cc.y*rotorTable[(i + 6)&7])); + y += z; + t += s; + } + + y = y*contrast1/t + brightness1; + c = c*chromaAdjust*rotor((x - burstCenter*_outputPixelsPerLine/samplesPerLine)*adjust); + + setOutput(output, SRGB( + checkClamp(y + 0.9563*c.x + 0.6210*c.y), + checkClamp(y - 0.2721*c.x - 0.6474*c.y), + checkClamp(y - 1.1069*c.x + 1.7046*c.y))); + ++output; + } + + int p = syncPositions[line + 1]; + int actualSamplesPerLine = p - syncPositions[line]; + samplesPerLine = (2*samplesPerLine + actualSamplesPerLine + fracSyncPositions[line] - fracSyncPositions[line + 1])/3; + q += samplesPerLine; + q = (10*q + p)/11; + + expectedBurst = actualBurst; + + if (line >= firstScanline) { + Byte* outputRow2 = outputRow + _output.stride(); + for (int yy = 1; yy < _yScale; ++yy) { + T* output = reinterpret_cast(outputRow2); + T* input = reinterpret_cast(outputRow); + for (int x = 0; x < _output.size().x; ++x) { + *output = *input; + ++output; + ++input; + } + outputRow2 += _output.stride(); + } + outputRow = outputRow2; + } + } + } +private: + void outputRaw() + { + Byte* outputRow = _output.data(); + Byte* b = _input; + for (int y = 0; y < 252; ++y) { + T* output = reinterpret_cast(outputRow); + for (int x = 0; x < 1824; ++x) { + setOutput(output, SRGB(*b, *b, *b)); + ++output; + ++b; + } + outputRow += _output.stride(); + } + T* output = reinterpret_cast(outputRow); + for (int x = 0; x < 450*1024-252*1824; ++x) { + setOutput(output, SRGB(*b, *b, *b)); + ++output; + ++b; + } + } + + + void setOutput(SRGB* output, SRGB x) { *output = x; } + void setOutput(UInt32* output, SRGB x) + { + *output = (x.x << 16) | (x.y << 8) | x.z; + } + void setOutput(DWORD* output, SRGB x) + { + *output = (x.x << 16) | (x.y << 8) | x.z; + } + + int _outputPixelsPerLine; + float _contrast; + float _brightness; + float _saturation; + float _hue; + Byte* _input; + Bitmap _output; + int _yScale; + bool _doDecode; + float _chromaSamples; + float _burstWeights[48]; +}; + +// A non-resampling decoder optimized to decode a large chunk of samples at +// once, using FFTs. +class NTSCDecoder +{ +public: + NTSCDecoder(int length = 512, int outputLength = 448) + : _rigor(FFTW_EXHAUSTIVE) + { + setLength(length, outputLength); + } + + void setLength(int length, int outputLength) + { + _length = length; + _outputLength = outputLength; + _iTime.ensure(length); + _qTime.ensure(length); + _yTime.ensure(length); + int fLength = length/2 + 1; + _frequency.ensure(fLength); + _lumaForward = + FFTWPlanDFTR2C1D(length, _yTime, _frequency, _rigor); + _chromaForward = + FFTWPlanDFTR2C1D(length / 2, _yTime, _frequency, _rigor); + _backward = + FFTWPlanDFTC2R1D(length, _frequency, _yTime, _rigor); + _yResponse.ensure(fLength); + _iResponse.ensure(fLength); + _qResponse.ensure(fLength); + } + void init() + { + _chromaScale = 2 / static_cast(_length); + float contrast = _contrast / _length; + _brightness2 = _brightness * 256.0f; + int fLength = _length / 2 + 1; + float lumaHigh = _lumaBandwidth / 2; + float chromaLow = (4 - _chromaBandwidth) / 8; + float chromaHigh = (4 + _chromaBandwidth) / 8; + float rollOff = _rollOff / 4; + float chromaCutoff = _chromaBandwidth / 8; + + float pi = static_cast(tau / 2); + float width = _lobes * 4; + float lumaScale = (pi * lumaHigh) / (2 * sinint(pi * lumaHigh * width)); + if (lumaHigh == 0) + lumaScale = 0; + float chromaScale = (pi * chromaCutoff) / + (2 * sinint(pi * chromaCutoff * width)); + if (chromaCutoff == 0) + chromaScale = 0; + + float lumaTotal = 0; + for (int t = 0; t < fLength; ++t) { + float d = static_cast(t); + float r = sinc(d * rollOff) * lumaScale * sinc(d * lumaHigh); + if (t > width) + r = 0; + _yTime[t] = r; + if (t > 0) + _yTime[_length - t] = r; + lumaTotal += r * (t == 0 ? 1 : 2); + } + float scale = 1 / lumaTotal; + _lumaForward.execute(_yTime, _frequency); + for (int f = 0; f < fLength; ++f) + _yResponse[f] = _frequency[f].x * contrast * scale; + + float chromaTotal = 0; + for (int t = 0; t < fLength; ++t) { + float d = static_cast(t); + float r = sinc(d * rollOff) * chromaScale * sinc(d * chromaCutoff); + if (t > width) + r = 0; + _yTime[t] = r; + if (t > 0) + _yTime[_length - t] = r; + chromaTotal += r * (t == 0 ? 1 : 2); + } + scale = 1 / chromaTotal; + _lumaForward.execute(_yTime, _frequency); + for (int f = 0; f < fLength; ++f) { + float s = scale * _frequency[f].x; + _iResponse[f] = s * unit(-f / 512.0f); + _qResponse[f] = s; + } + } + void calculateBurst(const Byte* burst) + { + Complex iq; + iq.x = static_cast(burst[0] - burst[2]); + iq.y = static_cast(burst[1] - burst[3]); + Complex iqAdjust = + -iq.conjugate()*unit((33 + 90 + _hue)/360.0f)*_saturation* + _contrast*_chromaScale/(iq.modulus()*2); + _ri = 0.9563f*iqAdjust.x +0.6210f*iqAdjust.y; + _rq = 0.6210f*iqAdjust.x -0.9563f*iqAdjust.y; + _gi = -0.2721f*iqAdjust.x -0.6474f*iqAdjust.y; + _gq = -0.6474f*iqAdjust.x +0.2721f*iqAdjust.y; + _bi = -1.1069f*iqAdjust.x +1.7046f*iqAdjust.y; + _bq = 1.7046f*iqAdjust.x +1.1069f*iqAdjust.y; + } + + void decodeBlock(SRGB* srgb) + { + int fLength = _length/2 + 1; + + // Filter I + _chromaForward.execute(_iTime, _frequency); + for (int f = 0; f < fLength/2; ++f) { + _frequency[f + fLength/2 + 1] = + _frequency[fLength/2 - 1 - f].conjugate(); + } + for (int f = 0; f < fLength; ++f) + _frequency[f] *= _iResponse[f]; + _backward.execute(_frequency, _iTime); + + // Filter Q + _chromaForward.execute(_qTime, _frequency); + for (int f = 0; f < fLength/2; ++f) { + _frequency[f + fLength/2 + 1] = + _frequency[fLength/2 - 1 - f].conjugate(); + } + for (int f = 0; f < fLength; ++f) + _frequency[f] *= _qResponse[f]; + _backward.execute(_frequency, _qTime); + + // Remove remodulated IQ from Y + for (int t = 0; t < _length; t += 4) { + _yTime[t] -= _qTime[t]*_chromaScale; + _yTime[t + 1] += _iTime[t + 1]*_chromaScale; + _yTime[t + 2] += _qTime[t + 2]*_chromaScale; + _yTime[t + 3] -= _iTime[t + 3]*_chromaScale; + } + + // Filter Y + _lumaForward.execute(_yTime, _frequency); + for (int f = 0; f < fLength; ++f) + _frequency[f] *= _yResponse[f]; + _backward.execute(_frequency, _yTime); + + for (int t = _padding; t < _padding + _outputLength; ++t) { + float y = _yTime[t] + _brightness2; + Complex iq(_iTime[t], _qTime[t]); + *srgb = SRGB(byteClamp(y + _ri*iq.x + _rq*iq.y), + byteClamp(y + _gi*iq.x + _gq*iq.y), + byteClamp(y + _bi*iq.x + _bq*iq.y)); + ++srgb; + } + } + + double getHue() { return _hue; } + void setHue(double hue) { _hue = static_cast(hue); } + double getSaturation() { return _saturation; } + void setSaturation(double saturation) + { + _saturation = static_cast(saturation); + } + double getContrast() { return _contrast; } + void setContrast(double contrast) + { + _contrast = static_cast(contrast); + } + double getBrightness() { return _brightness; } + void setBrightness(double brightness) + { + _brightness = static_cast(brightness); + } + double getChromaBandwidth() { return _chromaBandwidth; } + void setChromaBandwidth(double chromaBandwidth) + { + _chromaBandwidth = static_cast(chromaBandwidth); + } + double getLumaBandwidth() { return _lumaBandwidth; } + void setLumaBandwidth(double lumaBandwidth) + { + _lumaBandwidth = static_cast(lumaBandwidth); + } + double getRollOff() { return _rollOff; } + void setRollOff(double rollOff) { _rollOff = static_cast(rollOff); } + double getLobes() { return _lobes; } + void setLobes(double lobes) { _lobes = static_cast(lobes); } + void setInputScaling(int scaling) { } + void setPadding(int padding) { _padding = padding; } + float* yData() { return &_yTime[0]; } + float* iData() { return &_iTime[0]; } + float* qData() { return &_qTime[0]; } + + void decodeNTSC(Byte* ntsc, SRGB* srgb) + { + float* yData = &_yTime[0]; + float* iData = &_iTime[0]; + float* qData = &_qTime[0]; + for (int x = 0; x < _length; x += 4) { + yData[x] = ntsc[0]; + yData[x + 1] = ntsc[1]; + yData[x + 2] = ntsc[2]; + yData[x + 3] = ntsc[3]; + iData[0] = -static_cast(ntsc[1]); + iData[1] = ntsc[3]; + qData[0] = ntsc[0]; + qData[1] = -static_cast(ntsc[2]); + ntsc += 4; + iData += 2; + qData += 2; + } + decodeBlock(srgb); + } +private: + float _hue; + float _saturation; + float _contrast; + float _brightness; + float _chromaBandwidth; + float _lumaBandwidth; + float _rollOff; + float _lobes; + float _chromaScale; + + float _ri; + float _gi; + float _bi; + float _rq; + float _gq; + float _bq; + float _brightness2; + int _padding; + + FFTWComplexArray _frequency; + Array _yResponse; + Array> _iResponse; + Array _qResponse; + FFTWRealArray _yTime; + FFTWRealArray _iTime; + FFTWRealArray _qTime; + FFTWPlanDFTR2C1D _lumaForward; + FFTWPlanDFTR2C1D _chromaForward; + FFTWPlanDFTC2R1D _backward; + + int _rigor; + int _length; + int _outputLength; +}; + +// A non-resampling decoder optimized to decode a small number of samples at +// once, using FIR filters. +class MatchingNTSCDecoder +{ +public: + const MatchingNTSCDecoder& operator=(const MatchingNTSCDecoder& decoder) + { + _hue = decoder._hue; + _saturation = decoder._saturation; + _contrast = decoder._contrast; + _brightness = decoder._brightness; + _chromaBandwidth = decoder._chromaBandwidth; + _lumaBandwidth = decoder._lumaBandwidth; + _rollOff = decoder._rollOff; + _lobes = decoder._lobes; + _outputLength = decoder._outputLength; + _inputScaling = decoder._inputScaling; + return *this; + } + + void setLength(int outputLength) + { + _outputLength = outputLength; + } + void calculateBurst(const Byte* burst, const Byte* active = 0) + { + Complex iq; + iq.x = static_cast(burst[0] - burst[2]); + iq.y = static_cast(burst[1] - burst[3]); + _iqAdjust = -iq.conjugate()*unit((33 + 90 + _hue)/360.0f)*_saturation* + _contrast/iq.modulus(); +// define to 1 to use the floating-point filter, 0 for integer +#define FIR_FP 0 +#if FIR_FP + _brightness2 = _brightness*256.0f; +#else + _brightness2 = static_cast(_brightness*256.0f + + 128*_inputScaling*_contrast); +#endif + float lumaHigh = _lumaBandwidth/2; + float chromaBandwidth = _chromaBandwidth / 8; + float chromaLow = (4 - _chromaBandwidth) / 8; + float chromaHigh = (4 + _chromaBandwidth) / 8; + float rollOff = _rollOff / 4; + float width = _lobes*4; + int right = static_cast(width); + int left = -right; + +#if FIR_FP + _output.ensure(_outputLength*3*sizeof(float), 1); +#else + _output.ensure(_outputLength*3*sizeof(SInt16), 1); +#endif + + int n = 1 + right - left; + _lumaKernel.ensure(n); + _chromaKernel.ensure(n); + _diffKernel.ensure(n); + float pi = static_cast(tau/2); + float lumaTotal = 0; + float chromaTotal = 0; + for (int i = 0; i < n; ++i) { + int ii = i + left; + float i1 = static_cast(ii); + float r = sinc(i1*rollOff); + float l = r*lumaHigh*sinc(i1*lumaHigh); + float c = r*chromaBandwidth*sinc(i1*chromaBandwidth); + float diff; + if (lumaHigh > chromaHigh) { + diff = r*(chromaHigh*sinc(i1*chromaHigh) - + chromaLow*sinc(i1*chromaLow)); + } + else { + if (lumaHigh > chromaLow) { + diff = r*(lumaHigh*sinc(i1*lumaHigh) - + chromaLow*sinc(i1*chromaLow)); + } + else + diff = 0; + } + + lumaTotal += l; + _lumaKernel[i] = l; + chromaTotal += c; + _chromaKernel[i] = c; + _diffKernel[i] = diff; + } + if (lumaTotal == 0) + lumaTotal = 1; + if (chromaTotal == 0) + chromaTotal = 1; + for (int i = 0; i < n; ++i) { + _lumaKernel[i] /= lumaTotal; + _chromaKernel[i] /= chromaTotal; + } + + static const float channelPositions[3] = {0, 0, 0}; + + _filter.generate(Vector2(_outputLength, 1), 2, + channelPositions, 3, channelPositions, width, + [=](float distance, int inputChannel, int outputChannel) + { + int d = static_cast(distance) - left; + float r; + if ((inputChannel & 1) == 0) { + // Luma + r = _contrast*_lumaKernel[d]; + } + else { + // Chroma + Complex iq = 0; + switch (inputChannel & 6) { + case 0: iq.y = 1; break; + case 2: iq.x = -1; break; + case 4: iq.y = -1; break; + case 6: iq.x = 1; break; + } + iq *= _iqAdjust; + static const float i[3] = {0.9563f, -0.2721f, -1.1069f}; + static const float q[3] = {0.6210f, -0.6474f, 1.7046f}; + + r = (i[outputChannel]*iq.x + q[outputChannel]*iq.y)* + _chromaKernel[d] - _contrast*_diffKernel[d]; + } + if (active != 0 && active[inputChannel >> 1] == 0) + r = 0; + return Tuple(r, distance == 0 ? 1.0f : 0.0f); + }, + &_inputLeft, &_inputRight, 1, 0); + +#if FIR_FP + _input.ensure((_inputRight - _inputLeft)*8*sizeof(float), 1); +#else + _input.ensure((_inputRight - _inputLeft)*8*sizeof(UInt16), 1); +#endif + + _filter.setBuffers(_input, _output); + } + + void execute() { _filter.execute(); } + + void outputToSRGB(SRGB* srgb) + { +#if FIR_FP + Colour* output = reinterpret_cast(_output.data()); + for (int i = 0; i < _outputLength; ++i) { + Colour c = output[i] + + Colour(_brightness2, _brightness2, _brightness2); + srgb[i] = SRGB(byteClamp(c.x), byteClamp(c.y), byteClamp(c.z)); + } +#else + SInt16* output = reinterpret_cast(_output.data()); + static const int s = shift(); + static const int b = bias(); + for (int i = 0; i < _outputLength; ++i) { + srgb[i] = SRGB(byteClamp((output[0] + b) >> s), + byteClamp((output[1] + b) >> s), + byteClamp((output[2] + b) >> s)); + output += 3; + } +#endif + } + + void decodeNTSC(const Byte* ntsc) + { + auto input = inputData(); +#if FIR_FP + for (int i = _inputLeft; i < _inputRight; ++i) { + input[0] = ntsc[0]; + input[1] = ntsc[0]; + input += 2; + ++ntsc; + } +#else + for (int i = _inputLeft; i < _inputRight; ++i) { + input[0] = ntsc[0] - 128; + input[1] = ntsc[0] - 128; + input += 2; + ++ntsc; + } +#endif + execute(); + } + + void encodeNTSC(const Colour* input, Byte* output, int n, + const Linearizer* linearizer, int phase) + { + Complex iqAdjust = Complex(1)/_iqAdjust; + float contrast = 1/(_contrast*_inputScaling); + float brightness = -_brightness*256.0f; + for (int i = 0; i < n; ++i) { + SRGB srgb = linearizer->srgb(*input); + Complex iq; + float y = 0.299f*srgb.x + 0.587f*srgb.y + 0.114f*srgb.z; + iq.x = 0.596f*srgb.x - 0.275f*srgb.y - 0.321f*srgb.z; + iq.y = 0.212f*srgb.x - 0.528f*srgb.y + 0.311f*srgb.z; + iq *= iqAdjust; + y = (y + brightness)*contrast; + switch (phase & 3) { + case 0: + *output = byteClamp(y + iq.y); + break; + case 1: + *output = byteClamp(y - iq.x); + break; + case 2: + *output = byteClamp(y - iq.y); + break; + case 3: + *output = byteClamp(y + iq.x); + break; + } + ++output; + ++input; + ++phase; + } + } + + double getHue() { return _hue; } + void setHue(double hue) { _hue = static_cast(hue); } + double getSaturation() { return _saturation; } + void setSaturation(double saturation) + { + _saturation = static_cast(saturation); + } + double getContrast() { return _contrast; } + void setContrast(double contrast) + { + _contrast = static_cast(contrast); + } + double getBrightness() { return _brightness; } + void setBrightness(double brightness) + { + _brightness = static_cast(brightness); + } + double getChromaBandwidth() { return _chromaBandwidth; } + void setChromaBandwidth(double chromaBandwidth) + { + _chromaBandwidth = static_cast(chromaBandwidth); + } + double getLumaBandwidth() { return _lumaBandwidth; } + void setLumaBandwidth(double lumaBandwidth) + { + _lumaBandwidth = static_cast(lumaBandwidth); + } + double getRollOff() { return _rollOff; } + void setRollOff(double rollOff) { _rollOff = static_cast(rollOff); } + double getLobes() { return _lobes; } + void setLobes(double lobes) { _lobes = static_cast(lobes); } + void setInputScaling(int scaling) { _inputScaling = scaling; } + + int inputLeft() { return _inputLeft; } + int inputRight() { return _inputRight; } + int outputLeft() const { return _filter.outputLeft(); } + int outputRight() const { return _filter.outputRight(); } +#if FIR_FP + int shift() const { return 0; } + float bias() const { return _brightness2; } +#else + int shift() const { return _filter.shift(); } + int bias() const + { + int s = shift(); + return (_brightness2 << s) + (1 << (s - 1)); + } +#endif +#if FIR_FP + float* inputData() { return reinterpret_cast(_input.data()); } + float* outputData() { return reinterpret_cast(_output.data()); } +#else + SInt16* inputData() { return reinterpret_cast(_input.data()); } + SInt16* outputData() { return reinterpret_cast(_output.data()); } +#endif +private: + float _hue; + float _saturation; + float _contrast; + float _brightness; + float _chromaBandwidth; + float _lumaBandwidth; + float _rollOff; + float _lobes; + +#if FIR_FP + ImageFilterHorizontal _filter; +#else + ImageFilter16 _filter; +#endif + AlignedBuffer _input; + AlignedBuffer _output; + int _outputLength; + int _inputLeft; + int _inputRight; +#if FIR_FP + float _brightness2; +#else + int _brightness2; +#endif + Complex _iqAdjust; + int _inputScaling; + Array _lumaKernel; + Array _chromaKernel; + Array _diffKernel; +}; + +#endif // INCLUDED_NTSC_DECODE_H diff --git a/80386/disassembler/include/alfe/nullary.h b/80386/disassembler/include/alfe/nullary.h new file mode 100644 index 0000000..ed9081e --- /dev/null +++ b/80386/disassembler/include/alfe/nullary.h @@ -0,0 +1,42 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_NULLARY_H +#define INCLUDED_NULLARY_H + +#include "alfe/string.h" + +// Nullary is a helper class used for implementing classes which carry no data +// (apart from their vtable pointer). +template class Nullary : public Base +{ +public: + Nullary() : Base(instance()) { } +protected: + Nullary(const Base& other) : Base(other) { } + static Nullary instance() + { + static Nullary instance(Base::template create()); + return instance; + } +private: + template friend class NamedNullary; +}; + +// NamedNullary is used for Operator and some subclasses of Type and Kind. +template class NamedNullary + : public Nullary +{ +public: + NamedNullary() : Nullary(Nullary::instance()) { } +protected: + NamedNullary(const Base& other) : Nullary (other) { } + class Body : public Base::Body + { + public: + String toString() const { return My::name(); } + }; + + friend class Nullary; +}; + +#endif // INCLUDED_NULLARY_H diff --git a/80386/disassembler/include/alfe/operator.h b/80386/disassembler/include/alfe/operator.h new file mode 100644 index 0000000..2bf0f18 --- /dev/null +++ b/80386/disassembler/include/alfe/operator.h @@ -0,0 +1,253 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_OPERATOR_H +#define INCLUDED_OPERATOR_H + +#include "alfe/nullary.h" + +class Operator : public ConstHandle +{ +public: + Operator() { } + Operator(const ConstHandle& other) : ConstHandle(other) { } + + String toString() const { return body()->toString(); } + Operator parse(CharacterSource* source, Span* span) const + { + if (Space::parseOperator(source, toString(), span)) + return *this; + return Operator(); + } + bool operator==(const Operator& other) const + { + // All the bodies are nullary + return body() == other.body(); + } +protected: + class Body : public ConstHandle::Body + { + public: + virtual String toString() const = 0; + }; + const Body* body() const { return as(); } +}; + +class OperatorEqualTo : public NamedNullary +{ +public: + static String name() { return "=="; } +}; + +class OperatorAssignment : public NamedNullary +{ +public: + static String name() { return "="; } +}; + +class OperatorAddAssignment + : public NamedNullary +{ +public: + static String name() { return "+="; } +}; + +class OperatorSubtractAssignment + : public NamedNullary +{ +public: + static String name() { return "-="; } +}; + +class OperatorMultiplyAssignment + : public NamedNullary +{ +public: + static String name() { return "*="; } +}; + +class OperatorDivideAssignment + : public NamedNullary +{ +public: + static String name() { return "/="; } +}; + +class OperatorModuloAssignment + : public NamedNullary +{ +public: + static String name() { return "%="; } +}; + +class OperatorShiftLeftAssignment + : public NamedNullary +{ +public: + static String name() { return "<<="; } +}; + +class OperatorShiftRightAssignment + : public NamedNullary +{ +public: + static String name() { return ">>="; } +}; + +class OperatorBitwiseAndAssignment + : public NamedNullary +{ +public: + static String name() { return "&="; } +}; + +class OperatorBitwiseOrAssignment + : public NamedNullary +{ +public: + static String name() { return "|="; } +}; + +class OperatorBitwiseXorAssignment + : public NamedNullary +{ +public: + static String name() { return "~="; } +}; + +class OperatorPowerAssignment + : public NamedNullary +{ +public: + static String name() { return "^="; } +}; + +class OperatorAmpersand : public NamedNullary +{ +public: + static String name() { return "&"; } +}; + +class OperatorBitwiseOr : public NamedNullary +{ +public: + static String name() { return "|"; } +}; + +class OperatorTwiddle : public NamedNullary +{ +public: + static String name() { return "~"; } +}; + +class OperatorNot : public NamedNullary +{ +public: + static String name() { return "!"; } +}; + +class OperatorNotEqualTo : public NamedNullary +{ +public: + static String name() { return "!="; } +}; + +class OperatorLessThan : public NamedNullary +{ +public: + static String name() { return "<"; } +}; + +class OperatorGreaterThan : public NamedNullary +{ +public: + static String name() { return ">"; } +}; + +class OperatorLessThanOrEqualTo + : public NamedNullary +{ +public: + static String name() { return "<="; } +}; + +class OperatorGreaterThanOrEqualTo + : public NamedNullary +{ +public: + static String name() { return ">="; } +}; + +class OperatorShiftLeft : public NamedNullary +{ +public: + static String name() { return "<<"; } +}; + +class OperatorShiftRight : public NamedNullary +{ +public: + static String name() { return ">>"; } +}; + +class OperatorPlus : public NamedNullary +{ +public: + static String name() { return "+"; } +}; + +class OperatorMinus : public NamedNullary +{ +public: + static String name() { return "-"; } +}; + +class OperatorStar : public NamedNullary +{ +public: + static String name() { return "*"; } +}; + +class OperatorDivide : public NamedNullary +{ +public: + static String name() { return "/"; } +}; + +class OperatorModulo : public NamedNullary +{ +public: + static String name() { return "%"; } +}; + +class OperatorPower : public NamedNullary +{ +public: + static String name() { return "^"; } +}; + +class OperatorFunctionCall + : public NamedNullary +{ +public: + static String name() { return "()"; } +}; + +class OperatorIndex : public NamedNullary +{ +public: + static String name() { return "[]"; } +}; + +class OperatorIncrement : public NamedNullary +{ +public: + static String name() { return "++"; } +}; + +class OperatorDecrement : public NamedNullary +{ +public: + static String name() { return "--"; } +}; + +#endif // INCLUDED_OPERATOR_H diff --git a/80386/disassembler/include/alfe/owning_array.h b/80386/disassembler/include/alfe/owning_array.h new file mode 100644 index 0000000..d83c9ab --- /dev/null +++ b/80386/disassembler/include/alfe/owning_array.h @@ -0,0 +1,21 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_OWNING_ARRAY_H +#define INCLUDED_OWNING_ARRAY_H + +// An object which holds other objects and deletes them all on destruction. +template class OwningArray : public AppendableArray +{ +public: + void add(T* object) + { + append(object); + } + ~OwningArray() + { + for (int i = 0; i < count(); ++i) + delete (*this)[i]; + } +}; + +#endif // INCLUDED_OWNING_ARRAY_H diff --git a/80386/disassembler/include/alfe/parse_tree_object.h b/80386/disassembler/include/alfe/parse_tree_object.h new file mode 100644 index 0000000..3fab42c --- /dev/null +++ b/80386/disassembler/include/alfe/parse_tree_object.h @@ -0,0 +1,30 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_PARSE_TREE_OBJECT_H +#define INCLUDED_PARSE_TREE_OBJECT_H + +class ParseTreeObject : public Handle +{ +public: + Span span() const { return body()->span(); } + void setSpan(Span span) { body()->setSpan(span); } + + class Body : public Handle::Body + { + public: + Body(const Span& span) : _span(span) { } + Span span() const { return _span; } + void setSpan(Span span) { _span = span; } + private: + Span _span; + }; + +protected: + ParseTreeObject() { } + ParseTreeObject(Handle other) : Handle(other) { } + + const Body* body() const { return as(); } + Body* body() { return as(); } +}; + +#endif // INCLUDED_PARSE_TREE_OBJECT_H diff --git a/80386/disassembler/include/alfe/parser.h b/80386/disassembler/include/alfe/parser.h new file mode 100644 index 0000000..f7d4c28 --- /dev/null +++ b/80386/disassembler/include/alfe/parser.h @@ -0,0 +1,492 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_PARSER_H +#define INCLUDED_PARSER_H + +#include "alfe/code.h" +#include "alfe/space.h" + +class Parser : Uncopyable +{ +public: + CodeList parseFromFile(File file) + { + CodeList c; + parseFromFile(c, file); + return c; + } + void parseFromString(Code code, String s) + { + CharacterSource source(s); + do { + CharacterSource s2 = source; + if (s2.get() == -1) + return; + parseStatementOrFail(code, &source); + } while (true); + } +private: + void parseFromFile(Code code, File file) + { + parseFromString(code, file.contents()); + } + bool parseStatement(Code code, CharacterSource* source) + { + if (parseExpressionStatement(code, source)) + return true; + if (parseFunctionDefinitionStatement(code, source)) + return true; + if (parseAssignment(code, source)) + return true; + if (parseCompoundStatement(code, source)) + return true; + if (parseTycoDefinitionStatement(code, source)) + return true; + if (parseNothingStatement(source)) + return true; + if (parseIncrementDecrementStatement(code, source)) + return true; + if (parseConditionalStatement(code, source)) + return true; + if (parseSwitchStatement(code, source)) + return true; + if (parseReturnStatement(code, source)) + return true; + if (parseIncludeStatement(code, source)) + return true; + if (parseBreakOrContinueStatement(code, source)) + return true; + if (parseForeverStatement(code, source)) + return true; + if (parseWhileStatement(code, source)) + return true; + if (parseForStatement(code, source)) + return true; + if (parseLabelStatement(code, source)) + return true; + if (parseGotoStatement(code, source)) + return true; + return false; + } + void parseStatementOrFail(Code code, CharacterSource* source) + { + if (!parseStatement(code, source)) + source->location().throwError("Expected statement"); + } + bool parseExpressionStatement(Code code, CharacterSource* source) + { + CharacterSource s = *source; + Expression expression = Expression::parse(&s); + if (!expression.valid()) + return false; + Span span; + if (!Space::parseCharacter(&s, ';', &span)) + return false; + _lastSpan = span; + *source = s; + if (!expression.mightHaveSideEffect()) + source->location().throwError("Statement has no effect"); + code.insert(expression, expression.span() + span); + return true; + } + bool parseAssignment(Code code, CharacterSource* source) + { + CharacterSource s = *source; + Expression left = Expression::parse(&s); + Location operatorLocation = s.location(); + if (!left.valid()) + return false; + Span span; + + static const Operator ops[] = { + OperatorAssignment(), OperatorAddAssignment(), + OperatorSubtractAssignment(), OperatorMultiplyAssignment(), + OperatorDivideAssignment(), OperatorModuloAssignment(), + OperatorShiftLeftAssignment(), OperatorShiftRightAssignment(), + OperatorBitwiseAndAssignment(), OperatorBitwiseOrAssignment(), + OperatorBitwiseXorAssignment(), OperatorPowerAssignment(), + Operator() }; + + const Operator* op; + for (op = ops; op->valid(); ++op) + if (Space::parseOperator(&s, op->toString(), &span)) + break; + if (!op->valid()) + return false; + + *source = s; + Expression right = Expression::parseOrFail(source); + Space::assertCharacter(source, ';', &span); + _lastSpan = span; + + code.insert(FunctionCallExpression::binary(*op, + span, + FunctionCallExpression::unary(OperatorAmpersand(), Span(), left), + right), left.span() + span); + return true; + } + List parseParameterList(CharacterSource* source) + { + List list; + VariableDefinition parameter = VariableDefinition::parse(source); + if (!parameter.valid()) + return list; + list.add(parameter); + Span span; + while (Space::parseCharacter(source, ',', &span)) { + VariableDefinition parameter = VariableDefinition::parse(source); + if (!parameter.valid()) + source->location().throwError("Expected parameter"); + list.add(parameter); + } + return list; + } + bool parseFunctionDefinitionStatement(Code code, CharacterSource* source) + { + CharacterSource s = *source; + TycoSpecifier returnTypeSpecifier = TycoSpecifier::parse(&s); + if (!returnTypeSpecifier.valid()) + return false; + Identifier name = Identifier::parse(&s); + if (!name.valid()) + return false; + Span span; + if (!Space::parseCharacter(&s, '(')) + return false; + *source = s; + List parameterList = parseParameterList(source); + Space::assertCharacter(source, ')'); + Span span; + if (Space::parseKeyword(source, "from", &span)) { + Expression dll = Expression::parseOrFail(source); + Space::assertCharacter(source, ';', &span); + _lastSpan = span; + code.insert(returnTypeSpecifier, + name, parameterList, dll, returnTypeSpecifier.span() + span); + return true; + } + CodeList body; + parseStatementOrFail(body, source); + code.insert(returnTypeSpecifier, + name, parameterList, body, returnTypeSpecifier.span() + _lastSpan); + return true; + } + void parseStatementSequence(Code code, CharacterSource* source) + { + do { + if (!parseStatement(code, source)) + return; + } while (true); + } + bool parseCompoundStatement(Code code, CharacterSource* source) + { + Span span; + if (!Space::parseCharacter(source, '{', &span)) + return false; + parseStatementSequence(code, source); + Space::assertCharacter(source, '}', &span); + _lastSpan = span; + return true; + } + // TycoDefinitionStatement := TycoSignifier "=" TycoSpecifier ";" + bool parseTycoDefinitionStatement(Code code, CharacterSource* source) + { + CharacterSource s = *source; + CharacterSource s2 = s; + TycoSignifier tycoSignifier = TycoSignifier::parse(&s); + if (!tycoSignifier.valid()) + return false; + if (!Space::parseCharacter(&s, '=')) + return false; + *source = s; + TycoSpecifier tycoSpecifier = TycoSpecifier::parse(source); + Span span; + Space::assertCharacter(source, ';', &span); + _lastSpan = span; + code.insert(tycoSignifier, tycoSpecifier, + tycoSignifier.span() + span); + return true; + } + bool parseNothingStatement(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "nothing", &span)) + return false; + Space::assertCharacter(source, ';', &span); + _lastSpan = span; + return true; + } + bool parseIncrementDecrementStatement(Code code, CharacterSource* source) + { + Span span; + Operator o = OperatorIncrement().parse(source, &span); + if (!o.valid()) + o = OperatorDecrement().parse(source, &span); + if (!o.valid()) + return false; + Expression lValue = Expression::parse(source); + Span span2; + Space::assertCharacter(source, ';', &span2); + _lastSpan = span2; + code.insert(FunctionCallExpression::unary(o, span, + FunctionCallExpression::unary( + OperatorAmpersand(), Span(), lValue)), + span + span2); + return true; + } + void parseConditionalStatement2(Code code, CharacterSource* source, + Span span, bool unlessStatement) + { + Space::assertCharacter(source, '('); + Expression condition = Expression::parseOrFail(source); + Space::assertCharacter(source, ')'); + CodeList conditionalCode; + parseStatementOrFail(conditionalCode, source); + span += _lastSpan; + CodeList elseCode; + if (Space::parseKeyword(source, "else")) + parseStatementOrFail(elseCode, source); + else { + if (Space::parseKeyword(source, "elseIf")) + parseConditionalStatement2(elseCode, source, span, false); + else { + if (Space::parseKeyword(source, "elseUnless")) + parseConditionalStatement2(elseCode, source, span, true); + } + } + if (unlessStatement) + condition = !condition; + code.insert(condition, conditionalCode, elseCode, + span + _lastSpan); + } + // ConditionalStatement = (`if` | `unless`) ConditionedStatement + // ((`elseIf` | `elseUnless`) ConditionedStatement)* [`else` Statement]; + // ConditionedStatement = "(" Expression ")" Statement; + bool parseConditionalStatement(Code code, CharacterSource* source) + { + Span span; + if (Space::parseKeyword(source, "if", &span)) { + parseConditionalStatement2(code, source, span, false); + return true; + } + if (Space::parseKeyword(source, "unless", &span)) { + parseConditionalStatement2(code, source, span, true); + return true; + } + return false; + } + SwitchStatement::Case parseCase(CharacterSource* source) + { + List expressions; + bool defaultType; + Span span; + if (Space::parseKeyword(source, "case", &span)) { + defaultType = false; + do { + Expression expression = Expression::parseOrFail(source); + expressions.add(expression); + if (!Space::parseCharacter(source, ',')) + break; + } while (true); + } + else { + defaultType = true; + if (!Space::parseKeyword(source, "default", &span)) + source->location().throwError("Expected case or default"); + } + Space::assertCharacter(source, ':'); + CodeList code; + parseStatementOrFail(code, source); + span += _lastSpan; + if (defaultType) + return SwitchStatement::Case(code, span); + return SwitchStatement::Case(expressions, code, span); + } + bool parseSwitchStatement(Code code, CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "switch", &span)) + return false; + Space::assertCharacter(source, '('); + Expression expression = Expression::parseOrFail(source); + Space::assertCharacter(source, ')'); + Space::assertCharacter(source, '{'); + SwitchStatement::Case defaultCase; + + CharacterSource s = *source; + List cases; + do { + SwitchStatement::Case c = parseCase(source); + if (!c.valid()) + break; + if (c.isDefault()) { + if (defaultCase.valid()) + s.location().throwError( + "This switch statement already has a default case"); + defaultCase = c; + } + else + cases.add(c); + } while (true); + Space::assertCharacter(source, '}', &span); + _lastSpan = span; + code.insert(expression, defaultCase, cases, span); + return true; + } + bool parseReturnStatement(Code code, CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "return", &span)) + return false; + Expression expression = Expression::parseOrFail(source); + Space::assertCharacter(source, ';', &span); + _lastSpan = span; + code.insert(expression, span); + return true; + } + bool parseIncludeStatement(Code code, CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "include", &span)) + return false; + Expression expression = parseExpression(source); + + StringLiteralExpression s(expression); + if (!s.valid()) { + expression.span().throwError("Argument to include must be a " + "simple string"); + } + String path = s.string(); + + //Resolver resolver; + //resolver.resolve(expression); + //Evaluator evaluator; + //Value value = evaluator.evaluate(expression).convertTo(StringType()); + //String path = value.value(); + + File lastFile = _currentFile; + _currentFile = File(path, _currentFile.parent()); + parseFromFile(code, _currentFile); + _currentFile = lastFile; + } + bool parseBreakOrContinueStatement(Code code, CharacterSource* source) + { + int breakCount = 0; + bool hasContinue = false; + Span span; + do { + if (Space::parseKeyword(source, "break", &span)) + ++breakCount; + else + break; + } while (true); + if (Space::parseKeyword(source, "continue", &span)) + hasContinue = true; + if (breakCount == 0 && !hasContinue) + return false; + Space::assertCharacter(source, ';', &span); + _lastSpan = span; + code.insert(span, breakCount, hasContinue); + return true; + } + bool parseForeverStatement(Code code, CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "forever", &span)) + return false; + CodeList body; + parseStatementOrFail(body, source); + code.insert(body, span); + return true; + } + bool parseWhileStatement(Code code, CharacterSource* source) + { + Span span; + CodeList doCode; + bool foundDo = false; + if (Space::parseKeyword(source, "do", &span)) { + foundDo = true; + parseStatementOrFail(doCode, source); + } + bool foundWhile = false; + bool foundUntil = false; + if (Space::parseKeyword(source, "while", &span)) + foundWhile = true; + else + if (Space::parseKeyword(source, "until", &span)) + foundUntil = true; + if (!foundWhile && !foundUntil) { + if (foundDo) + source->location().throwError("Expected while or until"); + return false; + } + Space::assertCharacter(source, '('); + Expression condition = Expression::parse(source); + Space::assertCharacter(source, ')'); + CodeList body; + parseStatementOrFail(body, source); + CodeList doneCode; + if (Space::parseKeyword(source, "done")) + parseStatementOrFail(doneCode, source); + span += _lastSpan; + if (foundUntil) + condition = !condition; + code.insert(doCode, condition, body, doneCode, span); + return true; + } + bool parseForStatement(Code code, CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "for", &span)) + return false; + Space::assertCharacter(source, '('); + CodeList preCode; + if (!parseStatement(preCode, source)) + Space::assertCharacter(source, ';'); + Expression expression = Expression::parse(source); + Space::assertCharacter(source, ';'); + CodeList postCode; + parseStatement(postCode, source); + Space::parseCharacter(source, ')'); + CodeList body; + parseStatement(body, source); + span += _lastSpan; + CodeList doneCode; + if (Space::parseKeyword(source, "done")) { + parseStatementOrFail(doneCode, source); + span += _lastSpan; + } + code.insert(preCode, expression, postCode, body, + doneCode, span); + return true; + } + bool parseLabelStatement(Code code, CharacterSource* source) + { + CharacterSource s2 = *source; + Identifier identifier = Identifier::parse(&s2); + if (!identifier.valid()) + return false; + Span span; + if (!Space::parseCharacter(&s2, ':', &span)) + return false; + _lastSpan = span; + code.insert(identifier, identifier.span() + span); + return true; + } + bool parseGotoStatement(Code code, CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "goto", &span)) + return false; + Expression expression = Expression::parseOrFail(source); + Span span2; + Space::parseCharacter(source, ';', &span); + code.insert(expression, span); + return true; + } + + Span _lastSpan; + File _currentFile; +}; + +#endif // INCLUDED_PARSER_H \ No newline at end of file diff --git a/80386/disassembler/include/alfe/philosophy.txt b/80386/disassembler/include/alfe/philosophy.txt new file mode 100644 index 0000000..84c4c1d --- /dev/null +++ b/80386/disassembler/include/alfe/philosophy.txt @@ -0,0 +1,4 @@ +Error handling philosophy + Every error is an Exception + A particular error is thrown as Exception unless/until there is a reason to catch one particular error (or set of errors) and not another, then it becomes its own subclass + Put as much information as we have into the Exception diff --git a/80386/disassembler/include/alfe/pipes.h b/80386/disassembler/include/alfe/pipes.h new file mode 100644 index 0000000..b075fd3 --- /dev/null +++ b/80386/disassembler/include/alfe/pipes.h @@ -0,0 +1,838 @@ +// Classes for Filter graphs for manipulating streams of samples. +// +// A Filter is an object which can produce data, consume data or both (or, in +// the trivial case, neither). +// +// A Filter that produces data but does not consume is called a Source. +// A Filter that consumes data but does not produce is called a Sink. +// A Filter that both produces and consumes is called a Pipe. +// +// Filters communicate through Source and Sink objects. A combination of a +// Source and a Sink forms a circular buffer internally. These buffers always +// grow (never shrink) and are always a power of two number of samples. +// Therefore it is important to limit the amount of data a Filter produces +// before that data is consumed. +// +// Rather than accessing the buffer directly, a Filter obtains an Accessor +// object from the Source or Sink which encapsulates reading and writing +// operations. Calls to Accessor methods (especially the "one sample per call" +// methods) are expected to be inlined for maximum filter performance. +// +// Filters can work in two modes, "push mode" (Source driven) or "pull mode" +// (Sink driven). Not all filters in a filter graph are required to operate in +// the same mode, and any given filter may operate in both push and pull modes +// as necessary. +// +// In "push mode", a Filter produces data via one or more Source objects. When +// a Source's buffer gets too full, the connected Sink is notified to consume +// some data. These Filters that these Sinks are connected to may in turn +// produce more data and so on. +// +// In "pull mode" a Filter consumes data via one or more Sink objects. When a +// Sink's buffer is too empty, the connected Source is notified to produce some +// data. That Filter may in turn consume more data and so on. +// +// Filters are responsible for deciding how much data they will produce at once +// and how much data they will consume at once (which is also how much data the +// attached buffer will hold before it is considered "full"), though a hint is +// passed in to produce() (the number of samples required) and to consume() +// (the number of samples available). For most purposes this should generally +// be on the order of a kilobyte, depending on the number of Filters in the +// graph. +// +// Because Filters can be connected and disconnected at run time, each Filter +// doesn't know at compile time what it is connected to. In an ideal world it +// would be possible to instantiate the compiler back-end at runtime when +// connections are made to generate ideal code for a given Filter graph. +// However, that technology is not currently practical. +// +// Hence, a virtual function call is required for each produce() or consume() +// operation. A virtual function call cannot be inlined and interferes with a +// CPU's prediction heuristics, so is relatively expensive - perhaps on the +// order of 40 cycles. For data sampled at tens of MHz passing through tens of +// filters, this quickly becomes the limiting factor if a Filter only +// processes one sample per call. Hence Filters process multiple samples per +// call. +// +// An application will perform best if all the data required by its inner loop +// resides in L1 cache, which is generally 32Kb, so the average buffer size +// multiplied by the number of Connections should be less than this. +// +// A Pipe with a single Source and a single Sink can be implemented using the +// Pipe helper class. +// +// Sources can specify how many samples are remaining by calling "remaining". +// Sinks can obtain this figure (suitably adjusted for the latency caused by +// intermediate pipes) by calling "remaining". +// +// See also: http://dancinghacker.com/code/dataflow/ which is similar. + +#include "alfe/main.h" + +#ifndef INCLUDED_PIPES_H +#define INCLUDED_PIPES_H + +//#include "alfe/thread.h" + +// Infrastructure + +// Number of samples a Sink will accumulate by default before consume() is +// called. +static const int defaultSampleCount = 1024; + +// Base class for all filters. Filters are not copyable because connected +// filters will have pointers to them or their members. +class Filter : Uncopyable { }; + + +// Describes a circular buffer that can be read from or written to. +template class Accessor +{ +public: + Accessor() { } + Accessor(T* buffer, int position, int mask) + : _buffer(buffer), + _position(position), + _mask(mask) + { } + void advance(int count) { _position = offset(count); } + T& item(int position) { return _buffer[offset(position)]; } + T& item() + { + T& sample = _buffer[_position]; + advance(1); + return sample; + } + template void items(F& f, int count) + { + int n = min(count, _mask + 1 - _position); + f(_buffer + _position, n); + f(_buffer, count - n); + advance(count); + } + template void items(F& f, int position, int count) + { + int start = offset(position); + int n = min(count, _mask + 1 - (_position + position)); + f(_buffer + start, n); + f(_buffer, count - n); + } +private: + int offset(int delta) { return (delta + _position)&_mask; } + + T* _buffer; + int _position; + int _mask; +}; + + +// Functor to memcpy from an Accessor. +template class CopyTo +{ +public: + CopyTo(T* destination) : _destination(destination) { } + void operator()(T* source, int n) + { + memcpy(_destination, source, n*sizeof(T)); + _destination += n; + } +private: + T* _destination; +}; + + +// Functor to memcpy to an Accessor. +template class CopyFrom +{ +public: + CopyFrom(T* source) : _source(source) { } + void operator()(T* destination, int n) + { + memcpy(destination, _source, n*sizeof(T)); + _source += n; + } +private: + T* _source; +}; + + +// Specialization to copy from one Accessor to another. +template class CopyTo> +{ +public: + CopyTo(Accessor destination) : _destination(destination) { } + void operator()(T* source, int n) + { + _destination.items(CopyFrom(source), n); + } +private: + Accessor _destination; +}; + + +// Specialization to copy from a one Accessor to another. +template class CopyFrom> +{ +public: + CopyFrom(Accessor source) : _source(source) { } + void operator()(T* destination, int n) + { + _source.items(CopyTo(destination), n); + } +private: + Accessor _source; +}; + + +// Functor to zero samples in an Accessor using memset. +template class Zero +{ +public: + void operator()(T* destination, int n) + { + memset(destination, 0, n*sizeof(T)); + } +}; + + +// Functor to read samples from a Stream. +template class ReadFrom +{ +public: + ReadFrom(Stream stream) : _stream(stream) { } + void operator()(T* destination, int n) + { + _stream.read(destination, n*sizeof(T)); + } +private: + Stream _stream; +}; + + +// Functor to write samples to a Stream. +template class WriteTo +{ +public: + WriteTo(Stream* stream) : _stream(stream) { } + void operator()(T* source, int n) { _stream->write(source, n*sizeof(T)); } +private: + Stream* _stream; +}; + + +// Base class for filter endpoints. An EndPoint is either a Source or a Sink. +template class EndPoint : public Filter +{ +protected: + Accessor accessor() { return Accessor(_buffer, _position, _mask); } + int offset(int delta) { return (delta + _position)&_mask; } + + T* _buffer; + int _mask; + int _position; + int _count; + int _size; + int _remaining; +}; + + +template class Source; + +// A Sink is the means by which a Filter consumes data. Filters with a single +// Sink and no Source can just inherit from Sink, others should include it as +// a member. The argument to the constructor should be increased if +// defaultSampleCount is too few samples for consume() to do anything with, +// or decreased if it's so many that latency will be too high. +template class Sink : public EndPoint +{ +public: + Sink(int n = defaultSampleCount) : _n(n), _finite(false), _source(0) { } + void connect(Source* source) + { + if (_source == source) + return; + _source = source; + this->_buffer = source->_buffer; + this->_count = source->_count; + this->_size = source->_size; + this->_mask = source->_mask; + this->_position = + (source->_position + this->_size - this->_count) & this->_mask; + source->connect(this); + } + bool connected() const { return _source != 0; } + virtual void consume(int n) = 0; + Accessor reader(int n) + { + _source->ensureData(n); + return this->accessor(); + } + void read(int n) + { + this->_count -= n; + this->_position = this->offset(n); + _source->_count -= n; + _remaining -= n; + } + void consume() + { + while (this->_count >= _n) + consume(this->_count); + } + int remaining() + { + if (!_finite) + return 0x40000000; + else + return _remaining; + } + bool finite() { return _finite; } +protected: + int _n; +private: + void remaining(int n) { _remaining = n; _finite = true; } + Source* _source; + bool _finite; + int _remaining; + + friend class Source; +}; + + +// A Source is the means by which a Filter produces data. Filters with a +// single Source and no Sink can just inherit from Source, others should +// include it as a member. +template class Source : public EndPoint +{ +public: + Source() : _pulling(false), _sink(0) + { + this->_position = 0; + this->_size = 1; + this->_count = 0; + this->_mask = 0; + this->_buffer = new T[1]; + } + ~Source() { delete[] this->_buffer; } + void connect(Sink* sink) + { + if (_sink == sink) + return; + _sink = sink; + sink->connect(this); + } + bool connected() const { return _sink != 0; } + virtual void produce(int n) = 0; + Accessor writer(int n) + { + // Make sure we have enough space for an additional n items + int newN = n + this->_count; + if (this->_size < newN) { + // Double the size of the buffer until it's big enough. + int newSize = this->_size; + while (newSize < newN) + newSize <<= 1; + // Since buffers never shrink, this doesn't need to be particularly + // fast. Just copy all the data to the start of the new buffer. + T* newBuffer = new T[newSize]; + int start = this->offset(-this->_count); + int n1 = min(this->_count, this->_size - start); + memcpy(newBuffer, this->_buffer + start, n1*sizeof(T)); + memcpy(newBuffer + n1, this->_buffer, + (this->_count - n1)*sizeof(T)); + delete[] this->_buffer; + this->_position = this->_count; + this->_size = newSize; + this->_buffer = newBuffer; + this->_mask = this->_size - 1; + _sink->_buffer = this->_buffer; + _sink->_size = this->_size; + _sink->_mask = this->_mask; + _sink->_position = 0; + } + return this->accessor(); + } + void written(int n) + { + this->_position = this->offset(n); + this->_count += n; + _sink->_count += n; + // If we're pulling, the consumer will process anyway so we don't + // do it here. + if (!_pulling) + _sink->consume(); + } + void ensureData(int n) + { + _pulling = true; + while (this->_count < n) + produce(n - this->_count); + _pulling = false; + } + void remaining(int n) { _sink->remaining(n + this->_count); } +private: + Sink* _sink; + bool _pulling; + + friend class Sink; +}; + + +// Base classes to make filter implementation easier. + +// Base class that can be used by a filter with a single Source and a single +// Sink. +template class Pipe + : public Filter +{ +public: + Pipe(P* p, int n = defaultSampleCount) + : _source(p), _sink(p, n) + { } + Source* source() { return &_source; } + Sink* sink() { return &_sink; } + virtual void produce(int n) { consume(n); } + virtual void consume(int n) { produce(n); } +protected: + class PipeSource : public Source + { + public: + PipeSource(P* p) : _p(p) { } + void produce(int n) { _p->produce(n); } + private: + P* _p; + }; + class PipeSink : public Sink + { + public: + PipeSink(P* p, int n) : Sink(n), _p(p) { } + void consume(int n) { _p->consume(n); } + private: + P* _p; + }; + PipeSource _source; + PipeSink _sink; +}; + + +// Filter implementations + +// A Sink that does nothing with its data. Useful when you have a Filter with +// multiple Sources but don't need the data from all of them. Push only. +template class BitBucketSink : public Sink +{ +public: + void consume(int n) { this->reader(n); this->read(n); } +}; + + +// A Source that always produces the same sample. Pull only. Infinite. +template class ConstantSource : public Source +{ +public: + ConstantSource(T sample) : _sample(sample) { } + void produce(int n) + { + Accessor w = this->writer(n); + for (int i = 0; i < n; ++i) + w.write(_sample); + this->written(n); + } +private: + T _sample; +}; + + +// Data for a PeriodicSource filter. This is separate from PeriodicSource so +// that several producers can use the same data. +// TODO: refactor File constructor with File::contents(). +template class PeriodicSourceData +{ +public: + PeriodicSourceData(int size) : _buffer(size) { } + PeriodicSourceData(File file) + { + FileStream stream = file.openRead(); + UInt64 size = stream.size(); + if (size >= 0x80000000) + throw Exception("2Gb or more in file " + file.path()); + _buffer.resize(size / sizeof(T)); + stream.read(&_buffer[0], size); + } + + // Function for accessing the underlying buffer directly (to fill it, and + // for use by PeriodicSource). + T* buffer() { return &_buffer[0]; } + + // For use by PeriodicSource. + int length() const { return _buffer.count(); } +private: + Array _buffer; +}; + + +// A Source that produces the same information repeatedly. Pull only. Never +// finishes. +template class PeriodicSource : public Source +{ +public: + PeriodicSource(PeriodicSourceData* data, int offset) + : _data(data), + _offset(offset) + { } + void produce(int n) + { + int length = _data->length(); + T* buffer = _data->buffer(); + if (n < length - _offset) { + this->writer(n).items(CopyFrom(buffer + _offset), n); + _offset += n; + } + else { + n = length - _offset; + this->writer(n).items(CopyFrom(buffer + _offset), n); + _offset = 0; + } + this->written(n); + } +private: + PeriodicSourceData* _data; + int _offset; +}; + + +// A Source that takes data from a file. Pull only. Finishes. +template class FileSource : public Source +{ +public: + FileSource(File file) : _stream(file.openRead()) + { + _size = _stream.size() / sizeof(T); + } + void produce(int n) + { + int nRead = n; + int nRemaining = n; + if (nRead > _size) + nRead = static_cast(_size); + Accessor w = this->writer(n); + if (nRead > 0) { + w.items(ReadFrom(_stream), nRead); + nRemaining -= nRead; + } + if (nRemaining > 0) + w.items(Zero(), nRemaining); + _size -= n; + this->written(n); + if (_size < 0x40000000) + this->remaining(static_cast(_size)); + } +private: + FileStream _stream; + SInt64 _size; +}; + + +// A pipe that just takes samples from its Sink and sends them directly to its +// Source. This is useful as a pump: external code can call the produce() +// method directly to cause data to be pulled via the Sink and then pushed via +// the Source. +template class NopPipe : public Pipe> +{ +public: + void produce(int n) + { + this->_source.writer(n).items( + CopyFrom >(this->_sink.reader(n)), n); + this->_sink.read(n); + this->_source.written(n); + if (this->_sink.finite()) + this->_source.remaining(this->_sink.remaining()); + } +}; + + +// A filter that converts from one type to another (with static_cast<>). +template class CastPipe + : public Pipe> +{ +public: + void produce(int n) + { + Accessor reader = this->_sink.reader(n); + Accessor writer = this->_source.writer(n); + for (int i = 0; i < n; ++i) + writer.item() = static_cast(reader.item()); + this->_sink.read(n); + this->_source.written(n); + if (this->_sink.finite()) + this->_source.remaining(this->_sink.remaining()); + } +}; + + +// A filter with one sink and two sources, each of which yields identical data +// to the Sink. A pull from one Source may result in a push from the other. +template class Tee +{ +public: + Tee(int n = defaultSampleCount) + : _source1(this), _source2(this), _sink(this, n) { } + Sink* sink() { return &_sink; } + Source* source1() { return &_source1; } + Source* source2() { return &_source2; } + void process(int n) + { + Accessor r = _sink.reader(n); + _source1.writer(n).items(CopyFrom >(r), n); + _source1.written(n); + _source2.writer(n).items(CopyFrom >(r), n); + _source2.written(n); + _sink.read(n); + if (_sink.finite()) { + _source1.remaining(_sink.remaining()); + _source2.remaining(_sink.remaining()); + } + } +protected: + class TeeSource : public Source + { + public: + TeeSource(Tee* t) : _t(t) { } + void produce(int n) { _t->process(n); } + private: + Tee* _t; + }; + class TeeSink : public Sink + { + public: + TeeSink(Tee* t, int n) : Sink(n), _t(t) { } + void consume(int n) { _t->process(n); } + void remaining(int n) { _t->remaining(n); } + private: + Tee* _t; + }; + TeeSink _sink; + TeeSource _source1; + TeeSource _source2; +}; + + +// A pipe that interpolates using the nearest-neighbor algorithm. +template class NearestNeighborInterpolator + : public Pipe> +{ +public: + // For every "consumerRate" samples consumed we will produce "producerRate" + // samples. + NearestNeighborInterpolator(Rate producerRate, Rate consumerRate, + Rate offset = 0, int n = defaultSampleCount) + : Pipe>(this, n), + _producerRate(producerRate), + _consumerRate(consumerRate), + _offset(offset) + { } + void produce(int n) + { + // TODO: We can probably speed this up somewhat by copying blocks + Accessor reader = this->_sink.reader(n); + Accessor writer = this->_source.writer(toProduce(n) + 1); + int written = 0; + for (int i = 0; i < n; ++i) { + T sample = reader.item(); + while (_offset >= 0) { + writer.item() = sample; + ++written; + _offset -= _producerRate; + } + _offset += _consumerRate; + } + this->_sink.read(n); + this->_source.written(written); + // TODO: Correct for _offset so that remaining goes down smoothly + if (this->_sink.finite()) + this->_source.remaining(toProduce(this->_sink.remaining())); + } +private: + int toProduce(int consume) + { + return static_cast( + (static_cast(consume)*_producerRate)/_consumerRate); + } + Rate _producerRate; + Rate _consumerRate; + Rate _offset; +}; + + +// A pipe that interpolates using the linear interpolation. TODO: modify this +// so it downsamples as well. +template class LinearInterpolator + : public Pipe> +{ +public: + // For every "consumerRate" samples consumed we will produce "producerRate" + // samples. + LinearInterpolator(Rate producerRate, Rate consumerRate, Rate offset = 0, + T previous = 0, int n = defaultSampleCount) + : Pipe>(this, n), + _producerRate(producerRate), + _consumerRate(consumerRate), + _offset(offset), + _previous(0) + { } + void produce(int n) + { + Accessor reader = this->_sink.reader(n); + Accessor writer = this->_source.writer(toProduce(n) + 1); + int written = 0; + for (int i = 0; i < n; ++i) { + T sample = reader.item(); + while (_offset >= 0) { + writer.item() = sample + static_cast( + (static_cast(_previous - sample)*_offset)/ + _consumerRate); + ++written; + _offset -= _producerRate; + } + _offset += _consumerRate; + _previous = sample; + } + this->_sink.read(n); + this->_source.written(written); + // TODO: Correct for _offset so that remaining goes down smoothly + if (this->_sink.finite()) + this->_source.remaining(toProduce(this->_sink.remaining())); + } +private: + int toProduce(int consume) + { + return static_cast( + (static_cast(consume)*_producerRate)/_consumerRate); + } + Rate _producerRate; + Rate _consumerRate; + Rate _offset; + T _previous; +}; + +#if 0 +// A pipe that neither pushes or pulls. If you try to push to it without +// pulling, it continues to accumulate data until it runs out of memory. If +// you try to pull from it without pushing, it blocks until data is pushed. +template> class Tank : public Pipe +{ +public: + Tank() + : _buffer(new T[1]), + _size(1), + _count(0), + _mask(0), + _readPosition(0), + _writePosition(0) + { } + void produce(int n) + { + while (_count < n) + _event.wait(); + Lock lock(&_mutex); + _source.writer(n).items(CopyFrom >(reader()), n); + _readPosition = (_readPosition + n) & _mask; + _count -= n; + _source.written(n); + if (_sink.finite()) + _source.remaining(_sink.remaining() + _count); + } + void consume(int n) + { + Lock lock(&_mutex); + // Make sure we have enough space for an additional n items + int newN = n + _count; + if (_size < newN) { + // Double the size of the buffer until it's big enough. + int newSize = _size; + while (newSize < newN) + newSize <<= 1; + T* newBuffer = new T[newSize]; + int start = offset(-_count); + int n1 = min(_count, _size - start); + memcpy(newBuffer, _buffer + start, n1*sizeof(T)); + memcpy(newBuffer + n1, _buffer, (_size - n1)*sizeof(T)); + delete[] _buffer; + _writePosition = _count; + _readPosition = 0; + _size = newSize; + _buffer = newBuffer; + _mask = _size - 1; + } + writer().items(CopyFrom >(_sink.reader(n)), n); + _sink.read(n); + _writePosition = (_writePosition + n) & _mask; + _count += n; + _event.signal(); + } +private: + Mutex _mutex; + Event _event; + + Accessor reader() { return Accessor(_buffer, _readPosition, _mask); } + Accessor writer() { return Accessor(_buffer, _writePosition, _mask); } + + T* _buffer; + int _size; + volatile int _count; + int _mask; + int _readPosition; + int _writePosition; +}; + + +// A pipe that can be both pulled from and pushed to, and which adjusts the +// rate of a connected interpolator to match the pull rate to the push rate. +// The "timeConstant" parameter must be tuned. If it is too small, the +// resampling rate will fluctuate wildly as samples are pushed and pulled. If +// it is too large, it will take too long to adjust to changes in the push or +// pull rates, leading to high latencies or stalls waiting for the connected +// Source to push (PushPullPipe will never push or pull itself). "timeConstant" +// is measured in samples consumed. +template class PushPullPipe + : public Tank> +{ +public: + PushPullPipe(int timeConstant, Interpolator* interpolator) + : _timeConstant(timeConstant), + _interpolator(interpolator) + { } + void produce(int n) + { + _produced += n*_rate; + updateRate(); + Tank::produce(n); + } + void consume(int n) + { + double c = exp(-n/_timeConstant); + _produced *= c; + _consumed *= c; + _consumed += n; + updateRate(); + Tank::consume(n); + } +private: + void updateRate() + { + // TODO: Adjust slightly so that we speed up if we have a large number + // of samples + _rate = _produced/_consumed; + _interpolator->setRate(_rate); + } + + int _timeConstant; + Interpolator* _interpolator; + double _produced; + double _consumed; + double _rate; +}; +#endif + +#endif // INCLUDED_PIPES_H diff --git a/80386/disassembler/include/alfe/pool.h b/80386/disassembler/include/alfe/pool.h new file mode 100644 index 0000000..9460731 --- /dev/null +++ b/80386/disassembler/include/alfe/pool.h @@ -0,0 +1,139 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_POOL_H +#define INCLUDED_POOL_H + +#include +#include "alfe/linked_list.h" + +// A memory pool is a fast, low-overhead way to allocate objects of type T when +// they're all going to be deleted at once. We allocate objects in blocks. Each +// block is a std::vector of blockSize Ts of size unitSize*blockSize. Note that +// Ts are constructed when a block is allocated, not when a T is requested. +// +// This is used by the grid tree Fractal programs. When those are replaced by +// quadtree equivalents, this class will be unused. +template class MemoryPool : Uncopyable +{ +private: + // Inner class representing a block (a set of Ts all allocateda at once) + template class MemoryBlock : Uncopyable + { + public: + // Constructor, creates a new MemoryBlock + MemoryBlock(int size) : _data(size), _nextBlock(0) { } + + Array _data; // The actual T data + MemoryBlock* _nextBlock; // Pointer to the next MemoryBlock in the list + }; + + // Deletes the rest of the MemoryBlock list for destruction or reset + void release() + { + MemoryBlock* block = _firstBlock._nextBlock; + while (block != 0) { + MemoryBlock* next = block->_nextBlock; + delete block; + block = next; + } + _firstBlock._nextBlock = 0; + } + +public: + // Constructor. Initializes the parameters and the initial MemoryBlock + MemoryPool(int blockSize = 1024) + : _firstBlock(blockSize), + _blockSize(blockSize) + { reset(); } + + // Gets a new unit of Ts, allocating a new MemoryBlock if necessary + T* get() + { + T* unit = &*_end; + + // Here we are effectively incrementing the iterator _end but we can't + // just do ++_end because we might need to create a new block, for + // which we will need _blockSize, which is inaccessible to the iterator + ++_end._object; + if (_end._object == _end._block->_data.end()) { + _end._block->_nextBlock = new MemoryBlock(_blockSize); + _end._block = _end._block->_nextBlock; + _end._object = _end._block->_data.begin(); + } + return unit; + } + + void reset() { release(); _end = begin(); } + + class Iterator + { + public: + Iterator() { } + Iterator(typename Array::Iterator object, MemoryBlock* block) + : _object(object), + _block(block) + { } + + // Pointer to object within MemoryBlock + typename Array::Iterator _object; + + // Pointer to MemoryBlock + MemoryBlock* _block; + + Iterator& operator++() // preincrement + { + ++_object; + if (_object == _block->_data.end()) { + _block = _block->_nextBlock; + _object = _block->_data.begin(); + } + return *this; + } + Iterator& operator++(int) // postincrement + { + Iterator i = *this; ++*this; return t; + } + bool operator==(const Iterator& x) { return x._block==_block && x._object==_object; } + bool operator!=(const Iterator& x) { return !((*this)==x); } + T& operator*() const { return *_object; } + T* operator->() const { return &**this; } + }; + + Iterator begin() { return Iterator(_firstBlock._data.begin(), &_firstBlock); } + Iterator end() { return _end; } + + ~MemoryPool() { release(); } + +private: + MemoryBlock _firstBlock; // First MemoryBlock in pool (always exists) + int _blockSize; // Number of Ts per MemoryBlock + Iterator _end; // Next unit that will be returned +}; + + +template class Pool : Uncopyable +{ +public: + Pool() : _p(0) { } + ~Pool() { deleteReserve(); _active.release(); } + void create(P* p) { _p = p; } + T* aquire() + { + T* t = _reserve.next(); + if (t == 0) + t = _p->create(); + else + t->remove(); + _active.add(t); + return t; + } + void release(T* t) { t->remove(); _reserve.add(t); } + void deleteReserve() { _reserve.release(); } +private: + P* _p; + LinkedList _reserve; + LinkedList _active; + int _activeCount; +}; + +#endif // INCLUDED_POOL_H diff --git a/80386/disassembler/include/alfe/power.h b/80386/disassembler/include/alfe/power.h new file mode 100644 index 0000000..af23b49 --- /dev/null +++ b/80386/disassembler/include/alfe/power.h @@ -0,0 +1,23 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_POWER_H +#define INCLUDED_POWER_H + +// Computes a^b +template T power(T a, int b) +{ + T r = 1; + if (b < 0) { + a = 1/a; + b = -b; + } + while (b > 0) { + if ((b & 1) != 0) + r = r*a; + a *= a; + b >>= 1; + } + return r; +} + +#endif // INCLUDED_POWER_H diff --git a/80386/disassembler/include/alfe/random.h b/80386/disassembler/include/alfe/random.h new file mode 100644 index 0000000..2c856c4 --- /dev/null +++ b/80386/disassembler/include/alfe/random.h @@ -0,0 +1,20 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_RANDOM_H +#define INCLUDED_RANDOM_H + +UInt32 random32() +{ + static UInt32 r = 0; + r = r*1103515245 + 12345; + return r; +} + +UInt32 random(UInt32 n) { return random32() % n; } + +UInt64 random64(UInt64 n) +{ + return ((static_cast(random32()) << 32) + random32()) % n; +} + +#endif // INCLUDED_RANDOM_H diff --git a/80386/disassembler/include/alfe/rational.h b/80386/disassembler/include/alfe/rational.h new file mode 100644 index 0000000..8a9ebde --- /dev/null +++ b/80386/disassembler/include/alfe/rational.h @@ -0,0 +1,199 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_RATIONAL_H +#define INCLUDED_RATIONAL_H + +#include "alfe/gcd.h" + +class ZeroDivideException : public Exception +{ +public: + ZeroDivideException() : Exception("Division by zero") { } +}; + +template class RationalTemplate +{ +public: + RationalTemplate(const T& n, const T& d) : numerator(n), denominator(d) + { + normalize(); + } + RationalTemplate(const T& n) : numerator(n), denominator(1) { } + RationalTemplate() { } + RationalTemplate& operator=(const RationalTemplate& r) + { + numerator = r.numerator; denominator = r.denominator; + return *this; + } + RationalTemplate& operator=(const T& n) { numerator = n; denominator = 1; } + RationalTemplate operator*(const RationalTemplate& other) const + { + RationalTemplate r = *this; + r *= other; + return r; + } + RationalTemplate operator/(const RationalTemplate& other) const + { + RationalTemplate r = *this; + r /= other; + return r; + } + RationalTemplate operator+(const RationalTemplate& other) const + { + RationalTemplate r = *this; + r += other; + return r; + } + RationalTemplate operator-(const RationalTemplate& other) const + { + RationalTemplate r = *this; + r -= other; + return r; + } + RationalTemplate operator-() const + { + return RationalTemplate(-numerator, denominator); + } + RationalTemplate& operator+=(const RationalTemplate& other) + { + T n = other.numerator; + T d = other.denominator; + T g = gcd(denominator, d); + denominator /= g; + numerator = numerator*(d/g) + n*denominator; + g = gcd(numerator, g); + numerator /= g; + denominator *= (d/g); + return *this; + } + RationalTemplate& operator-=(const RationalTemplate& other) + { + *this += (-other); + return *this; + } + RationalTemplate& operator*=(const RationalTemplate& other) + { + T n = other.numerator; + T d = other.denominator; + T a = gcd(numerator, d); + T b = gcd(n, denominator); + numerator = (numerator/a)*(n/b); + denominator = (denominator/b)*(d/a); + return *this; + } + RationalTemplate& operator/=(const RationalTemplate& other) + { + T n = other.numerator; + T d = other.denominator; + if (n == 0) + throw ZeroDivideException(); + if (numerator == 0) + return *this; + T a = gcd(numerator, n); + T b = gcd(denominator, d); + numerator = (numerator/a)*(d/b); + denominator = (denominator/b)*(n/a); + normalizeSign(); + return *this; + } + bool operator<(const RationalTemplate& other) const + { + return ((*this) - other).numerator < 0; + } + bool operator>(const RationalTemplate& other) const + { + return other < (*this); + } + bool operator<=(const RationalTemplate& other) const + { + return !((*this) > other); + } + bool operator>=(const RationalTemplate& other) const + { + return !((*this) < other); + } + bool operator==(const RationalTemplate& other) const + { + return numerator == other.numerator && + denominator == other.denominator; + } + bool operator!=(const RationalTemplate& other) const + { + return !operator==(other); + } + template U value() const + { + return static_cast(numerator)/static_cast(denominator); + } + T floor() const { return numerator/denominator; } + T ceiling() const { return (numerator + denominator - 1)/denominator; } + UInt32 hash() const + { + return Hash(typeid(RationalTemplate)).mixin(numerator). + mixin(denominator); + } + RationalTemplate frac() const + { + return RationalTemplate(numerator%denominator, denominator); + } + + T numerator; + T denominator; +private: + void normalize() + { + if (denominator == 0) + throw ZeroDivideException(); + if (numerator == 0) { + denominator = 1; + return; + } + T g = gcd(numerator, denominator); + numerator /= g; + denominator /= g; + normalizeSign(); + } + void normalizeSign() + { + if (denominator < 0) { + numerator = -numerator; + denominator = -denominator; + } + } +}; + +template RationalTemplate + lcm(const RationalTemplate& x, const RationalTemplate& y) +{ + return RationalTemplate( + lcm(x.numerator, y.numerator)*lcm(x.denominator, y.denominator), + x.denominator*y.denominator); +} + +template RationalTemplate operator*(const T& x, + const RationalTemplate& y) +{ + return y*x; +} + +template RationalTemplate operator/(const T& x, + const RationalTemplate& y) +{ + return RationalTemplate(x)/y; +} + +template RationalTemplate operator+(const T& x, + const RationalTemplate& y) +{ + return y+x; +} + +template RationalTemplate operator-(const T& x, + const RationalTemplate& y) +{ + return x+(-y); +} + +typedef RationalTemplate Rational; + +#endif // INCLUDED_RATIONAL_H diff --git a/80386/disassembler/include/alfe/rational_functions.h b/80386/disassembler/include/alfe/rational_functions.h new file mode 100644 index 0000000..0d6d3a0 --- /dev/null +++ b/80386/disassembler/include/alfe/rational_functions.h @@ -0,0 +1,423 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_RATIONAL_FUNCTIONS_H +#define INCLUDED_RATIONAL_FUNCTIONS_H + +#include "alfe/function.h" +#include "alfe/rational.h" +#include "alfe/power.h" + +class AddRationalRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l + i->value()); + } + Identifier identifier() const { return OperatorPlus(); } + FunctionType type() const + { + return + FunctionType(RationalType(), RationalType(), RationalType()); + } + }; +}; + +class AddRationalInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l + i->value()); + } + Identifier identifier() const { return OperatorPlus(); } + FunctionType type() const + { + return FunctionType(RationalType(), RationalType(), IntegerType()); + } + }; +}; + +class AddIntegerRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l + i->value()); + } + Identifier identifier() const { return OperatorPlus(); } + FunctionType type() const + { + return FunctionType(RationalType(), IntegerType(), RationalType()); + } + }; +}; + +class SubtractRationalRational + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l - i->value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return + FunctionType(RationalType(), RationalType(), RationalType()); + } + }; +}; + +class SubtractRationalInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l - i->value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return FunctionType(RationalType(), RationalType(), IntegerType()); + } + }; +}; + +class SubtractIntegerRational + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l - i->value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return FunctionType(RationalType(), IntegerType(), RationalType()); + } + }; +}; + +class MultiplyRationalRational + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l * i->value()); + } + Identifier identifier() const { return OperatorStar(); } + FunctionType type() const + { + return + FunctionType(RationalType(), RationalType(), RationalType()); + } + }; +}; + +class MultiplyRationalInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l * i->value()); + } + Identifier identifier() const { return OperatorStar(); } + FunctionType type() const + { + return FunctionType(RationalType(), RationalType(), IntegerType()); + } + }; +}; + +class MultiplyIntegerRational + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l * i->value()); + } + Identifier identifier() const { return OperatorStar(); } + FunctionType type() const + { + return FunctionType(RationalType(), IntegerType(), RationalType()); + } + }; +}; + +class DivideRationalRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l / i->value()); + } + Identifier identifier() const { return OperatorDivide(); } + FunctionType type() const + { + return + FunctionType(RationalType(), RationalType(), RationalType()); + } + }; +}; + +class DivideRationalInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + return Value(l / i->value()); + } + Identifier identifier() const { return OperatorDivide(); } + FunctionType type() const + { + return FunctionType(RationalType(), RationalType(), IntegerType()); + } + }; +}; + +class DivideIntegerRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l / i->value()); + } + Identifier identifier() const { return OperatorDivide(); } + FunctionType type() const + { + return FunctionType(RationalType(), IntegerType(), RationalType()); + } + }; +}; + +class DivideIntegerInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(Rational(l, i->value())); + } + Identifier identifier() const { return OperatorDivide(); } + FunctionType type() const + { + return FunctionType(RationalType(), IntegerType(), IntegerType()); + } + }; +}; + +class ShiftLeftRationalInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + auto l = i->value(); + ++i; + int r = i->value(); + if (r < 0) + return Rational(l.numerator, l.denominator << -r); + return Rational(l.numerator << r, l.denominator); + } + Identifier identifier() const { return OperatorShiftLeft(); } + FunctionType type() const + { + return FunctionType(RationalType(), RationalType(), IntegerType()); + } + }; +}; + +class ShiftRightRationalInteger + : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + auto l = i->value(); + ++i; + int r = i->value(); + if (r < 0) + return Rational(l.numerator << -r, l.denominator); + return Rational(l.numerator, l.denominator << r); + } + Identifier identifier() const { return OperatorShiftRight(); } + FunctionType type() const + { + return FunctionType(RationalType(), RationalType(), IntegerType()); + } + }; +}; + +class PowerIntegerInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + int r = i->value(); + return power(Rational(l), r); + } + Identifier identifier() const { return OperatorPower(); } + FunctionType type() const + { + return FunctionType(RationalType(), IntegerType(), IntegerType()); + } + }; +}; + +class PowerRationalInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + Rational l = i->value(); + ++i; + int r = i->value(); + return power(l, r); + } + Identifier identifier() const { return OperatorPower(); } + FunctionType type() const + { + return FunctionType(RationalType(), RationalType(), IntegerType()); + } + }; +}; + +class NegativeRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + return Value( - arguments.begin()->value()); + } + Identifier identifier() const { return OperatorMinus(); } + FunctionType type() const + { + return FunctionType(RationalType(), RationalType()); + } + }; +}; + +class FloorRational : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + return Value(arguments.begin()->value().floor()); + } + Identifier identifier() const { return "floor"; } + FunctionType type() const + { + return FunctionType(IntegerType(), RationalType()); + } + }; +}; + +#endif // INCLUDED_RATIONAL_FUNCTIONS_H diff --git a/80386/disassembler/include/alfe/rdif.h b/80386/disassembler/include/alfe/rdif.h new file mode 100644 index 0000000..07e0db8 --- /dev/null +++ b/80386/disassembler/include/alfe/rdif.h @@ -0,0 +1,287 @@ +#include "alfe/main.h" +#include "zlib/zlib.h" + +#ifndef INCLUDED_RDIF_H +#define INCLUDED_RDIF_H + +class DiskImage +{ +public: + DiskImage() : _version(0) { } + ~DiskImage() { _blocks.release(); } + void clear() + { + _blocks.release(); + _isRaw = false; + _version = 0; + _compressed = false; + _creator = ""; + _label = ""; + _description = ""; + _medium = miniFloppy; + _tracksPerInch = 48; + _writeEnable = true; + _rotationsPerMinute = 300; + _bitsPerSecond = 250000; + _encoding = modifiedFrequencyModulation; + _heads = 2; + _defaultBytesPerSector = 512; + _defaultSectorsPerTrack = 9; + _blockCount = 0; + } + void load(String data) + { + _blocks.release(); + int l = data.length(); + create(l); + int magic = readInt(data, 0); + if (magic != 0x46494452) + _isRaw = true; + if (_isRaw) { + Block* block = new Block; + _blocks.add(block); + block->_size = l; + block->_cylinder = 0; + block->_head = 0; + block->_position = 0; + block->_dataRate = _bitsPerSecond * 60 / _rotationsPerMinute; + block->_type = Block::justData; + block->_trackWidth = 0x100; + block->_initialFlux = 0x40; + block->_compressed = false; + block->_data.allocate(l); + for (int i = 0; i < l; ++i) + block->_data[i] = data[i]; + return; + } + _version = readInt(data, 4); + if (_version != 0) + throw Exception("Unknown RDIF version"); + _compressed = (readInt(data, 8) != 0); + _creator = data.subString(readInt(data, 12), readInt(data, 16)); + _label = data.subString(readInt(data, 20), readInt(data, 24)); + _description = data.subString(readInt(data, 28), readInt(data, 32)); + switch (readInt(data, 36)) { + case 0: _medium = eightInch; break; + case 1: _medium = miniFloppy; break; + case 2: _medium = microFloppy; break; + default: + throw Exception("Unknown media type"); + } + _tracksPerInch = readInt(data, 40); + _writeEnable = (readInt(data, 44) != 0); + _rotationsPerMinute = readInt(data, 48); + _bitsPerSecond = readInt(data, 52); + switch (readInt(data, 56)) { + case 0: _encoding = frequencyModulation; break; + case 1: _encoding = modifiedFrequencyModulation; break; + default: + throw Exception("Unknown encoding type"); + } + _heads = readInt(data, 60); + _defaultBytesPerSector = readInt(data, 64); + _defaultSectorsPerTrack = readInt(data, 68); + _blockCount = readInt(data, 72); + for (int i = 0; i < _blockCount; ++i) { + Block* block = new Block(data, i); + _blocks.add(block); + } + } + String save() + { + // TODO + } + void create(int length) + { + clear(); + switch (length) { + case 160*1024: + _isRaw = true; + _defaultSectorsPerTrack = 8; + _heads = 1; + break; + case 180*1024: + _isRaw = true; + _heads = 1; + break; + case 320*1024: + _isRaw = true; + _defaultSectorsPerTrack = 8; + break; + case 360*1024: + _isRaw = true; + break; + case 720*1024: + _isRaw = true; + _medium = microFloppy; + break; + case 1200*1024: + _isRaw = true; + _defaultSectorsPerTrack = 15; + _tracksPerInch = 96; + _rotationsPerMinute = 360; + _bitsPerSecond = 500000; + break; + case 1440*1024: + _isRaw = true; + _defaultSectorsPerTrack = 18; + _medium = microFloppy; + _bitsPerSecond = 500000; + break; + case 2880*1024: + _isRaw = true; + _defaultSectorsPerTrack = 36; + _medium = microFloppy; + _bitsPerSecond = 1000000; + break; + default: + _isRaw = false; + } + if (_medium == microFloppy) + _tracksPerInch = 135; + } + + // For XT Server. + void bios(Array* data, Byte* hostBytes) + { + if (hostBytes[19] != 0) + return; + Byte sectorCount = hostBytes[1]; + Byte operation = hostBytes[2]; + Byte sector = hostBytes[3] & 0x3f; + Word track = hostBytes[4] | ((hostBytes[3] & 0xc0) << 2); + Byte head = hostBytes[6]; + int sectorSize = 128 << hostBytes[10]; + Byte sectorsPerTrack = hostBytes[11]; + Byte gapLength = hostBytes[12]; + Byte dataLength = hostBytes[13]; + Byte formatGapLength = hostBytes[14]; + Byte formatFillByte = hostBytes[15]; + Block* block; + switch (operation) { + case 2: + // Read + { + block = _blocks.getNext(); + int offset = _defaultBytesPerSector*((track*_heads + head)*_defaultSectorsPerTrack + sector - 1); + int bytes = sectorSize * sectorCount; + if (offset < 0 || offset + bytes >= block->_size) { + hostBytes[18] = 0; + hostBytes[19] = 4; // Sector not found + return; + } + data->allocate(bytes); + memcpy(&(*data)[0], &block->_data[offset], bytes); + hostBytes[18] = sectorCount; + hostBytes[19] = 0; + hostBytes[20] = 2; + } + break; + case 3: + // Write + break; + case 4: + // Verify + break; + case 5: + // Format + break; + default: + hostBytes[19] = 1; + return; + } + } + +private: + static int readInt(String data, int p) + { + return static_cast(readSInt32(data, p)); + } + static SInt32 readSInt32(String data, int p) + { + return static_cast(readUInt32(data, p)); + } + static UInt32 readUInt32(String data, int p) + { + return readUInt16(data, p) | (readUInt16(data, p + 2) << 16); + } + static UInt16 readUInt16(String data, int p) + { + return readUInt8(data, p) | (readUInt8(data, p + 1) << 8); + } + static UInt16 readUInt8(String data, int p) + { + if (p >= data.length()) + return 0; + return data[p]; + } + //void findBlock(SInt32 track, int head) + //{ + // Block* b = _blocks.getNext(); + // Block* p = b; + // while (b != 0) { + // SInt32 start = b->_cylinder - (b->_trackWidth / 2); + // if (track >= start && track < start + b->_trackWidth && _he) + + // } + //} + class Block : public LinkedListMember + { + public: + Block() { } + Block(String data, int i) + { + int p = i*36 + 76; + _size = readInt(data, p + 4); + _data.allocate(_size); + int offset = readInt(data, p); + for (int j = 0; j < _size; ++j) + _data[j] = data[offset + j]; + _cylinder = readSInt32(data, p + 8); + _head = readInt(data, p + 12); + _position = readSInt32(data, p + 16); + _dataRate = readUInt32(data, p + 20); + switch (readInt(data, p + 24)) { + case 0: _type = justData; break; + case 1: _type = fluxReversals; break; + case 2: _type = rawFlux; break; + default: + throw Exception("Unknown RDIF data type"); + } + _trackWidth = readSInt32(data, p + 28); + _initialFlux = readSInt32(data, p + 32); + _compressed = (readSInt32(data, p + 36) != 0); + } + + int _size; + SInt32 _cylinder; + int _head; + SInt32 _position; + UInt32 _dataRate; + enum Type { justData, fluxReversals, rawFlux } _type; + SInt32 _trackWidth; + SInt32 _initialFlux; + bool _compressed; + Array _data; + }; + + bool _isRaw; + int _version; + bool _compressed; + String _creator; + String _label; + String _description; + enum Medium { eightInch, miniFloppy, microFloppy } _medium; + int _tracksPerInch; + bool _writeEnable; + int _rotationsPerMinute; // Nominal (0 = variable; CLV or zone bit recording) + int _bitsPerSecond; + enum Encoding { frequencyModulation, modifiedFrequencyModulation } _encoding; + int _heads; + int _defaultBytesPerSector; + int _defaultSectorsPerTrack; + LinkedList _blocks; + int _blockCount; +}; + +#endif // INCLUDED_RDIF_H diff --git a/80386/disassembler/include/alfe/rdif.txt b/80386/disassembler/include/alfe/rdif.txt new file mode 100644 index 0000000..afb5706 --- /dev/null +++ b/80386/disassembler/include/alfe/rdif.txt @@ -0,0 +1,93 @@ +Reenigne Disk Image Format: + +Goals: +* preservation/archiving - ability to accurately represent any physical floppy disk as it would appear to the drive. +* emulation - ability to modify the image as the emulator formats and writes, accurate timing for when the DMAs occur +* interoperability with raw data image formats + * if a raw image format is used and is rewritten but not formatted, it will be persisted in raw data image format. + + +File format description: + +If a file is 160KB, 180KB, 320KB, 360KB, 720KB, 1440KB or 2880KB, just interpret it as raw data. If it's a structured file, make sure it is not one of these sizes by adding an extra padding byte if +necessary. + +Otherwise, the structured file format is as follows: + +Magic bytes: RDIF +Version word: Only 0 currently defined. +File compression word: 0 for uncompressed data follows, 1 for zlib compressed data follows +Creator string pointer word +Creator string length word +Label string pointer word +Label string length word +Description string pointer word +Description string length word +Medium word: 0 = 8" disk, 1 = 5.25" disk, 2 = 3.5" disk +Tracks per inch word: 48, 96, 100 +Write enable word +RPM word +Bit rate word +FM/MFM word +Default number of bytes per sector (for "just the data" type blocks) +Default number of sectors per track (for "just the data" type blocks) + +File base: this is offset 0 in the file +Number of entries in Block table word: N +Block table: N entries of: + Offset word: relative to file base + Size word: in bytes when uncompressed. Overlapping the index hole causes the next part to go onto the following track. + Cylinder word: 24.8 signed fixed point, relative to track 0 + Head word: Should be an integer + Track position word: .32 fixed point in revolutions, relative to index hole + Data rate word: 24.8 bits per revolution + Track width word: 24.8 bits, in tracks + Media amplification: 24.8 bits. Normally 0x1.00 (or 0x0.00 for a laser hole). Value read = value written * amplification. As this is a property of the medium, not the message, it cannot be changed by format/write, so any media amplification boundaries persist across writes. If amplification == 0x00 then rewriting doesn't work at all. + Type word: + 0 = just the data as 512 byte sectors (logical, not physical order) + 1 = data including gaps + 2 = FM/MFM flux-reversal data (two bits per one actual data bit) + 3 = raw flux measurement (4 bytes per one actual data bit) + Block compression word: same meaning as file compression word +Raw block data chunks follow + + +Explanation: + +A disk is an array of heads. + +Think of each head as a rectangle, with angular-position on the X axis and distance-from-hub on the Y axis. +Each block then represents a sub-rectangle of this, with 1-dimensional bitmap data. + A block may actually span multiple rectangles on multiple heads, but this is an optimization detail. + +In memory, a head is stored as a binary tree (alternating between dividing in the angular and track axes) + This makes it easy (O(log(N))) to find the "top-left" of a sub-block and therefore to find the data for a track + + +Implementation plan: + +Initially assume a single block of type 0 +Initially implement read only +Convert type 0 to type 1 +Implement read of type 1 +Implement write of type 1 +Implement format of type 1 +Convert type 1 back to type 0 if no data loss would be incurred (standard gaps) +Convert type 1 to type 2 +Implement read of type 2 +Implement write of type 2 +Implement format of type 2 +Convert type 2 back to type 1 if no data loss would be incurred (standard encoding) +Convert type 2 to type 3 +Implement read of type 3 +Implement write of type 3 +Implement format of type 3 +Convert type 3 back to type 2 if no data loss would be incurred (standard transitions) +Optimize as necessary + + +References: + +http://www.kryoflux.com/ +http://www.softpres.org/_media/files:ipfdoc102a.zip + diff --git a/80386/disassembler/include/alfe/reference.h b/80386/disassembler/include/alfe/reference.h new file mode 100644 index 0000000..95b42a4 --- /dev/null +++ b/80386/disassembler/include/alfe/reference.h @@ -0,0 +1,35 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_REFERENCE_H +#define INCLUDED_REFERENCE_H + +template class Reference : private Handle +{ +public: + Reference() { } + template static Reference create(Args&&... args) + { + Reference r(Handle::create>(std::forward(args)...)); + return r; + } + T* operator->() { return body()->t(); } + T& operator*() { return *body()->t(); } +private: + class BaseBody : public Handle::Body + { + public: + virtual T* t() = 0; + }; + template class Body : public BaseBody + { + public: + template Body(Args&&... args) + : _c(std::forward(args)...) { } + T* t() { return &_c; } + C _c; + }; + BaseBody* body() { return as(); } + Reference(const Handle& other) : Handle(other) { } +}; + +#endif // INCLUDED_REFERENCE_H diff --git a/80386/disassembler/include/alfe/resolver.h b/80386/disassembler/include/alfe/resolver.h new file mode 100644 index 0000000..bdefad9 --- /dev/null +++ b/80386/disassembler/include/alfe/resolver.h @@ -0,0 +1,785 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_RESOLVER_H +#define INCLUDED_RESOLVER_H + +#include "alfe/code.h" + +class Resolver : Uncopyable +{ +public: + void resolve(Code code) + { + + } +private: +}; + +template class FunctionDefinitionStatementT : public Statement +{ +public: + static FunctionDefinitionStatement parse(CharacterSource* source) + { + CharacterSource s = *source; + TycoSpecifier returnTypeSpecifier = TycoSpecifier::parse(&s); + if (!returnTypeSpecifier.valid()) + return FunctionDefinitionStatement(); + Identifier name = Identifier::parse(&s); + if (!name.valid()) + return FunctionDefinitionStatement(); + Span span; + if (!Space::parseCharacter(&s, '(')) + return FunctionDefinitionStatement(); + *source = s; + List> parameterList = + parseParameterList(source); + Space::assertCharacter(source, ')'); + Statement body = FromStatement::parse(source); + if (!body.valid()) + body = Statement::parseOrFail(source); + return create(returnTypeSpecifier, name, parameterList, body); + } +private: + static List> parseParameterList( + CharacterSource* source) + { + List> list; + VariableDefinitionT parameter = + VariableDefinitionT::parse(source); + if (!parameter.valid()) + return list; + list.add(parameter); + Span span; + while (Space::parseCharacter(source, ',', &span)) { + VariableDefinitionT parameter = + VariableDefinitionT::parse(source); + if (!parameter.valid()) + source->location().throwError("Expected parameter"); + list.add(parameter); + } + return list; + } + + FunctionDefinitionStatementT() { } + FunctionDefinitionStatementT(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const TycoSpecifier& returnTypeSpecifier, const Identifier& name, + const List>& parameterList, + const Statement& body) + : Statement::Body(returnTypeSpecifier.span() + body.span()), + _returnTypeSpecifier(returnTypeSpecifier), _name(name), + _parameterList(parameterList), _body(body) { } + TypeT type() const + { + FunctionType t(_returnTypeSpecifier); + for (auto p : _parameterList) + t.instantiate(p.type()); + return t; + } + void resolve(Scope* scope) + { + _returnTypeSpecifier.resolve(scope); + for (auto p : _parameterList) { + p.resolve(scope); + _scope.addObject(p.identifier(), p); + } + _scope.setParentScope(scope); + _body.resolve(&_scope); + } + private: + TycoSpecifier _returnTypeSpecifier; + Identifier _name; + List> _parameterList; + Statement _body; + Scope _scope; + }; +}; + +class StatementSequence : public ParseTreeObject +{ +public: + StatementSequence() { } + static StatementSequence parse(CharacterSource* source) + { + Span span; + List sequence; + do { + Statement statement = Statement::parse(source); + if (!statement.valid()) + break; + span += statement.span(); + sequence.add(statement); + } while (true); + return create(sequence, span); + } + void resolve(Scope* scope) { body()->resolve(scope); } + List::Iterator begin() { return body()->begin(); } + List::Iterator end() { return body()->end(); } +private: + StatementSequence(Handle other) : ParseTreeObject(other) { } + + class Body : public ParseTreeObject::Body + { + public: + Body(const List& sequence, const Span& span) + : ParseTreeObject::Body(span), _sequence(sequence) { } + void resolve(Scope* scope) + { + for (auto s : _sequence) + s.resolve(scope); + } + List::Iterator begin() { return _sequence.begin(); } + List::Iterator end() { return _sequence.end(); } + private: + List _sequence; + }; + + Body* body() { return as(); } +}; + +class CompoundStatement : public Statement +{ +public: + static CompoundStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseCharacter(source, '{', &span)) + return CompoundStatement(); + StatementSequence sequence = StatementSequence::parse(source); + Space::assertCharacter(source, '}', &span); + return create(sequence, span); + } +private: + CompoundStatement() { } + CompoundStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const StatementSequence& sequence, const Span& span) + : Statement::Body(span), _sequence(sequence) { } + void resolve(Scope* scope) { _sequence.resolve(scope); } + private: + StatementSequence _sequence; + }; +}; + +// TycoDefinitionStatement := TycoSignifier "=" TycoSpecifier ";" +class TycoDefinitionStatement : public Statement +{ +public: + static TycoDefinitionStatement parse(CharacterSource* source) + { + CharacterSource s = *source; + CharacterSource s2 = s; + TycoSignifier tycoSignifier = TycoSignifier::parse(&s); + if (!tycoSignifier.valid()) + return TycoDefinitionStatement(); + if (!Space::parseCharacter(&s, '=')) + return TycoDefinitionStatement(); + *source = s; + TycoSpecifier tycoSpecifier = TycoSpecifier::parse(source); + Span span; + Space::assertCharacter(source, ';', &span); + return create(tycoSignifier, tycoSpecifier, + tycoSignifier.span() + span); + } +private: + TycoDefinitionStatement() { } + TycoDefinitionStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const TycoSignifier& tycoSignifier, + const TycoSpecifier& tycoSpecifier, const Span& span) + : Statement::Body(span), _tycoSignifier(tycoSignifier), + _tycoSpecifier(tycoSpecifier) { } + void resolve(Scope* scope) + { + + } + private: + TycoSignifier _tycoSignifier; + TycoSpecifier _tycoSpecifier; + }; +}; + +class NothingStatement : public Statement +{ +public: + static NothingStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "nothing", &span)) + return NothingStatement(); + Space::assertCharacter(source, ';', &span); + return create(span); + } +private: + NothingStatement() { } + NothingStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Span& span) : Statement::Body(span) { } + void resolve(Scope* scope) { } + }; +}; + +class IncrementDecrementStatement : public Statement +{ +public: + static Statement parse(CharacterSource* source) + { + Span span; + Operator o = OperatorIncrement().parse(source, &span); + if (!o.valid()) + o = OperatorDecrement().parse(source, &span); + if (!o.valid()) + return Statement(); + Expression lValue = Expression::parse(source); + Span span2; + Space::assertCharacter(source, ';', &span2); + return ExpressionStatement(FunctionCallExpression::unary(o, span, + FunctionCallExpression::unary( + OperatorAmpersand(), Span(), lValue)), + span + span2); + } +}; + +// ConditionalStatement = (`if` | `unless`) ConditionedStatement +// ((`elseIf` | `elseUnless`) ConditionedStatement)* [`else` Statement]; +// ConditionedStatement = "(" Expression ")" Statement; +class ConditionalStatement : public Statement +{ +public: + static ConditionalStatement parse(CharacterSource* source) + { + Span span; + if (Space::parseKeyword(source, "if", &span)) + return parse2(source, span, false); + if (Space::parseKeyword(source, "unless", &span)) + return parse2(source, span, true); + return ConditionalStatement(); + } +private: + static ConditionalStatement parse2(CharacterSource* source, Span span, + bool unlessStatement) + { + Space::assertCharacter(source, '('); + Expression condition = Expression::parseOrFail(source); + Space::assertCharacter(source, ')'); + Statement statement = Statement::parseOrFail(source); + span += statement.span(); + Statement elseStatement; + if (Space::parseKeyword(source, "else")) { + elseStatement = Statement::parseOrFail(source); + span += elseStatement.span(); + } + else + if (Space::parseKeyword(source, "elseIf")) { + elseStatement = parse2(source, span, false); + span += elseStatement.span(); + } + else + if (Space::parseKeyword(source, "elseUnless")) { + elseStatement = parse2(source, span, true); + span += elseStatement.span(); + } + if (unlessStatement) + condition = !condition; + return create(condition, statement, elseStatement, span); + } + + ConditionalStatement() { } + ConditionalStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& condition, const Statement& trueStatement, + const Statement& falseStatement, const Span& span) + : Statement::Body(span), _condition(condition), + _trueStatement(trueStatement), _falseStatement(falseStatement) { } + void resolve(Scope* scope) + { + _condition.resolve(scope); + _trueStatement.resolve(scope); + _falseStatement.resolve(scope); + } + private: + Expression _condition; + Statement _trueStatement; + Statement _falseStatement; + }; +}; + +class SwitchStatement : public Statement +{ +public: + static SwitchStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "switch", &span)) + return SwitchStatement(); + Space::assertCharacter(source, '('); + Expression expression = Expression::parseOrFail(source); + Space::assertCharacter(source, ')'); + Space::assertCharacter(source, '{'); + Case defaultCase; + + CharacterSource s = *source; + List cases; + do { + Case c = Case::parse(source); + if (!c.valid()) + break; + if (c.isDefault()) { + if (defaultCase.valid()) + s.location().throwError( + "This switch statement already has a default case"); + defaultCase = c; + } + else + cases.add(c); + } while (true); + Space::assertCharacter(source, '}', &span); + return create(expression, defaultCase, cases, span); + } +private: + SwitchStatement() { } + SwitchStatement(Handle other) { } + + class Case : public ParseTreeObject + { + public: + static Case parse(CharacterSource* source) + { + List expressions; + bool defaultType; + Span span; + if (Space::parseKeyword(source, "case", &span)) { + defaultType = false; + do { + Expression expression = Expression::parseOrFail(source); + expressions.add(expression); + if (!Space::parseCharacter(source, ',')) + break; + } while (true); + } + else { + defaultType = true; + if (!Space::parseKeyword(source, "default", &span)) + source->location().throwError("Expected case or default"); + } + Space::assertCharacter(source, ':'); + Statement statement = Statement::parseOrFail(source); + span += statement.span(); + if (defaultType) + return create(statement, span); + return create(expressions, statement, span); + } + bool isDefault() const { return body()->isDefault(); } + void resolve(Scope* scope) { body()->resolve(scope); } + + Case() { } + + class Body : public ParseTreeObject::Body + { + public: + Body(const Statement& statement, const Span& span) + : ParseTreeObject::Body(span), _statement(statement) { } + virtual bool isDefault() const = 0; + virtual void resolve(Scope* scope) + { + _statement.resolve(scope); + } + private: + Statement _statement; + }; + private: + Case(Handle other) : ParseTreeObject(other) { } + + Body* body() { return as(); } + const Body* body() const { return as(); } + + class DefaultBody : public Body + { + public: + DefaultBody(const Statement& statement, const Span& span) + : Body(statement, span) { } + bool isDefault() const { return true; } + }; + class ValueBody : public Body + { + public: + ValueBody(const List& expressions, + const Statement& statement, const Span& span) + : Body(statement, span), _expressions(expressions) { } + bool isDefault() const { return false; } + void resolve(Scope* scope) + { + for (auto e : _expressions) + e.resolve(scope); + Body::resolve(scope); + } + private: + List _expressions; + }; + }; + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Case& defaultCase, + const List& cases, const Span& span) + : Statement::Body(span), _expression(expression), + _defaultCase(defaultCase), _cases(cases) { } + void resolve(Scope* scope) + { + _expression.resolve(scope); + _defaultCase.resolve(scope); + for (auto c : _cases) + c.resolve(scope); + } + private: + Expression _expression; + Case _defaultCase; + List _cases; + }; +}; + +class ReturnStatement : public Statement +{ +public: + static ReturnStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "return", &span)) + return ReturnStatement(); + Expression expression = Expression::parseOrFail(source); + Space::assertCharacter(source, ';', &span); + return create(expression, span); + } +private: + ReturnStatement() { } + ReturnStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + void resolve(Scope* scope) { _expression.resolve(scope); } + private: + Expression _expression; + }; +}; + +class IncludeStatement : public Statement +{ +public: + static IncludeStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "include", &span)) + return IncludeStatement(); + Expression expression = Expression::parseOrFail(source); + Space::assertCharacter(source, ';', &span); + return create(expression, span); + } +private: + IncludeStatement() { } + IncludeStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + void resolve(Scope* scope) { _expression.resolve(scope); } + private: + Expression _expression; + }; +}; + +template class BreakOrContinueStatementT; +typedef BreakOrContinueStatementT BreakOrContinueStatement; + +template class BreakOrContinueStatementT : public Statement +{ +public: + static BreakOrContinueStatement parse(CharacterSource* source) + { + BreakOrContinueStatement breakStatement = parseBreak(source); + if (breakStatement.valid()) + return breakStatement; + return parseContinue(source); + } +private: + BreakOrContinueStatementT() { } + BreakOrContinueStatementT(Handle other) : Statement(other) { } + + static BreakOrContinueStatement parseBreak(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "break", &span)) + return BreakOrContinueStatement(); + BreakOrContinueStatement statement = parse(source); + if (!statement.valid()) + Space::assertCharacter(source, ';', &span); + else + span += statement.span(); + return create(statement, span); + } + + static BreakOrContinueStatement parseContinue(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "continue", &span)) + return BreakOrContinueStatement(); + Space::assertCharacter(source, ';', &span); + return create(span); + } + + class Body : public Statement::Body + { + public: + Body(const Span& span) : Statement::Body(span) { } + void resolve(Scope* scope) { } + }; + + class BreakBody : public Body + { + public: + BreakBody(const BreakOrContinueStatement& statement, const Span& span) + : Body(span), _statement(statement) { } + private: + BreakOrContinueStatement _statement; + }; + + class ContinueBody : public Body + { + public: + ContinueBody(const Span& span) : Body(span) { } + }; +}; + +class ForeverStatement : public Statement +{ +public: + static ForeverStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "forever", &span)) + return ForeverStatement(); + Statement statement = Statement::parseOrFail(source); + return create(statement, span + statement.span()); + } +private: + ForeverStatement() { } + ForeverStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Statement& statement, const Span& span) + : Statement::Body(span), _statement(statement) { } + void resolve(Scope* scope) { _statement.resolve(scope); } + private: + Statement _statement; + }; +}; + +class WhileStatement : public Statement +{ +public: + static WhileStatement parse(CharacterSource* source) + { + Span span; + Statement doStatement; + bool foundDo = false; + if (Space::parseKeyword(source, "do", &span)) { + foundDo = true; + doStatement = Statement::parseOrFail(source); + } + bool foundWhile = false; + bool foundUntil = false; + if (Space::parseKeyword(source, "while", &span)) + foundWhile = true; + else + if (Space::parseKeyword(source, "until", &span)) + foundUntil = true; + if (!foundWhile && !foundUntil) { + if (foundDo) + source->location().throwError("Expected while or until"); + return WhileStatement(); + } + Space::assertCharacter(source, '('); + Expression condition = Expression::parse(source); + Space::assertCharacter(source, ')'); + Statement statement = Statement::parseOrFail(source); + span += statement.span(); + Statement doneStatement; + if (Space::parseKeyword(source, "done")) { + doneStatement = Statement::parseOrFail(source); + span += doneStatement.span(); + } + if (foundUntil) + condition = !condition; + return create(doStatement, condition, statement, + doneStatement, span); + } +private: + WhileStatement() { } + WhileStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Statement& doStatement, const Expression& condition, + const Statement& statement, const Statement& doneStatement, + const Span& span) + : Statement::Body(span), _doStatement(doStatement), + _condition(condition), _statement(statement), + _doneStatement(doneStatement) { } + void resolve(Scope* scope) + { + _doStatement.resolve(scope); + _condition.resolve(scope); + _statement.resolve(scope); + _doneStatement.resolve(scope); + } + private: + Statement _doStatement; + Expression _condition; + Statement _statement; + Statement _doneStatement; + }; +}; + +class ForStatement : public Statement +{ +public: + static ForStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "for", &span)) + return ForStatement(); + Space::assertCharacter(source, '('); + Statement preStatement = Statement::parse(source); + if (!preStatement.valid()) + Space::assertCharacter(source, ';'); + Expression expression = Expression::parse(source); + Space::assertCharacter(source, ';'); + Statement postStatement = Statement::parse(source); + Space::parseCharacter(source, ')'); + Statement statement = Statement::parseOrFail(source); + span += statement.span(); + Statement doneStatement; + if (Space::parseKeyword(source, "done")) { + doneStatement = Statement::parseOrFail(source); + span += doneStatement.span(); + } + return create(preStatement, expression, postStatement, + statement, doneStatement, span); + } +private: + ForStatement() { } + ForStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Statement& preStatement, const Expression& condition, + const Statement& postStatement, const Statement& statement, + const Statement& doneStatement, const Span& span) + : Statement::Body(span), _preStatement(preStatement), + _condition(condition), _postStatement(postStatement), + _statement(statement), _doneStatement(doneStatement) { } + void resolve(Scope* scope) + { + _preStatement.resolve(scope); + _condition.resolve(scope); + _postStatement.resolve(scope); + _statement.resolve(scope); + _doneStatement.resolve(scope); + } + private: + Statement _preStatement; + Expression _condition; + Statement _postStatement; + Statement _statement; + Statement _doneStatement; + }; +}; + +template class LabelStatementT; +typedef LabelStatementT LabelStatement; + +template class LabelStatementT : public Statement +{ +public: + static LabelStatement parse(CharacterSource* source) + { + CharacterSource s2 = *source; + Identifier identifier = Identifier::parse(&s2); + if (!identifier.valid()) + return LabelStatement(); + Span span; + if (!Space::parseCharacter(&s2, ':', &span)) + return LabelStatement(); + return create(identifier, identifier.span() + span); + } +private: + LabelStatementT() { } + LabelStatementT(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Identifier& identifier, const Span& span) + : Statement::Body(span), _identifier(identifier) { } + void resolve(Scope* scope) + { + + } + private: + IdentifierT _identifier; + }; +}; + +class GotoStatement : public Statement +{ +public: + static GotoStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "goto", &span)) + return GotoStatement(); + Expression expression = Expression::parseOrFail(source); + Span span2; + Space::parseCharacter(source, ';', &span); + return create(expression, span); + } +private: + GotoStatement() { } + GotoStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + void resolve(Scope* scope) { _expression.resolve(scope); } + private: + Expression _expression; + }; +}; + +#endif // INCLUDED_RESOLVER_H \ No newline at end of file diff --git a/80386/disassembler/include/alfe/rotors.h b/80386/disassembler/include/alfe/rotors.h new file mode 100644 index 0000000..b86addd --- /dev/null +++ b/80386/disassembler/include/alfe/rotors.h @@ -0,0 +1,176 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_ROTORS_H +#define INCLUDED_ROTORS_H + +#define _USE_MATH_DEFINES +#include + +template class Vector2; +template class Rotor2_static_cast; + +// A Rotor is a way of representing a rotation. It's faster than Euler angles +// (since the sines are cosines don't have to be computed each time the rotor +// is applied) but more memory efficient than a matrix (for dimensions <7). + +// A Rotor can be thought of as the exponential of a bivector. The plane +// described by the bivector is the plane left invariant by the rotation. The +// magnitude of the bivector is half the rotation angle. + +// 2D Rotors are isomorphic to unit complex numbers, and +// 3D Rotors are isomorphic to unit quaternions. + +// Rotors R and -R have the same meaning geometrically, so they form a +// double-cover. + +template class Rotor2 +{ +public: + Rotor2() : _c(1), _s(0) { } + Rotor2(T a) + { + _c = cos(a/2); + _s = sin(a/2); + } + // Construct a rotor that rotates a onto b + Rotor2(Vector2& a, Vector2& b) + { + T m = sqrt(a.modulus2()*b.modulus2()); + _c = dot(a, b)/m; + _s = cross(b, a)/m; + } + Rotor2(const Rotor2& other) : _c(other._c), _s(other._s) { } + template Rotor2(const Rotor2& other) + : _c(other._c), _s(other._s) { } + const Rotor2& operator=(const Rotor2& other) + { + _c = other._c; + _s = other._s; + return *this; + } + const Rotor2& operator*=(const Rotor2& other) + { + *this = *this * other; + return *this; + } + const Rotor2& operator/=(const Rotor2& other) + { + *this = *this / other; + return *this; + } + Rotor2 operator*(const Rotor2& other) const + { + return Rotor2(_c*other._c-_s*other._s, _s*other._c+_c*other._s); + } + Rotor2 operator/(const Rotor2& other) const + { + return *this * other.conjugate(); + } + void toMatrix(T* matrix) const + { + matrix[0] = 1 - 2*(_s*_s); + matrix[1] = 2*(_s*_c); + matrix[2] = - 2*(_s*_c); + matrix[3] = 1 - 2*(_s*_s); + } + + // The conjugate rotor rotates in the opposite direction + Rotor2 conjugate() const { return Rotor2(_c, -_s); } +private: + Rotor2(const T& c, const T& s) : _c(c), _s(s) { } + T _c; + T _s; + + template friend class Vector2; + template friend class Rotor2_static_cast; +}; + +template class Rotor2_static_cast : public Rotor2 +{ +public: + template Rotor2_static_cast(const Rotor2& other) + : Rotor2(static_cast(other._c), static_cast(other._s)) { } +}; + +template class Vector3; +template class Rotor3_static_cast; + +template class Rotor3 +{ +public: + Rotor3() : _sc(1), _yz(0), _zx(0), _xy(0) { } + static Rotor3 yz(T a) { return Rotor3(cos(a/2), sin(a/2), 0, 0); } + static Rotor3 zx(T a) { return Rotor3(cos(a/2), 0, sin(a/2), 0); } + static Rotor3 xy(T a) { return Rotor3(cos(a/2), 0, 0, sin(a/2)); } + + // // Construct a rotor that rotates a onto b + //Rotor3(Vector3& a, Vector3& b) + //{ + // T m = sqrt(a.modulus2()*b.modulus2()); + // _c = (b.x*a.x + b.y*a.y)/m; + // _s = (b.x*a.y - b.y*a.x)/m; + //} + Rotor3(const Rotor3& other) + : _sc(other._sc), _yz(other._yz), _zx(other._zx), _xy(other._xy) { } + template Rotor3(const Rotor3& other) + : _sc(other._sc), _yz(other._yz), _zx(other._zx), _xy(other._xy) { } + const Rotor3& operator=(const Rotor3& other) + { + _sc = other._sc; + _yz = other._yz; + _zx = other._zx; + _xy = other._xy; + return *this; + } + const Rotor3& operator*=(const Rotor3& other) + { + *this = *this * other; + return *this; + } + const Rotor3& operator/=(const Rotor3& other) + { + *this = *this / other; + return *this; + } + Rotor3 operator*(const Rotor3& other) const + { + return Rotor3( + _sc*other._sc - _yz*other._yz - _zx*other._zx - _xy*other._xy, + _sc*other._yz + _yz*other._sc - _zx*other._xy + _xy*other._zx, + _sc*other._zx + _yz*other._xy + _zx*other._sc - _xy*other._yz, + _sc*other._xy - _yz*other._zx + _zx*other._yz + _xy*other._sc); + } + Rotor3 operator/(const Rotor3& other) const + { + return *this * other.conjugate(); + } + + // The conjugate rotor rotates in the opposite direction. + Rotor3 conjugate() const { return Rotor3(_sc, -_yz, -zx, -xy); } + + void toMatrix(T* matrix) const + { + matrix[0] = 1 - 2*(_zx*_zx + _xy*_xy); + matrix[1] = 2*(_xy*_sc + _zx*_yz); + matrix[2] = 2*(_xy*_yz - _zx*_sc); + matrix[3] = 2*(_zx*_yz - _xy*_sc); + matrix[4] = 1 - 2*(_yz*_yz + _xy*_xy); + matrix[5] = 2*(_yz*_sc + _xy*_zx); + matrix[6] = 2*(_zx*_sc + _xy*_yz); + matrix[7] = 2*(_xy*_zx - _yz*_sc); + matrix[8] = 1 - 2*(_yz*_yz + _zx*_zx); + } +private: + Rotor3(const T& sc, const T& yz, const T& zx, const T& xy) + : _sc(sc), _yz(yz), _zx(zx), _xy(xy) { } + + T _sc; + T _yz; + T _zx; + T _xy; + + template friend class Vector3; + template friend class Rotor3_static_cast; +}; + +#endif // INCLUDED_ROTORS_H diff --git a/80386/disassembler/include/alfe/scanlines.h b/80386/disassembler/include/alfe/scanlines.h new file mode 100644 index 0000000..903cdcb --- /dev/null +++ b/80386/disassembler/include/alfe/scanlines.h @@ -0,0 +1,452 @@ +#include "alfe/main.h" +#include "alfe/bitmap.h" +#include "alfe/complex.h" +#include "alfe/fft.h" + +#ifndef INCLUDED_SCANLINES_H +#define INCLUDED_SCANLINES_H + +#include "alfe/image_filter.h" +#include + +class ScanlineRenderer +{ +public: + ScanlineRenderer() + : _profile(4), _horizontalProfile(4), _width(1), _bleeding(2), + _horizontalBleeding(2), _horizontalRollOff(0), _verticalRollOff(0), + _subPixelSeparation(0), _phosphor(0), _mask(0), _maskSize(0), + _needsInit(true) + { } + void init() + { + if (!_needsInit) + return; + _needsInit = false; + _output.ensure(_size.x*3*sizeof(float), _size.y); + + _vertical.generate(_size, 3, + kernelRadius(_profile, _zoom.y, _width, _verticalRollOff, + _verticalLobes), + kernel(_profile, _zoom.y, _width, _verticalRollOff, + _verticalLobes), + &_inputTL.y, &_inputBR.y, _zoom.y, _offset.y); + + int inputHeight = _inputBR.y - _inputTL.y; + _intermediate.ensure(_size.x*3*sizeof(float), inputHeight); + + _vertical.setBuffers(_intermediate, _output); + + static const float inputChannelPositions[3] = {0, 0, 0}; + float outputChannelPositions[3] = + {-_subPixelSeparation/3, 0, _subPixelSeparation/3}; + + auto channelKernel = kernel(_horizontalProfile, _zoom.x, 1, + _horizontalRollOff, _horizontalLobes); + _horizontal.generate(Vector(_size.x, inputHeight), 3, + inputChannelPositions, 3, outputChannelPositions, + kernelRadius(_horizontalProfile, _zoom.x, 1, _horizontalRollOff, + _horizontalLobes), + [=](float distance, int inputChannel, int outputChannel) + { + if ((inputChannel - outputChannel) % 3 != 0) + return Tuple(0.0f, 0.0f); + return channelKernel(distance); + }, + &_inputTL.x, &_inputBR.x, _zoom.x, _offset.x); + + _input.ensure((_inputBR.x - _inputTL.x)*3*sizeof(float), inputHeight); + + _horizontal.setBuffers(_input, _intermediate); + } + void render() + { + _horizontal.execute(); + Byte* d = _intermediate.data(); + for (int y = 0; y < _inputBR.y - _inputTL.y; ++y) { + bleed(d, 12, Vector(3, _size.x), _horizontalBleeding); + d += _intermediate.stride(); + } + _vertical.execute(); + bleed(_output.data(), _output.stride(), _size*Vector(3, 1), _bleeding); + } + int getProfile() { return _profile; } + void setProfile(int profile) + { + if (_profile != profile) + _needsInit = true; + _profile = profile; + } + float getWidth() { return _width; } + void setWidth(float width) + { + if (_width != width) + _needsInit = true; + _width = width; + } + int getBleeding() { return _bleeding; } + void setBleeding(int bleeding) { _bleeding = bleeding; } + int getHorizontalProfile() { return _horizontalProfile; } + void setHorizontalProfile(int profile) { _horizontalProfile = profile; } + int getHorizontalBleeding() { return _horizontalBleeding; } + void setHorizontalBleeding(int bleeding) + { + _horizontalBleeding = bleeding; + } + float getVerticalRollOff() { return _verticalRollOff; } + void setVerticalRollOff(float rollOff) + { + if (_verticalRollOff != rollOff) + _needsInit = true; + _verticalRollOff = rollOff; + } + float getHorizontalRollOff() { return _horizontalRollOff; } + void setHorizontalRollOff(float rollOff) + { + if (_horizontalRollOff != rollOff) + _needsInit = true; + _horizontalRollOff = rollOff; + } + float getVerticalLobes() { return _verticalLobes; } + void setVerticalLobes(float lobes) + { + if (_verticalLobes != lobes) + _needsInit = true; + _verticalLobes = lobes; + } + float getHorizontalLobes() { return _horizontalLobes; } + void setHorizontalLobes(float lobes) + { + if (_horizontalLobes != lobes) + _needsInit = true; + _horizontalLobes = lobes; + } + float getSubPixelSeparation() { return _subPixelSeparation; } + void setSubPixelSeparation(float separation) + { + if (_subPixelSeparation != separation) + _needsInit = true; + _subPixelSeparation = separation; + } + int getPhosphor() { return _phosphor; } + void setPhosphor(int phosphor) + { + if (_phosphor != phosphor) + _needsInit = true; + _phosphor = phosphor; + } + int getMask() { return _mask; } + void setMask(int mask) + { + if (_mask != mask) + _needsInit = true; + _mask = mask; + } + float getMaskSize() { return _maskSize; } + void setMaskSize(float maskSize) + { + if (_maskSize != maskSize) + _needsInit = true; + _maskSize = maskSize; + } + void setZoom(Vector2 zoom) + { + if (_zoom != zoom) + _needsInit = true; + _zoom = zoom; + } + void setOffset(Vector2 offset) + { + if (_offset != offset) + _needsInit = true; + _offset = offset; + } + void setOutputSize(Vector size) + { + if (_size != size) + _needsInit = true; + _size = size; + } + Vector inputTL() { return _inputTL; } + Vector inputBR() { return _inputBR; } + AlignedBuffer input() { return _input; } + AlignedBuffer output() { return _output; } + +private: + std::function(float)> kernel(int profile, float zoom, + float width, float rollOff, float cutOff) + { + switch (profile) { + case 0: + // Rectangle + { + float b = 0.5f*zoom*static_cast(tau)*width/2.0f; + float c = 0.5f*zoom*static_cast(tau); + return [=](float d) + { + float r = (sinint(b + c*d) + sinint(b - c*d))* + sinc(d*rollOff); + return Tuple(r, r); + }; + } + break; + case 1: + // Triangle + return [=](float distance) + { + float b = 0.5f*zoom; + float w = 0.5f*width; + float f = distance; + float t = static_cast(tau); + float r = sinc(distance*rollOff)*( + +2*t*(f-w)*b*sinint(t*(f-w)*b) + +2*t*(f+w)*b*sinint(t*(f+w)*b) + -4*t*f*b*sinint(t*f*b) + +2*cos(b*t*(f-w)) + +2*cos(b*t*(f+w)) + -4*cos(b*t*f)); + return Tuple(r, r); + }; + break; + case 2: + // Circle + { + float b = 4.0f/(width*width); + float c = width/2.0f; + return [=](float distance) + { + float r = 0.0f; + if (distance > -c && distance < c) { + r = sqrt(1 - b*distance*distance)* + sinc(distance*rollOff); + } + return Tuple(r, r); + }; + } + break; + case 3: + // Gaussian + { + float a = -8/(width*width); + return [=](float distance) + { + float r = exp(a*distance*distance)* + sinc(distance*rollOff); + return Tuple(r, r); + }; + } + break; + case 4: + // Sinc + { + float bandLimit = min(1.0f, zoom)/width; + if (width == 0) + bandLimit = 10000; + return [=](float distance) + { + float r = sinc(distance*bandLimit)* + sinc(distance*rollOff); + return Tuple(r, r); + }; + } + break; + default: + // Box + { + return [=](float distance) + { + float r = sinc(distance*rollOff); + return Tuple(r, r); + }; + } + break; + } + } + float kernelRadius(int profile, float zoom, float width, float rollOff, + float lobes) + { + switch (profile) { + case 2: + // Circle + return width/2.0f; + case 3: + // Gaussian + return lobes; + case 4: + // Sinc + return lobes*width/min(1.0f, zoom); + case 5: + // Box + return 0.5f; + } + return lobes/min(1.0f, zoom); + } + void bleed(Byte* data, int s, Vector size, int bleeding) + { + if (bleeding == 1) { + Byte* outputColumn = data; + for (int x = 0; x < size.x; ++x) { + Byte* output = outputColumn; + float bleed = 0; + for (int y = 0; y < size.y; ++y) { + float o = bleed + *reinterpret_cast(output); + bleed = 0; + if (o < 0) { + bleed = o; + o = 0; + } + if (o > 1) { + bleed = o - 1; + o = 1; + } + *reinterpret_cast(output) = o; + output += s; + } + outputColumn += sizeof(float); + } + return; + } + if (bleeding == 2) { + Byte* outputColumn = data; + for (int x = 0; x < size.x; ++x) { + Byte* output = outputColumn; + float bleed = 0; + for (int y = 0; y < size.y; ++y) { + float o = *reinterpret_cast(output); + if (o < 0) { + Byte* output1 = output + s; + int y1; + float t = -o; + *reinterpret_cast(output) = 0; + for (y1 = y + 1; y1 < size.y; ++y1, output1 += s) { + float o1 = *reinterpret_cast(output1); + if (o1 > 0) + break; + t -= o1; + *reinterpret_cast(output1) = 0; + } + float bleed = t/2; + Byte* output2 = output - s; + for (int y2 = y - 1; y2 >= 0; --y2, output2 -= s) { + float* p = reinterpret_cast(output2); + float o2 = *p; + if (o2 > 0) { + if (bleed > o2) { + bleed -= o2; + *p = 0; + } + else { + *p = o2 - bleed; + break; + } + } + } + bleed = t/2; + output2 = output1; + for (int y2 = y1; y2 < size.y; ++y2, output2 += s) { + float* p = reinterpret_cast(output2); + float o2 = *p; + if (o2 > 0) { + if (bleed > o2) { + bleed -= o2; + *p = 0; + } + else { + *p = o2 - bleed; + break; + } + } + } + // We need to restart at y1 here rather than y2 because + // there might be some more <0 values between y1 and + // y2. + y = y1 - 1; + output = output1; + continue; + } + if (o > 1) { + Byte* output1 = output + s; + int y1; + float t = o - 1; + *reinterpret_cast(output) = 1; + for (y1 = y + 1; y1 < size.y; ++y1, output1 += s) { + float o1 = *reinterpret_cast(output1); + if (o1 < 1) + break; + t += o1 - 1; + *reinterpret_cast(output1) = 1; + } + float bleed = t/2; + Byte* output2 = output - s; + for (int y2 = y - 1; y2 >= 0; --y2, output2 -= s) { + float* p = reinterpret_cast(output2); + float o2 = *p; + if (o2 < 1) { + if (bleed + o2 > 1) { + bleed -= 1 - o2; + *p = 1; + } + else { + *p = o2 + bleed; + break; + } + } + } + bleed = t/2; + output2 = output1; + for (int y2 = y1; y2 < size.y; ++y2, output2 += s) { + float* p = reinterpret_cast(output2); + float o2 = *p; + if (o2 < 1) { + if (bleed + o2 > 1) { + bleed -= 1 - o2; + *p = 1; + } + else { + *p = o2 + bleed; + break; + } + } + } + // We need to restart at y1 here rather than y2 because + // there might be some more >1 values between y1 and + // y2. + y = y1 - 1; + output = output1; + continue; + } + output += s; + } + outputColumn += sizeof(float); + } + } + } + + int _profile; + int _horizontalProfile; + float _width; + int _bleeding; + int _horizontalBleeding; + float _horizontalRollOff; + float _verticalRollOff; + float _horizontalLobes; + float _verticalLobes; + float _subPixelSeparation; + int _phosphor; + int _mask; + float _maskSize; + Vector2 _offset; + Vector2 _zoom; + Vector _size; + AlignedBuffer _input; + AlignedBuffer _intermediate; + AlignedBuffer _output; + Vector _inputTL; + Vector _inputBR; + bool _needsInit; + + ImageFilterHorizontal _horizontal; + ImageFilterVertical _vertical; +}; + +#endif // INCLUDED_SCANLINES_H diff --git a/80386/disassembler/include/alfe/scratch.txt b/80386/disassembler/include/alfe/scratch.txt new file mode 100644 index 0000000..992a393 --- /dev/null +++ b/80386/disassembler/include/alfe/scratch.txt @@ -0,0 +1,10 @@ +String::subString() takes start and length, CharacterSource::subString() takes start and end. + +See http://docs.racket-lang.org/reference/windowspaths.html for details on paths starting with \\?\ + +If use \\?\ to avoid MAX_PATH limit, we need to know the current drive - this is the first character of CurrentDirectory().windowsPath() . + +When parsing paths, use getCodePoint() instead of get() so that Unix paths can contain 0x0a and 0x0d bytes. + +We should be using substitution into templates instead of concatenation for globalization purposes. + diff --git a/80386/disassembler/include/alfe/sdl2.h b/80386/disassembler/include/alfe/sdl2.h new file mode 100644 index 0000000..1adfef6 --- /dev/null +++ b/80386/disassembler/include/alfe/sdl2.h @@ -0,0 +1,102 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_SDL_H +#define INCLUDED_SDL_H + +#ifdef _WIN32 +#include "SDL.h" +#else +#include "SDL2/SDL.h" +#endif + +// This is the exception that we throw if any SDL methods fail. +class SDLException : public Exception +{ +public: + SDLException(String message) + : Exception(message + ": " + SDL_GetError()) { } +}; + +#define IF_ZERO_THROW_SDL(expr, msg) \ + IF_TRUE_THROW((expr) == 0, SDLException(msg)) +#define IF_NONZERO_THROW_SDL(expr, msg) \ + IF_TRUE_THROW((expr) != 0, SDLException(msg)) + +class SDL +{ +public: + SDL(UInt32 flags = 0) + { + IF_NONZERO_THROW_SDL(SDL_Init(flags), "Initializing SDL"); + } + ~SDL() { SDL_Quit(); } +}; + +class SDLWindow +{ +public: + SDLWindow() + { + _window = SDL_CreateWindow("CGA monitor", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 912, 525, 0); + IF_ZERO_THROW_SDL(_window, "Creating SDL window"); + } + ~SDLWindow() { SDL_DestroyWindow(_window); } + SDL_Window* _window; +}; + +template class SDLTextureT; +typedef SDLTextureT SDLTexture; + +template class SDLRendererT +{ +public: + SDLRendererT(SDLWindow* window) + { + _renderer = SDL_CreateRenderer(window->_window, -1, 0); + IF_ZERO_THROW_SDL(_renderer, "Creating SDL renderer"); + } + ~SDLRendererT() { SDL_DestroyRenderer(_renderer); } + void renderTexture(SDLTextureT* texture) + { + // IF_NONZERO_THROW_SDL(SDL_RenderClear(_renderer), "Clearing target"); + IF_NONZERO_THROW_SDL( + SDL_RenderCopy(_renderer, texture->_texture, NULL, NULL), + "Rendering texture"); + SDL_RenderPresent(_renderer); + } + SDL_Renderer* _renderer; +}; + +typedef SDLRendererT SDLRenderer; + +template class SDLTextureT +{ +public: + SDLTextureT(SDLRenderer* renderer) + { + _texture = SDL_CreateTexture(renderer->_renderer, + SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 912, 525); + IF_ZERO_THROW_SDL(_texture, "Creating SDL texture"); + } + ~SDLTextureT() { SDL_DestroyTexture(_texture); } + void unlock() { SDL_UnlockTexture(_texture); } + SDL_Texture* _texture; +}; + +class SDLTextureLock +{ +public: + SDLTextureLock(SDLTexture* texture) : _texture(texture) + { + IF_NONZERO_THROW_SDL( + SDL_LockTexture(_texture->_texture, NULL, &_pixels, &_pitch), + "Locking SDL texture"); + } + ~SDLTextureLock() { _texture->unlock(); } + SDLTexture* _texture; + void* _pixels; + int _pitch; +}; + +#endif // INCLUDED_SDL_H diff --git a/80386/disassembler/include/alfe/set.h b/80386/disassembler/include/alfe/set.h new file mode 100644 index 0000000..3f47b68 --- /dev/null +++ b/80386/disassembler/include/alfe/set.h @@ -0,0 +1,129 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_SET_H +#define INCLUDED_SET_H + +template class SetBody : public Array::AppendableBaseBody +{ +public: + virtual void justSetSize(int size) const = 0; + void preDestroy() const { justSetSize(this->_allocated); } +}; + +// Set is not quite a value type, since adding an element in one set will +// affect copies of the same set. Adding an element may cause it to become a +// deep copy, if more storage space was needed. +// +// Note that the default-constructed Key should not be used for real entries. +template class Set : private AppendableArray> +{ +public: + bool has(const Key& key) const + { + auto e = lookup(key); + if (e != 0) + return *e == key; + return false; + } + void add(const Key& key) + { + auto e = lookup(key); + if (e != 0 && *e == key) + return; + if (count() >= this->allocated()*3/4) { + int n = this->allocated()*2; + if (n == 0) + n = 1; + Set other; + other.allocate(n); + n = other.allocated(); + other.expand(n); + other.body()->_size = 0; + for (auto i : *this) + other.add(i); + *this = other; + e = lookup(key); + } + ++this->body()->_size; + *e = key; + } + int count() const { return this->body() == 0 ? 0 : this->body()->_size; } + class Iterator + { + public: + const Key& operator*() const { return *_key; } + bool operator==(const Iterator& other) const + { + return _key == other._key; + } + bool operator!=(const Iterator& other) const + { + return !operator==(other); + } + void operator++() + { + do { + ++_key; + if ((*this) == _set.end()) + return; + } while (*_key == Key()); + } + private: + Iterator(const Key* key, const Set& set) : _key(key), _set(set) { } + const Key* _key; + const Set _set; + + friend class Set; + }; + Iterator begin() const + { + if (this->allocated() == 0) + return Iterator(0, *this); + Iterator i(&(*this)[0], *this); + if (*i == Key()) + ++i; + return i; + } + Iterator end() const + { + if (this->allocated() == 0) + return Iterator(0, *this); + return Iterator(&(*this)[this->allocated()], *this); + } +private: + int row(const Key& key) const { return ::hash(key) % this->allocated(); } + Key* lookup(const Key& key) + { + if (this->allocated() == 0) + return 0; + int r = row(key); + for (int i = 0; i < this->allocated(); ++i) { + // We have a decent hash function so linear probing should work + // fine. + r = (r + 1)%this->allocated(); + Key& e = (*this)[r]; + if (e == key || e == Key()) + return &e; + } + // We should only get here if 0 entries in table, since otherwise there + // should be at least one empty entry. + return 0; + } + const Key* lookup(const Key& key) const + { + if (this->allocated() == 0) + return 0; + int r = row(key); + for (int i = 0; i < this->allocated(); ++i) { + r = (r + 1)%this->allocated(); + const Key& e = (*this)[r]; + if (e == key || e == Key()) + return &e; + } + // We should only get here if 0 entries in table, since otherwise there + // should be at least one empty entry. + return 0; + } +}; + +#endif // INCLUDED_SET_H diff --git a/80386/disassembler/include/alfe/sha256.h b/80386/disassembler/include/alfe/sha256.h new file mode 100644 index 0000000..c78282a --- /dev/null +++ b/80386/disassembler/include/alfe/sha256.h @@ -0,0 +1,218 @@ +#ifndef INCLUDED_SHA256_H +#define INCLUDED_SHA256_H + +#include "alfe/integer_types.h" + +// Based on Brad Conte's implementation at +// https://github.com/B-Con/crypto-algorithms + +class SHA256Hash +{ + Byte _data[32]; +public: + bool bit(int i) { return (_data[i >> 3] & (1 << (i & 7))) != 0; } + class Hasher + { + public: + Hasher() + { + _datalen = 0; + _bitlen = 0; + _state[0] = 0x6a09e667; + _state[1] = 0xbb67ae85; + _state[2] = 0x3c6ef372; + _state[3] = 0xa54ff53a; + _state[4] = 0x510e527f; + _state[5] = 0x9b05688c; + _state[6] = 0x1f83d9ab; + _state[7] = 0x5be0cd19; + } + void update(const Byte* data, size_t len) + { + DWord i; + + for (i = 0; i < len; ++i) { + _data[_datalen] = data[i]; + _datalen++; + if (_datalen == 64) { + transform(); + _bitlen += 512; + _datalen = 0; + } + } + } + void final(Byte* hash) + { + int i = _datalen; + + // Pad whatever data is left in the buffer. + if (_datalen < 56) { + _data[i++] = 0x80; + while (i < 56) + _data[i++] = 0x00; + } + else { + _data[i++] = 0x80; + while (i < 64) + _data[i++] = 0x00; + transform(); + memset(_data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + _bitlen += _datalen * 8; + _data[63] = _bitlen & 0xff; + _data[62] = (_bitlen >> 8) & 0xff; + _data[61] = (_bitlen >> 16) & 0xff; + _data[60] = (_bitlen >> 24) & 0xff; + _data[59] = (_bitlen >> 32) & 0xff; + _data[58] = (_bitlen >> 40) & 0xff; + _data[57] = (_bitlen >> 48) & 0xff; + _data[56] = (_bitlen >> 56) & 0xff; + transform(); + + // Since this implementation uses little endian byte ordering and SHA uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i] = (_state[0] >> (24 - i * 8)) & 0xff; + hash[i + 4] = (_state[1] >> (24 - i * 8)) & 0xff; + hash[i + 8] = (_state[2] >> (24 - i * 8)) & 0xff; + hash[i + 12] = (_state[3] >> (24 - i * 8)) & 0xff; + hash[i + 16] = (_state[4] >> (24 - i * 8)) & 0xff; + hash[i + 20] = (_state[5] >> (24 - i * 8)) & 0xff; + hash[i + 24] = (_state[6] >> (24 - i * 8)) & 0xff; + hash[i + 28] = (_state[7] >> (24 - i * 8)) & 0xff; + } + } + private: + // Right rotation + DWord rot(DWord a, int b) { return (a >> b) | (a << (32 - b)); } + DWord sig0(DWord x) { return rot(x, 7) ^ rot(x, 18) ^ (x >> 3); } + DWord sig1(DWord x) { return rot(x, 17) ^ rot(x, 19) ^ (x >> 10); } + void transform() + { + static const DWord k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + DWord m[64]; + int i; + int j; + + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (_data[j] << 24) | (_data[j + 1] << 16) | (_data[j + 2] << 8) | (_data[j + 3]); + for (; i < 64; ++i) + m[i] = sig1(m[i - 2]) + m[i - 7] + sig0(m[i - 15]) + m[i - 16]; + + DWord a = _state[0]; + DWord b = _state[1]; + DWord c = _state[2]; + DWord d = _state[3]; + DWord e = _state[4]; + DWord f = _state[5]; + DWord g = _state[6]; + DWord h = _state[7]; + + for (i = 0; i < 64; ++i) { + DWord t1 = h + (rot(e, 6) ^ rot(e, 11) ^ rot(e, 25)) + ((e & f) ^ (~e & g)) + k[i] + m[i]; + DWord t2 = (rot(a, 2) ^ rot(a, 13) ^ rot(a, 22)) + ((a & b) ^ (a & c) ^ (b & c)); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + _state[0] += a; + _state[1] += b; + _state[2] += c; + _state[3] += d; + _state[4] += e; + _state[5] += f; + _state[6] += g; + _state[7] += h; + } + + Byte _data[64]; + DWord _datalen; + unsigned long long _bitlen; + DWord _state[8]; + }; + + SHA256Hash(const Byte* data, int length) + { + Hasher h; + h.update(data, length); + h.final(_data); + } + SHA256Hash(File file) + { + Hasher h; + FileStream stream = file.tryOpenRead(); + if (!stream.valid()) { + // We don't want to throw an exception in this situation, since for + // find_duplicates we expect this will happen frequently, for files + // we don't have read access to. Hash the path instead to avoid + // extraneous duplicates. + String p = file.path(); + h.update(&p[0], p.length()); + } + else { + UInt64 size = stream.size(); + DWORD crc = 0xffffffff; + static const int bufferSize = 0x10000; + Array buffer(bufferSize); + while (size > 0) { + int s = + static_cast(min(static_cast(bufferSize), size)); + stream.read(&buffer[0], s); + h.update(&buffer[0], s); + size -= s; + } + } + h.final(_data); + } + SHA256Hash(const SHA256Hash& other) + { + for (int i = 0; i < 32; ++i) + _data[i] = other._data[i]; + } + SHA256Hash(Hasher& hasher) + { + hasher.final(_data); + } + bool operator==(const SHA256Hash& other) + { + for (int i = 0; i < 32; ++i) + if (_data[i] != other._data[i]) + return false; + return true; + } + String toString() + { + static const char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + char s[65]; + for (int i = 0; i < 32; ++i) { + s[i*2] = hexDigits[_data[i] >> 4]; + s[i*2 + 1] = hexDigits[_data[i] & 0x0f]; + } + s[64] = 0; + // This is a bit strange - the String constructor taking a char* and a + // size doesn't copy the data. + return String(s, String()); + } + const Byte* data() { return &_data[0]; } +}; + +#endif // INCLUDED_SHA256_H diff --git a/80386/disassembler/include/alfe/space.h b/80386/disassembler/include/alfe/space.h new file mode 100644 index 0000000..92528ce --- /dev/null +++ b/80386/disassembler/include/alfe/space.h @@ -0,0 +1,203 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_SPACE_H +#define INCLUDED_SPACE_H + +#include "alfe/rational.h" + +class Space +{ +public: + static void parse(CharacterSource* source) + { + do { + CharacterSource s = *source; + int c = s.get(); + if (c == ' ' || c == 10) { + *source = s; + continue; + } + if (parseComment(source)) + continue; + return; + } while (true); + } + static bool parseCharacter(CharacterSource* source, int character, + Span* span = 0) + { + if (!source->parse(character, span)) + return false; + parse(source); + return true; + } + static void assertCharacter(CharacterSource* source, int character, + Span* span = 0) + { + source->assert(character, span); + parse(source); + } + static bool parseOperator(CharacterSource* source, String op, + Span* span = 0) + { + CharacterSource s = *source; + CharacterSource o(op); + Span sp; + do { + Span sp2; + int c = o.get(); + if (c == -1) + break; + if (s.get(&sp2) != c) + return false; + sp += sp2; + } while (true); + *source = s; + if (span != 0) + *span += sp; + parse(source); + return true; + } + static bool parseKeyword(CharacterSource* source, String keyword, + Span* span = 0) + { + CharacterSource s = *source; + CharacterSource o(keyword); + Span sp; + Span sp2; + do { + int c = o.get(); + if (c == -1) + break; + if (s.get(&sp2) != c) + return false; + sp += sp2; + } while (true); + CharacterSource s2 = s; + int c = s2.get(&sp2); + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || c == '_') + return false; + *source = s; + if (span != 0) + *span += sp; + parse(source); + return true; + } + static bool parseNumber(CharacterSource* source, Rational* result, + Span* span = 0) + { + CharacterSource s = *source; + int n = 0; + int c = s.get(span); + int denominator = 1; + bool seenPoint = false; + if (c < '0' || c > '9') + return false; + if (c == '0') { + CharacterSource s2 = s; + Span span2; + int c = s2.get(&span2); + if (c == 'x') { + bool okay = false; + int n = 0; + do { + c = s2.get(&span2); + if (c == '.' && !seenPoint) + seenPoint = true; + else + if (c >= '0' && c <= '9') { + n = n*0x10 + c - '0'; + if (seenPoint) + denominator <<= 4; + } + else + if (c >= 'A' && c <= 'F') { + n = n*0x10 + c + 10 - 'A'; + if (seenPoint) + denominator <<= 4; + } + else + if (c >= 'a' && c <= 'f') { + n = n*0x10 + c + 10 - 'a'; + if (seenPoint) + denominator <<= 4; + } + else + if (okay) { + parse(source); + *result = Rational(n, denominator); + return true; + } + else + return false; + okay = true; + *source = s2; + if (span != 0) + *span += span2; + } while (true); + } + } + do { + n = n*10 + c - '0'; + if (seenPoint) + denominator *= 10; + *source = s; + Span span2; + c = s.get(&span2); + if (c == '.' && !seenPoint) { + seenPoint = true; + c = s.get(&span2); + } + if (c < '0' || c > '9') { + parse(source); + *result = Rational(n, denominator); + return true; + } + if (span != 0) + *span += span2; + } while (true); + } +private: + static bool parseComment(CharacterSource* source) + { + CharacterSource s = *source; + int c = s.get(); + if (c != '/') + return false; + c = s.get(); + if (c == '/') { + do { + *source = s; + c = s.get(); + if (c == 10 || c == -1) + break; + if (c < 0x20) + source->throwUnexpected("printable character", hex(c, 2)); + } while (true); + *source = s; + return true; + } + if (c == '*') { + do { + if (parseComment(&s)) + continue; + *source = s; + c = s.get(); + while (c == '*') { + c = s.get(); + if (c == '/') { + *source = s; + return true; + } + } + if (c == -1) + source->location().throwError("End of file in comment"); + if (c < 0x20 && c != 10) + source->throwUnexpected("printable character", hex(c, 2)); + } while (true); + } + return false; + } +}; + +#endif // INCLUDED_SPACE_H diff --git a/80386/disassembler/include/alfe/stack.h b/80386/disassembler/include/alfe/stack.h new file mode 100644 index 0000000..2f28206 --- /dev/null +++ b/80386/disassembler/include/alfe/stack.h @@ -0,0 +1,68 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_STACK_H +#define INCLUDED_STACK_H + +template class Stack +{ +public: + Stack() : _top(0), _n(0) { } + ~Stack() + { + while (!empty()) + pop(); + } + void push(T t) + { + Entry* top = _top; + _top = new Entry(t); + _top->_next = top; + ++_n; + } + void toArray(Array* array) + { + array->allocate(_n); + for (int i = _n - 1; i >= 0; --i) + (*array)[i] = pop(); + } + T pop() + { + T t = top(); + Entry* top = _top; + _top = top->_next; + delete top; + --_n; + return t; + } + T value(int offset) const + { + Entry* top = _top; + while (offset > 0) { + --offset; + top = top->_next; + } + return top->_t; + } + T top() const { return _top->_t; } + T fromTop(int n) const + { + Entry* top = _top; + while (n > 0) + top = top->_next; + return top->_t; + } + bool empty() const { return _top == 0; } +private: + + class Entry + { + public: + Entry(T t) : _t(t) { } + T _t; + Entry* _next; + }; + Entry* _top; + int _n; +}; + +#endif // INCLUDED_STACK_H diff --git a/80386/disassembler/include/alfe/statement.h b/80386/disassembler/include/alfe/statement.h new file mode 100644 index 0000000..726351c --- /dev/null +++ b/80386/disassembler/include/alfe/statement.h @@ -0,0 +1,989 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_STATEMENT_H +#define INCLUDED_STATEMENT_H + +#include "alfe/parse_tree_object.h" + +template class StatementT; +typedef StatementT Statement; + +template class IdentifierT; +typedef IdentifierT Identifier; + +class ExpressionStatement; + +template class FunctionDefinitionStatementT; +typedef FunctionDefinitionStatementT FunctionDefinitionStatement; + +class CompoundStatement; + +class TycoDefinitionStatement; + +class NothingStatement; + +class IncrementDecrementStatement; + +class ConditionalStatement; + +class SwitchStatement; + +class ReturnStatement; + +class IncludeStatement; + +template class BreakOrContinueStatementT; +typedef BreakOrContinueStatementT BreakOrContinueStatement; + +class ForeverStatement; + +class WhileStatement; + +class ForStatement; + +template class LabelStatementT; +typedef LabelStatementT LabelStatement; + +class GotoStatement; + +class Context +{ +public: + virtual ~Context() { } +}; + +template class StatementT : public ParseTreeObject +{ +public: + static Statement parse(CharacterSource* source) + { + Statement statement = ExpressionStatement::parse(source); + if (statement.valid()) + return statement; + statement = FunctionDefinitionStatement::parse(source); + if (statement.valid()) + return statement; + statement = ExpressionStatement::parseAssignment(source); + if (statement.valid()) + return statement; + statement = CompoundStatement::parse(source); + if (statement.valid()) + return statement; + statement = TycoDefinitionStatement::parse(source); + if (statement.valid()) + return statement; + statement = NothingStatement::parse(source); + if (statement.valid()) + return statement; + statement = IncrementDecrementStatement::parse(source); + if (statement.valid()) + return statement; + statement = ConditionalStatement::parse(source); + if (statement.valid()) + return statement; + statement = SwitchStatement::parse(source); + if (statement.valid()) + return statement; + statement = ReturnStatement::parse(source); + if (statement.valid()) + return statement; + statement = IncludeStatement::parse(source); + if (statement.valid()) + return statement; + statement = BreakOrContinueStatement::parse(source); + if (statement.valid()) + return statement; + statement = ForeverStatement::parse(source); + if (statement.valid()) + return statement; + statement = WhileStatement::parse(source); + if (statement.valid()) + return statement; + statement = ForStatement::parse(source); + if (statement.valid()) + return statement; + statement = LabelStatement::parse(source); + if (statement.valid()) + return statement; + return GotoStatement::parse(source); + } + static Statement parseOrFail(CharacterSource* source) + { + Statement statement = parse(source); + if (!statement.valid()) + source->location().throwError("Expected statement"); + return statement; + } + StatementT() { } + void resolve(Scope* scope) { body()->resolve(scope); } +protected: + StatementT(Handle other) : ParseTreeObject(other) { } + + class Body : public ParseTreeObject::Body + { + public: + Body(const Span& span) : ParseTreeObject::Body(span) { } + virtual void resolve(Scope* scope) = 0; + }; + + Body* body() { return as(); } +}; + +class ExpressionStatement : public Statement +{ +public: + ExpressionStatement(Expression expression, Span span) + : ExpressionStatement(create(expression, span)) { } + + static ExpressionStatement parse(CharacterSource* source) + { + CharacterSource s = *source; + Expression expression = Expression::parse(&s); + if (!expression.valid()) + return ExpressionStatement(); + Span span; + if (!Space::parseCharacter(&s, ';', &span)) + return ExpressionStatement(); + *source = s; + if (!expression.mightHaveSideEffect()) + source->location().throwError("Statement has no effect"); + return ExpressionStatement(expression, expression.span() + span); + } + + static ExpressionStatement parseAssignment(CharacterSource* source) + { + CharacterSource s = *source; + Expression left = Expression::parse(&s); + Location operatorLocation = s.location(); + if (!left.valid()) + return ExpressionStatement(); + Span span; + + static const Operator ops[] = { + OperatorAssignment(), OperatorAddAssignment(), + OperatorSubtractAssignment(), OperatorMultiplyAssignment(), + OperatorDivideAssignment(), OperatorModuloAssignment(), + OperatorShiftLeftAssignment(), OperatorShiftRightAssignment(), + OperatorBitwiseAndAssignment(), OperatorBitwiseOrAssignment(), + OperatorBitwiseXorAssignment(), OperatorPowerAssignment(), + Operator()}; + + const Operator* op; + for (op = ops; op->valid(); ++op) + if (Space::parseOperator(&s, op->toString(), &span)) + break; + if (!op->valid()) + return ExpressionStatement(); + + *source = s; + Expression right = Expression::parseOrFail(source); + Space::assertCharacter(source, ';', &span); + + return ExpressionStatement(FunctionCallExpression::binary(*op, span, + FunctionCallExpression::unary(OperatorAmpersand(), Span(), left), + right), left.span() + span); + } +private: + ExpressionStatement() { } + ExpressionStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + void resolve(Scope* scope) { _expression.resolve(scope); } + private: + Expression _expression; + }; +}; + +class FromStatement : public Statement +{ +public: + static FromStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "from", &span)) + return FromStatement(); + Expression dll = Expression::parseOrFail(source); + Space::assertCharacter(source, ';', &span); + return create(dll, span); + } +private: + FromStatement() { } + FromStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + void resolve(Scope* scope) { _expression.resolve(scope); } + private: + Expression _expression; + }; +}; + +template class FunctionDefinitionStatementT : public Statement +{ +public: + static FunctionDefinitionStatement parse(CharacterSource* source) + { + CharacterSource s = *source; + TycoSpecifier returnTypeSpecifier = TycoSpecifier::parse(&s); + if (!returnTypeSpecifier.valid()) + return FunctionDefinitionStatement(); + Identifier name = Identifier::parse(&s); + if (!name.valid()) + return FunctionDefinitionStatement(); + Span span; + if (!Space::parseCharacter(&s, '(')) + return FunctionDefinitionStatement(); + *source = s; + List> parameterList = + parseParameterList(source); + Space::assertCharacter(source, ')'); + Statement body = FromStatement::parse(source); + if (!body.valid()) + body = Statement::parseOrFail(source); + return create(returnTypeSpecifier, name, parameterList, body); + } +private: + static List> parseParameterList( + CharacterSource* source) + { + List> list; + VariableDefinitionT parameter = + VariableDefinitionT::parse(source); + if (!parameter.valid()) + return list; + list.add(parameter); + Span span; + while (Space::parseCharacter(source, ',', &span)) { + VariableDefinitionT parameter = + VariableDefinitionT::parse(source); + if (!parameter.valid()) + source->location().throwError("Expected parameter"); + list.add(parameter); + } + return list; + } + + FunctionDefinitionStatementT() { } + FunctionDefinitionStatementT(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const TycoSpecifier& returnTypeSpecifier, const Identifier& name, + const List>& parameterList, + const Statement& body) + : Statement::Body(returnTypeSpecifier.span() + body.span()), + _returnTypeSpecifier(returnTypeSpecifier), _name(name), + _parameterList(parameterList), _body(body) { } + TypeT type() const + { + FunctionType t(_returnTypeSpecifier); + for (auto p : _parameterList) + t.instantiate(p.type()); + return t; + } + void resolve(Scope* scope) + { + _returnTypeSpecifier.resolve(scope); + for (auto p : _parameterList) { + p.resolve(scope); + _scope.addObject(p.identifier(), p); + } + _scope.setParentScope(scope); + _body.resolve(&_scope); + } + private: + TycoSpecifier _returnTypeSpecifier; + Identifier _name; + List> _parameterList; + Statement _body; + Scope _scope; + }; +}; + +class StatementSequence : public ParseTreeObject +{ +public: + StatementSequence() { } + static StatementSequence parse(CharacterSource* source) + { + Span span; + List sequence; + do { + Statement statement = Statement::parse(source); + if (!statement.valid()) + break; + span += statement.span(); + sequence.add(statement); + } while (true); + return create(sequence, span); + } + void resolve(Scope* scope) { body()->resolve(scope); } + List::Iterator begin() { return body()->begin(); } + List::Iterator end() { return body()->end(); } +private: + StatementSequence(Handle other) : ParseTreeObject(other) { } + + class Body : public ParseTreeObject::Body + { + public: + Body(const List& sequence, const Span& span) + : ParseTreeObject::Body(span), _sequence(sequence) { } + void resolve(Scope* scope) + { + for (auto s : _sequence) + s.resolve(scope); + } + List::Iterator begin() { return _sequence.begin(); } + List::Iterator end() { return _sequence.end(); } + private: + List _sequence; + }; + + Body* body() { return as(); } +}; + +class CompoundStatement : public Statement +{ +public: + static CompoundStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseCharacter(source, '{', &span)) + return CompoundStatement(); + StatementSequence sequence = StatementSequence::parse(source); + Space::assertCharacter(source, '}', &span); + return create(sequence, span); + } +private: + CompoundStatement() { } + CompoundStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const StatementSequence& sequence, const Span& span) + : Statement::Body(span), _sequence(sequence) { } + void resolve(Scope* scope) { _sequence.resolve(scope); } + private: + StatementSequence _sequence; + }; +}; + +// TycoDefinitionStatement := TycoSignifier "=" TycoSpecifier ";" +class TycoDefinitionStatement : public Statement +{ +public: + static TycoDefinitionStatement parse(CharacterSource* source) + { + CharacterSource s = *source; + CharacterSource s2 = s; + TycoSignifier tycoSignifier = TycoSignifier::parse(&s); + if (!tycoSignifier.valid()) + return TycoDefinitionStatement(); + if (!Space::parseCharacter(&s, '=')) + return TycoDefinitionStatement(); + *source = s; + TycoSpecifier tycoSpecifier = TycoSpecifier::parse(source); + Span span; + Space::assertCharacter(source, ';', &span); + return create(tycoSignifier, tycoSpecifier, + tycoSignifier.span() + span); + } +private: + TycoDefinitionStatement() { } + TycoDefinitionStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const TycoSignifier& tycoSignifier, + const TycoSpecifier& tycoSpecifier, const Span& span) + : Statement::Body(span), _tycoSignifier(tycoSignifier), + _tycoSpecifier(tycoSpecifier) { } + void resolve(Scope* scope) + { + + } + private: + TycoSignifier _tycoSignifier; + TycoSpecifier _tycoSpecifier; + }; +}; + +class NothingStatement : public Statement +{ +public: + static NothingStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "nothing", &span)) + return NothingStatement(); + Space::assertCharacter(source, ';', &span); + return create(span); + } +private: + NothingStatement() { } + NothingStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Span& span) : Statement::Body(span) { } + void resolve(Scope* scope) { } + }; +}; + +class IncrementDecrementStatement : public Statement +{ +public: + static Statement parse(CharacterSource* source) + { + Span span; + Operator o = OperatorIncrement().parse(source, &span); + if (!o.valid()) + o = OperatorDecrement().parse(source, &span); + if (!o.valid()) + return Statement(); + Expression lValue = Expression::parse(source); + Span span2; + Space::assertCharacter(source, ';', &span2); + return ExpressionStatement(FunctionCallExpression::unary(o, span, + FunctionCallExpression::unary( + OperatorAmpersand(), Span(), lValue)), + span + span2); + } +}; + +// ConditionalStatement = (`if` | `unless`) ConditionedStatement +// ((`elseIf` | `elseUnless`) ConditionedStatement)* [`else` Statement]; +// ConditionedStatement = "(" Expression ")" Statement; +class ConditionalStatement : public Statement +{ +public: + static ConditionalStatement parse(CharacterSource* source) + { + Span span; + if (Space::parseKeyword(source, "if", &span)) + return parse2(source, span, false); + if (Space::parseKeyword(source, "unless", &span)) + return parse2(source, span, true); + return ConditionalStatement(); + } +private: + static ConditionalStatement parse2(CharacterSource* source, Span span, + bool unlessStatement) + { + Space::assertCharacter(source, '('); + Expression condition = Expression::parseOrFail(source); + Space::assertCharacter(source, ')'); + Statement statement = Statement::parseOrFail(source); + span += statement.span(); + Statement elseStatement; + if (Space::parseKeyword(source, "else")) { + elseStatement = Statement::parseOrFail(source); + span += elseStatement.span(); + } + else + if (Space::parseKeyword(source, "elseIf")) { + elseStatement = parse2(source, span, false); + span += elseStatement.span(); + } + else + if (Space::parseKeyword(source, "elseUnless")) { + elseStatement = parse2(source, span, true); + span += elseStatement.span(); + } + if (unlessStatement) + condition = !condition; + return create(condition, statement, elseStatement, span); + } + + ConditionalStatement() { } + ConditionalStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& condition, const Statement& trueStatement, + const Statement& falseStatement, const Span& span) + : Statement::Body(span), _condition(condition), + _trueStatement(trueStatement), _falseStatement(falseStatement) { } + void resolve(Scope* scope) + { + _condition.resolve(scope); + _trueStatement.resolve(scope); + _falseStatement.resolve(scope); + } + private: + Expression _condition; + Statement _trueStatement; + Statement _falseStatement; + }; +}; + +class SwitchStatement : public Statement +{ +public: + static SwitchStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "switch", &span)) + return SwitchStatement(); + Space::assertCharacter(source, '('); + Expression expression = Expression::parseOrFail(source); + Space::assertCharacter(source, ')'); + Space::assertCharacter(source, '{'); + Case defaultCase; + + CharacterSource s = *source; + List cases; + do { + Case c = Case::parse(source); + if (!c.valid()) + break; + if (c.isDefault()) { + if (defaultCase.valid()) + s.location().throwError( + "This switch statement already has a default case"); + defaultCase = c; + } + else + cases.add(c); + } while (true); + Space::assertCharacter(source, '}', &span); + return create(expression, defaultCase, cases, span); + } +private: + SwitchStatement() { } + SwitchStatement(Handle other) { } + + class Case : public ParseTreeObject + { + public: + static Case parse(CharacterSource* source) + { + List expressions; + bool defaultType; + Span span; + if (Space::parseKeyword(source, "case", &span)) { + defaultType = false; + do { + Expression expression = Expression::parseOrFail(source); + expressions.add(expression); + if (!Space::parseCharacter(source, ',')) + break; + } while (true); + } + else { + defaultType = true; + if (!Space::parseKeyword(source, "default", &span)) + source->location().throwError("Expected case or default"); + } + Space::assertCharacter(source, ':'); + Statement statement = Statement::parseOrFail(source); + span += statement.span(); + if (defaultType) + return create(statement, span); + return create(expressions, statement, span); + } + bool isDefault() const { return body()->isDefault(); } + void resolve(Scope* scope) { body()->resolve(scope); } + + Case() { } + + class Body : public ParseTreeObject::Body + { + public: + Body(const Statement& statement, const Span& span) + : ParseTreeObject::Body(span), _statement(statement) { } + virtual bool isDefault() const = 0; + virtual void resolve(Scope* scope) + { + _statement.resolve(scope); + } + private: + Statement _statement; + }; + private: + Case(Handle other) : ParseTreeObject(other) { } + + Body* body() { return as(); } + const Body* body() const { return as(); } + + class DefaultBody : public Body + { + public: + DefaultBody(const Statement& statement, const Span& span) + : Body(statement, span) { } + bool isDefault() const { return true; } + }; + class ValueBody : public Body + { + public: + ValueBody(const List& expressions, + const Statement& statement, const Span& span) + : Body(statement, span), _expressions(expressions) { } + bool isDefault() const { return false; } + void resolve(Scope* scope) + { + for (auto e : _expressions) + e.resolve(scope); + Body::resolve(scope); + } + private: + List _expressions; + }; + }; + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Case& defaultCase, + const List& cases, const Span& span) + : Statement::Body(span), _expression(expression), + _defaultCase(defaultCase), _cases(cases) { } + void resolve(Scope* scope) + { + _expression.resolve(scope); + _defaultCase.resolve(scope); + for (auto c : _cases) + c.resolve(scope); + } + private: + Expression _expression; + Case _defaultCase; + List _cases; + }; +}; + +class ReturnStatement : public Statement +{ +public: + static ReturnStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "return", &span)) + return ReturnStatement(); + Expression expression = Expression::parseOrFail(source); + Space::assertCharacter(source, ';', &span); + return create(expression, span); + } +private: + ReturnStatement() { } + ReturnStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + void resolve(Scope* scope) { _expression.resolve(scope); } + private: + Expression _expression; + }; +}; + +class IncludeStatement : public Statement +{ +public: + static IncludeStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "include", &span)) + return IncludeStatement(); + Expression expression = Expression::parseOrFail(source); + Space::assertCharacter(source, ';', &span); + return create(expression, span); + } +private: + IncludeStatement() { } + IncludeStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + void resolve(Scope* scope) { _expression.resolve(scope); } + private: + Expression _expression; + }; +}; + +template class BreakOrContinueStatementT : public Statement +{ +public: + static BreakOrContinueStatement parse(CharacterSource* source) + { + BreakOrContinueStatement breakStatement = parseBreak(source); + if (breakStatement.valid()) + return breakStatement; + return parseContinue(source); + } +private: + BreakOrContinueStatementT() { } + BreakOrContinueStatementT(Handle other) : Statement(other) { } + + static BreakOrContinueStatement parseBreak(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "break", &span)) + return BreakOrContinueStatement(); + BreakOrContinueStatement statement = parse(source); + if (!statement.valid()) + Space::assertCharacter(source, ';', &span); + else + span += statement.span(); + return create(statement, span); + } + + static BreakOrContinueStatement parseContinue(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "continue", &span)) + return BreakOrContinueStatement(); + Space::assertCharacter(source, ';', &span); + return create(span); + } + + class Body : public Statement::Body + { + public: + Body(const Span& span) : Statement::Body(span) { } + void resolve(Scope* scope) { } + }; + + class BreakBody : public Body + { + public: + BreakBody(const BreakOrContinueStatement& statement, const Span& span) + : Body(span), _statement(statement) { } + private: + BreakOrContinueStatementT _statement; + }; + + class ContinueBody : public Body + { + public: + ContinueBody(const Span& span) : Body(span) { } + }; +}; + +class ForeverStatement : public Statement +{ +public: + static ForeverStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "forever", &span)) + return ForeverStatement(); + Statement statement = Statement::parseOrFail(source); + return create(statement, span + statement.span()); + } +private: + ForeverStatement() { } + ForeverStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Statement& statement, const Span& span) + : Statement::Body(span), _statement(statement) { } + void resolve(Scope* scope) { _statement.resolve(scope); } + private: + Statement _statement; + }; +}; + +class WhileStatement : public Statement +{ +public: + static WhileStatement parse(CharacterSource* source) + { + Span span; + Statement doStatement; + bool foundDo = false; + if (Space::parseKeyword(source, "do", &span)) { + foundDo = true; + doStatement = Statement::parseOrFail(source); + } + bool foundWhile = false; + bool foundUntil = false; + if (Space::parseKeyword(source, "while", &span)) + foundWhile = true; + else + if (Space::parseKeyword(source, "until", &span)) + foundUntil = true; + if (!foundWhile && !foundUntil) { + if (foundDo) + source->location().throwError("Expected while or until"); + return WhileStatement(); + } + Space::assertCharacter(source, '('); + Expression condition = Expression::parse(source); + Space::assertCharacter(source, ')'); + Statement statement = Statement::parseOrFail(source); + span += statement.span(); + Statement doneStatement; + if (Space::parseKeyword(source, "done")) { + doneStatement = Statement::parseOrFail(source); + span += doneStatement.span(); + } + if (foundUntil) + condition = !condition; + return create(doStatement, condition, statement, + doneStatement, span); + } +private: + WhileStatement() { } + WhileStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Statement& doStatement, const Expression& condition, + const Statement& statement, const Statement& doneStatement, + const Span& span) + : Statement::Body(span), _doStatement(doStatement), + _condition(condition), _statement(statement), + _doneStatement(doneStatement) { } + void resolve(Scope* scope) + { + _doStatement.resolve(scope); + _condition.resolve(scope); + _statement.resolve(scope); + _doneStatement.resolve(scope); + } + private: + Statement _doStatement; + Expression _condition; + Statement _statement; + Statement _doneStatement; + }; +}; + +class ForStatement : public Statement +{ +public: + static ForStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "for", &span)) + return ForStatement(); + Space::assertCharacter(source, '('); + Statement preStatement = Statement::parse(source); + if (!preStatement.valid()) + Space::assertCharacter(source, ';'); + Expression expression = Expression::parse(source); + Space::assertCharacter(source, ';'); + Statement postStatement = Statement::parse(source); + Space::parseCharacter(source, ')'); + Statement statement = Statement::parseOrFail(source); + span += statement.span(); + Statement doneStatement; + if (Space::parseKeyword(source, "done")) { + doneStatement = Statement::parseOrFail(source); + span += doneStatement.span(); + } + return create(preStatement, expression, postStatement, + statement, doneStatement, span); + } +private: + ForStatement() { } + ForStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Statement& preStatement, const Expression& condition, + const Statement& postStatement, const Statement& statement, + const Statement& doneStatement, const Span& span) + : Statement::Body(span), _preStatement(preStatement), + _condition(condition), _postStatement(postStatement), + _statement(statement), _doneStatement(doneStatement) { } + void resolve(Scope* scope) + { + _preStatement.resolve(scope); + _condition.resolve(scope); + _postStatement.resolve(scope); + _statement.resolve(scope); + _doneStatement.resolve(scope); + } + private: + Statement _preStatement; + Expression _condition; + Statement _postStatement; + Statement _statement; + Statement _doneStatement; + }; +}; + +template class LabelStatementT : public Statement +{ +public: + static LabelStatement parse(CharacterSource* source) + { + CharacterSource s2 = *source; + Identifier identifier = Identifier::parse(&s2); + if (!identifier.valid()) + return LabelStatement(); + Span span; + if (!Space::parseCharacter(&s2, ':', &span)) + return LabelStatement(); + return create(identifier, identifier.span() + span); + } +private: + LabelStatementT() { } + LabelStatementT(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Identifier& identifier, const Span& span) + : Statement::Body(span), _identifier(identifier) { } + void resolve(Scope* scope) + { + + } + private: + IdentifierT _identifier; + }; +}; + +class GotoStatement : public Statement +{ +public: + static GotoStatement parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "goto", &span)) + return GotoStatement(); + Expression expression = Expression::parseOrFail(source); + Span span2; + Space::parseCharacter(source, ';', &span); + return create(expression, span); + } +private: + GotoStatement() { } + GotoStatement(Handle other) : Statement(other) { } + + class Body : public Statement::Body + { + public: + Body(const Expression& expression, const Span& span) + : Statement::Body(span), _expression(expression) { } + void resolve(Scope* scope) { _expression.resolve(scope); } + private: + Expression _expression; + }; +}; + +#endif // INCLUDED_STATEMENT_H diff --git a/80386/disassembler/include/alfe/statistics.h b/80386/disassembler/include/alfe/statistics.h new file mode 100644 index 0000000..93f1e4a --- /dev/null +++ b/80386/disassembler/include/alfe/statistics.h @@ -0,0 +1,26 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_STATISTICS_H +#define INCLUDED_STATISTICS_H + +template class Statistics +{ +public: + Statistics() : _n(0), _total(0), _total2(0) { } + void add(const T& value) + { + ++_n; + _total += value; + _total2 += value*value; + } + T mean() const { return _total/_n; } + T variance() const { return _total2/_n - mean()*mean(); } + T standardDeviation() const { return sqrt(variance()); } + T populationDeviation() const { return sqrt(variance()*_n/(_n - 1)); } +private: + int _n; + T _total; + T _total2; +}; + +#define INCLUDED_STATISTICS_H diff --git a/80386/disassembler/include/alfe/stream.h b/80386/disassembler/include/alfe/stream.h new file mode 100644 index 0000000..f202e55 --- /dev/null +++ b/80386/disassembler/include/alfe/stream.h @@ -0,0 +1,272 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_STREAM_H +#define INCLUDED_STREAM_H + +#ifndef _WIN32 +class FileDescriptor : public ConstHandle +{ +public: + FileDescriptor() : _fileDescriptor(-1) { } + WindowsHandle(int fileDescriptor, bool own = true) + : _handle(handle), + ConstHandle((own && fileDescriptor != -1) + ? create(fileDescriptor) : ConstHandle()) + { } + bool valid() const { return _fileDescriptor != -1; } + operator int() const { return _fileDescriptor; } +protected: + FileDescriptor(const ConstHandle& other, int fileDescriptor) + : ConstHandle(other), _fileDescriptor(fileDescriptor) { } + class Body : public ConstHandle::Body + { + Body(int fileDescriptor) : _fileDescriptor(fileDescriptor) { } + ~Body() + { + if (_fileDescriptor != -1) + close(_fileDescriptor); + } + private: + int _fileDescriptor; + }; +private: + int _fileDescriptor; +}; +#endif + +template class StreamT +#ifdef _WIN32 + : public WindowsHandle +#else + : public FileDescriptor +#endif +{ +public: +#ifdef _WIN32 + StreamT() { } + StreamT(HANDLE handle, const File& file = File(), bool own = true) + : WindowsHandle(create(own && + handle != INVALID_HANDLE_VALUE ? handle : INVALID_HANDLE_VALUE), + handle), + _file(file) + { } + HANDLE handle() const { return operator HANDLE(); } +#else + StreamT() { } + StreamT(int fileDescriptor, const File& file = File(), bool own = true) + : FileDescriptor(create(own && + fileDesciptor != -1 ? fileDescriptor : -1), fileDescriptor), + _file(file) + { } + operator int() const { return operator int(); } +#endif + File file() const { return _file; } + // Be careful using the template read() and write() functions with types + // other than single bytes and arrays thereof - they are not endian-safe. + void write(const char* string) const + { + write(static_cast(string), strlen(string)); + } + template void write(const U& value) const + { + write(static_cast(&value), sizeof(U)); + } + template void write(const Array& value) const + { + write(static_cast(&value[0]), value.count()*sizeof(U)); + } + template void write(const AppendableArray& value) const + { + write(static_cast(&value[0]), value.count()*sizeof(U)); + } + void write(const String& s) const { write(&s[0], s.length()); } + void write(const Exception& e) const { e.write(*this); } + void write(const void* buffer, size_t bytes) const + { + if (bytes == 0) + return; +#ifdef _WIN32 + DWORD bytesWritten; + if (bytes > std::numeric_limits::max()) { + throw Exception("Trying to write too many bytes to " + + _file.path()); + } + if (WriteFile(handle(), buffer, static_cast(bytes), &bytesWritten, NULL) == 0 || + bytesWritten != bytes) + throw Exception::systemError("Writing file " + _file.path()); +#else + ssize_t writeResult = ::write(_fileDescriptor, buffer, bytes); + if (writeResult != bytes) + throw Exception::systemError("Writing file " + _file.path()); +#endif + } + template U read() + { + U value; + read(reinterpret_cast(&value), sizeof(U)); + return value; + } + String readLengthString() + { + int length = read(); + String data(length); + read(data.data(), length); + return data; + } + // Read a string from the file. The end of the line (any line ending) or + // the end of the file delimits the string. EOL characters are not + // returned. + String readString(bool* eof = 0, int maxLength = 0x7fffffff) + { + String s; + int l = 0; + if (eof != 0) + *eof = false; + do { + int b = peekByte(0); + if (b == 10) { + read(); + if (peekByte(0) == 13) + read(); + return s; + } + if (b == 13) { + read(); + if (peekByte(0) == 10) + read(); + return s; + } + if (b == -1) { + if (eof != 0) { + *eof = true; + return s; + } + if (l != 0) + return s; + // We're at EOF, but caller was sure we wouldn't be. Throw. + } + if (l == maxLength) + return s; + read(); + ++l; + s += String::Byte(b); + } while (true); + } + // Returns number of bytes actually read + int tryRead(Byte* destination, int bytes) const + { + // Read any buffered bytes first + CircularBuffer* buffer = &body()->_buffer; + int c = buffer->count(); + if (c != 0) { + if (c > bytes) + c = bytes; + int b = buffer->readBoundary(); + if (b > c) + b = c; + memcpy(destination, buffer->readPointer(), b); + memcpy(destination + b, buffer->lowPointer(), c-b); + buffer->remove(c); + destination += c; + bytes -= c; + } + return c + tryReadUnbuffered(destination, bytes); + } + int tryReadByte() + { + Byte b; + int bytesRead = tryRead(&b, 1); + if (bytesRead != 1) + return -1; + return b; + } + void read(Byte* destination, int bytes) const + { + int bytesRead = tryRead(destination, bytes); + if (bytesRead != bytes) + throw Exception("End of file reading file " + _file.path()); + } + int peekByte(int n) { return peek(n, -1); } + template U peek(int n, const U& defaultValue = U()) + { + return peek(n, defaultValue); + } + template R peek(int n, const R& defaultValue = R()) + { + // Make sure we have enough data in the buffer + CircularBuffer* buffer = &body()->_buffer; + int r = sizeof(U)*(n + 1) - buffer->count(); + if (r > 0) { + buffer->add(r); + int b = buffer->writeBoundary(); + int c; + if (b > r) + b = r; + c = tryReadUnbuffered(buffer->writePointer(), b); + buffer->added(c); + if (c < b) + return defaultValue; + c = tryReadUnbuffered(buffer->lowPointer(), r - b); + buffer->added(c); + if (c < r - b) + return defaultValue; + } + + // The object we want to peek at may be unaligned in the buffer or even + // split across the boundary, so copy it out to return it. + U x; + buffer->copyOut(&x, n*sizeof(U), sizeof(U)); + return x; + } + void close() + { + *this = Stream(); + } +private: + int tryReadUnbuffered(Byte* destination, int bytes) const + { + if (bytes == 0) + return 0; +#ifdef _WIN32 + DWORD bytesRead; + if (ReadFile(handle(), destination, bytes, &bytesRead, NULL) == 0) { + DWORD error = GetLastError(); + if (error == ERROR_HANDLE_EOF || error == ERROR_BROKEN_PIPE || + error == ERROR_PIPE_NOT_CONNECTED) + return bytesRead; + throw Exception::systemError("Reading file " + _file.path()); + } + return bytesRead; +#else + ssize_t readResult = ::read(_fileDescriptor, destination, bytes); + if (readResult == -1) + throw Exception::systemError("Reading file " + _file.path()); + return readResult; +#endif + } + class Body +#ifdef _WIN32 + : public WindowsHandle::Body +#else + : public FileDescriptor::Body +#endif + { + public: +#ifdef _WIN32 + Body(HANDLE handle) + : WindowsHandle::Body(handle) +#else + Body(int fileDescriptor) + : FileDescriptor::Body(fileDescriptor) +#endif + { } + mutable CircularBuffer _buffer; + }; + const Body* body() const { return as(); } + + File _file; + + friend class Body; +}; + +#endif // INCLUDED_STREAM_H diff --git a/80386/disassembler/include/alfe/string.h b/80386/disassembler/include/alfe/string.h new file mode 100644 index 0000000..0ed6f74 --- /dev/null +++ b/80386/disassembler/include/alfe/string.h @@ -0,0 +1,812 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_STRING_H +#define INCLUDED_STRING_H + +#include + +template class ExceptionT; +typedef ExceptionT Exception; + +template class StringTemplate; +typedef StringTemplate String; + +template class CharacterSourceT; +typedef CharacterSourceT CharacterSource; + +template class StringTemplate +{ +public: +#ifdef _WIN32 + static int bytes(const WCHAR* utf16) + { + int n = 0; + int offset = 0; + while (true) { + int c = *utf16; + ++utf16; + if (c == 0) + break; + if (c >= 0xdc00 && c < 0xe000) + throw Exception("String offset " + Hex(offset) + + ": expected 0x0000..0xDBFF or 0xE000..0xFFFF, found " + + Hex(c, 4)); + ++offset; + if (c >= 0xd800 && c < 0xdc00) { + int c2 = *utf16; + ++utf16; + if (c2 < 0xdc00 || c2 >= 0xe000) + throw Exception("String offset " + Hex(offset) + + ": expected 0xDC00..0xDFFF, found " + Hex(c2, 4)); + ++offset; + c = (((c & 0x3ff) << 10) | (c2 & 0x3ff)) + 0x10000; + } + n += CodePoint(c).bytes(); + } + return n; + } +#endif + class Hex + { + public: + Hex(int n, int digits = 8, bool ox = true) + : _n(n), _digits(digits), _ox(ox) { } + String operator+(const char* a) + { + int l = bytes(); + int al = static_cast(strlen(a)); + String s(l + al); + write(s.data()); + memcpy(s.data() + l, a, al); + return s; + } + private: + int bytes() const { return _digits + (_ox ? 2 : 0); } + void write(T* destination) const + { + if (_ox) { + *destination = '0'; + ++destination; + *destination = 'x'; + ++destination; + } + for (int i = 0; i < _digits; ++i) { + int d = (_n >> ((_digits - i - 1) << 2)) & 0xf; + *destination = d < 10 ? d + '0' : d + 'A' - 10; + ++destination; + } + } + + int _n; + int _digits; + bool _ox; + friend class StringTemplate; + }; + + class CodePoint + { + public: + CodePoint(int c) : _c(c) { } + String operator+(const char* a) + { + int l = bytes(); + int al = static_cast(strlen(a)); + String s(l + al); + write(s.data()); + memcpy(s.data() + l, a, al); + return s; + } + private: + int bytes() const + { + if (_c < 0x80) + return 1; + if (_c < 0x800) + return 2; + if (_c < 0x10000) + return 3; + return 4; + } + void write(T* destination) const + { + if (_c < 0x80) { + *destination = _c; + return; + } + if (_c < 0x800) { + *destination = 0xc0 | (_c >> 6); + ++destination; + } + else { + if (_c < 0x10000) { + *destination = 0xe0 | (_c >> 12); + ++destination; + } + else { + *destination = 0xf0 | (_c >> 18); + ++destination; + *destination = 0x80 | ((_c >> 12) & 0x3f); + ++destination; + } + *destination = 0x80 | ((_c >> 6) & 0x3f); + ++destination; + } + *destination = 0x80 | (_c & 0x3f); + } + int _c; + friend class StringTemplate; + }; + + class Byte + { + public: + Byte(const T& b) : _b(b) { } + String operator+(const char* a) + { + int al = strlen(a); + String s(1 + al); + write(s.data()); + memcpy(s.data() + 1, a, al); + return s; + } + private: + void write(T* destination) const { *destination = _b; } + T _b; + friend class StringTemplate; + }; + + class Decimal + { + public: + Decimal(int n, int digits = 0) : _n(n), _digits(digits) { } + String operator+(const char* a) + { + int l = bytes(); + int al = static_cast(strlen(a)); + //if (l + al > std::numeric_limits::max()) + // throw Exception("String too long"); + String s(static_cast(l + al)); + write(s.data()); + memcpy(s.data() + l, a, al); + return s; + } + private: + int bytes() const + { + int l = 1; + int n = _n; + if (n < 0) { + if (n == std::numeric_limits::min()) + n = 1 - n; + else + n = -n; + ++l; + } + while (n >= 10) { + ++l; + n /= 10; + } + if (l < _digits) + return _digits; + return l; + } + void write(T* destination) const + { + int n = _n; + int l = bytes(); + bool intMin = false; + if (n < 0) { + if (n == std::numeric_limits::min()) { + n = 1 - n; + intMin = true; + } + else + n = -n; + *destination = '-'; + ++destination; + --l; + } + int d = n % 10; + if (intMin) + ++d; + do { + --l; + destination[l] = d + '0'; + n /= 10; + d = n % 10; + } while (l > 0); + } + + int _n; + int _digits; + friend class StringTemplate; + }; + + class Boolean + { + public: + explicit Boolean(bool b) : _b(b) { } + int bytes() const { return _b ? 4 : 5; } + String operator+(const char* a) + { + int l = bytes(); + int al = strlen(a); + String s(l + al); + write(s.data()); + memcpy(s.data() + l, a, al); + return s; + } + private: + void write(T* destination) const + { + auto s = reinterpret_cast(_b ? "true" : "false"); + memcpy(destination, s, bytes()); + } + bool _b; + friend class StringTemplate; + }; + + StringTemplate() : StringTemplate(0, 0, 0) { } + StringTemplate(const char* data, int length, bool owning = false) + : StringTemplate(reinterpret_cast(data), length, length, + owning) + { } + StringTemplate(const char* data) + : StringTemplate(data, static_cast(strlen(data))) { } + StringTemplate(const Array& array) + : StringTemplate(reinterpret_cast(&array[0]), array.count()) + { } + StringTemplate(const String& other) : StringTemplate(0, 0, 0) + { + *this = other; + } + StringTemplate(const char* a, const String& b) : StringTemplate(0, 0, 0) + { + int al = static_cast(strlen(a)); + if (al == 0) + *this = b; + else { + int bl = b.length(); + int l = al + bl; + *this = StringTemplate(reinterpret_cast(a), l, al); + memcpy(data() + al, b.data(), bl); + } + } + + ~StringTemplate() { reset(); } + const String& operator=(const String& other) + { + reset(); + setLength(other.length()); + unreset(); + if (small()) + memcpy(data(), other.data(), length()); + else { + _array = other._array; + _start = other._start; + } + return *this; + } + +#ifdef _WIN32 + StringTemplate(const WCHAR* utf16) : StringTemplate(bytes(utf16)) + { + write(data(), utf16); + } +#endif + StringTemplate(const Hex& hex) : StringTemplate(hex.bytes()) + { + hex.write(data()); + } + StringTemplate(const CodePoint& c) : StringTemplate(c.bytes()) + { + c.write(data()); + } + StringTemplate(const Decimal d) : StringTemplate(d.bytes()) + { + d.write(data()); + } + StringTemplate(const Byte b): StringTemplate(1) { b.write(data()); } + StringTemplate(const Boolean b): StringTemplate(b.bytes()) + { + b.write(data()); + } + const String& operator+=(const String& other) + { + extend(other.data(), other.length(), other.length()); + return *this; + } + String operator+(const String& other) const + { + String s(*this); + s += other; + return s; + } + const String& operator+=(int d) + { + Decimal dd(d); + int l = dd.bytes(); + extend(0, l, 0); + dd.write(data() + length() - l); + return *this; + } + String operator+(int d) const { String s(*this); s += d; return s; } +#ifdef _WIN32 + const String& operator+=(const WCHAR* utf16) + { + int l = bytes(utf16); + extend(0, l, 0); + write(data() + length() - l, utf16); + return *this; + } + String operator+(const WCHAR* utf16) const + { + String s(*this); + s += utf16; + return s; + } +#endif + const String& operator+=(const Hex& hex) + { + int l = hex.bytes(); + extend(0, l, 0); + hex.write(data() + length() - l); + return *this; + } + String operator+(const Hex& hex) const + { + String s(*this); + s += hex; + return s; + } + const String& operator+=(const CodePoint& c) + { + int l = c.bytes(); + extend(0, l, 0); + c.write(data() + length() - l); + return *this; + } + String operator+(const CodePoint& c) const + { + String s(*this); + s += c; + return s; + } + const String& operator+=(const Byte& b) + { + extend(&b._b, 1, 1); + return *this; + } + String operator+(const Byte& b) const + { + String s(*this); + s += b; + return s; + } + const String& operator+=(const Boolean& b) + { + int l = b.bytes(); + extend(0, l, 0); + b.write(data() + length() - l); + return *this; + } + String operator+(const Boolean& b) const + { + String s(*this); + s += b; + return s; + } + + const String& operator*=(int n) + { + if (n == 0) + *this = String(); + else { + int l = length(); + extend(0, l*(n - 1), 0); + T* source = data(); + T* destination = source + l; + for (int i = 1; i < n; ++i) { + memcpy(destination, source, l); + destination += l; + } + } + return *this; + } + String operator*(int n) { String s(*this); s *= n; return s; } + + String subString(int start, int length) const + { + return String(*this, start, length); + } + void operator++() + { + if (length() > 0) + *this = subString(_start + 1, length() - 1); + } + T operator*() const { return *data(); } + const T& operator[](int offset) const { return *(data() + offset); } + UInt32 hash() const + { + Hash h(typeid(String)); + const T* p = data(); + for (int i = 0; i < length(); ++i) { + h.mixin(*p); + ++p; + } + return h; + } + bool operator==(const String& other) const + { + if (length() != other.length()) + return false; + return memcmp(data(), other.data(), length()) == 0; + } + bool operator==(const char* b) const + { + const T* a = data(); + for (int i = 0; i < length(); ++i) { + if (*b == 0) + return false; + if (*a != *b) + return false; + ++a; + ++b; + } + return *b == 0; + } + bool equalsIgnoreCase(const String& other) const + { + int l = length(); + if (l != other.length()) + return false; + const T* a = data(); + const T* b = other.data(); + for (int i = 0; i < l; ++i) { + if (tolower(*a) != tolower(*b)) + return false; + ++a; + ++b; + } + return true; + } + bool equalsIgnoreCase(const char* b) const + { + const T* a = data(); + for (int i = 0; i < length(); ++i) { + if (*b == 0) + return false; + if (tolower(*a) != tolower(*b)) + return false; + ++a; + ++b; + } + return *b == 0; + } + + + bool operator!=(const String& other) const { return !operator==(other); } + bool operator<(const String& other) const + { + const T* a = data(); + const T* b = other.data(); + for (int i = 0; i < min(_length, other._length); ++i) { + if (*a < *b) + return true; + if (*a > *b) + return false; + ++a; + ++b; + } + return _length < other._length; + } + bool operator>(const String& other) const { return other < *this; } + bool operator<=(const String& other) const { return !operator>(other); } + bool operator>=(const String& other) const { return !operator<(other); } + + String alignRight(int n) + { + return String(" ")*max(0, n - length()) + (*this); + } + String alignLeft(int n) + { + return (*this) + String(" ")*max(0, n - length()); + } + + bool empty() const { return length() == 0; } + int length() const + { + return *(reinterpret_cast(reinterpret_cast( + this+1)) - 1); + } + bool endsInIgnoreCase(String suffix) const + { + int l = suffix.length(); + int o = length() - l; + if (o < 0) + return false; + for (int i = 0; i < l; ++i) + if (tolower((*this)[i + o]) != tolower(suffix[i])) + return false; + return true; + } +private: + explicit StringTemplate(int length) : StringTemplate(0, length, 0) { } + void setLength(int l) + { + *(reinterpret_cast(reinterpret_cast(this+1)) - 1) = l; + } + void extend(const T* otherData, int extendLength, int copyLength) + { + int newLength = length() + extendLength; + if (small()) { + if (newLength > smallStringThreshold()) { + String a(data(), newLength, length()); + memcpy(a.data() + length(), otherData, copyLength); + *this = a; + } + else { + memcpy(data() + length(), otherData, copyLength); + setLength(newLength); + } + } + else { + if (_array.count() == 0) { + // We always need to own concatenations, because we don't know + // where the end of the external buffer is. + String a(data(), newLength, length()); + memcpy(a.data() + length(), otherData, copyLength); + *this = a; + } + else { + int t = static_cast(min( + static_cast(copyLength), + bufferStart() + bufferCount() - (data() + length()))); + if (memcmp(data() + length(), otherData, t) == 0) { + setLength(length() + t); + copyLength -= t; + otherData += t; + } + if (extendLength <= _array.allocated() - bufferCount() && + bufferStart() + bufferCount() == data() + length()) { + _array.append(otherData, copyLength); + _array.expand(extendLength - copyLength); + setLength(newLength); + } + else { + String a(data(), newLength, length()); + memcpy(a.data() + length(), otherData, copyLength); + *this = a; + } + } + } + } + + const T* bufferStart() const { return &_array[0]; } + int bufferCount() const { return _array.count(); } + T* data() + { + return small() ? reinterpret_cast(this) : const_cast(_start); + } + const T* data() const + { + return small() ? reinterpret_cast(this) : _start; + } + // With the small string optimization, we use all the space in String + // (_array, _start and any alignment slop space) as the data buffer. Since + // _array and _start are pointers (8-byte aligned on 64-bit machines - + // checked with VC++ and GCC) we should get 8 bytes for small strings on + // 32-bit and 20 bytes on 64-bit. + static int smallStringThreshold() + { + // This is basically offsetof(String, length()) but that would call + // length() on a null pointer and invoke undefined behavior. + return static_cast(reinterpret_cast( + reinterpret_cast(reinterpret_cast( + reinterpret_cast(0) + 1)) - 1)); + } + bool small() const { return length() <= smallStringThreshold(); } + // All constructors ultimately use this one, as String construction is + // quite involved (due to the small string optimization). + StringTemplate(const T* start, int size, int copy, bool owning = true) + { + if (size > smallStringThreshold()) { + if (owning) { + _array = AppendableArray(size); + _array.expand(size); + _start = bufferStart(); + } + else + _start = start; + } + else + owning = true; + setLength(size); + unreset(); + if (owning) + memcpy(data(), start, copy); + } + StringTemplate(const String& other, int start, int size) + { + if (size > smallStringThreshold()) { + *this = other; + _start += start; + setLength(size); + } + else { + setLength(size); + unreset(); + memcpy(data(), other.data() + start, size); + } + } + void reset() + { + if (small()) { + // Default construct Handle so destructor works correctly. This + // should just zero out the _body member. + new(&_array) AppendableArray(); + } + } + void unreset() + { + if (small()) { + // Should be a no-op. We'll undo this in reset(). + (&_array)->~AppendableArray(); + } + } + +#ifdef _WIN32 + static T* write(T* destination, const WCHAR* utf16) + { + int i = 0; + while (true) { + int c = *utf16; + ++utf16; + if (c == 0) + break; + if (c >= 0xd800 && c < 0xdc00) { + c = (((c & 0x3ff) << 10) | ((*utf16) & 0x3ff)) + 0x10000; + ++utf16; + } + CodePoint cp(c); + cp.write(destination); + destination += cp.bytes(); + } + return destination; + } +#endif + AppendableArray _array; + const T* _start; + // Don't use _length, it's only there for size and alignment purposes. Use + // length() instead, which places the field at the end of the end of the + // class's memory in order to maximize small string space. + int _length; + + // These things create an uninitialized String of a known length and then + // write into it, something we only let our friends do (String is immutable + // to non-friends). + friend class ProgramBase; + template friend class FileT; + template friend class StreamT; + template friend class CurrentDirectoryT; + friend String format(const char* format, ...); +}; + +String operator*(int n, String a) { a *= n; return a; } + +String operator+(const char* a, const String& b) { return String(a, b); } +String operator+(const char* a, const String::Hex& b) { return String(a) + b; } +String operator+(const char* a, const String::Decimal& b) +{ + return String(a) + b; +} +String operator+(const char* a, const String::Boolean& b) +{ + return String(a) + b; +} +String operator+(const char* a, const String::CodePoint& b) +{ + return String(a) + b; +} +String operator+(const char* a, const String::Byte& b) +{ + return String(a) + b; +} + +String::Hex hex(int n, int digits = 8, bool ox = true) +{ + return String::Hex(n, digits, ox); +} + +String::Decimal decimal(int n, int w = 0) { return String::Decimal(n, w); } +String::CodePoint codePoint(int n) { return String::CodePoint(n); } + +String format(const char* format, ...) +{ + va_list args; + va_start(args, format); + int c = vsnprintf(0, 0, format, args) + 1; + String s(c); + vsnprintf(reinterpret_cast(s.data()), c, format, args); + return s.subString(0, s.length() - 1); // Discard trailing null byte +} + +template class StreamT; +typedef StreamT Stream; + +#ifdef _WIN32 +template class NullTerminatedWideStringT +{ +public: + NullTerminatedWideStringT(String s) + { + CharacterSourceT start(s); + CharacterSourceT cs = start; + int l = 1; + do { + int c = cs.get(); + if (c == -1) + break; + ++l; + if (c >= 0x10000) + ++l; + } while (true); + cs = start; + _buffer.allocate(l); + WCHAR* d = &_buffer[0]; + do { + int c = cs.get(); + if (c == -1) + break; + if (c >= 0x10000) { + c -= 0x10000; + *d = 0xd800 + ((c >> 10) & 0x03ff); + ++d; + *d = 0xdc00 + (c & 0x03ff); + ++d; + } + else { + *d = c; + ++d; + } + } while (true); + *d = 0; + } + operator WCHAR*() + { + return &_buffer[0]; + } +private: + Array _buffer; +}; + +typedef NullTerminatedWideStringT NullTerminatedWideString; +#endif + +class NullTerminatedString +{ +public: + NullTerminatedString(String s) : _s(s + codePoint(0)) { } + operator const char*() + { + return reinterpret_cast(&_s[0]); + } +private: + String _s; +}; + +#ifdef _WIN32 +class LocalString : Uncopyable +{ +public: + LocalString() : _str(NULL) { } + ~LocalString() { LocalFree(_str); } + LPWSTR* operator&() { return &_str; } + String string() { return String(_str); } + operator LPWSTR() { return _str; } +private: + LPWSTR _str; +}; +#endif + +#endif // INCLUDED_STRING_H diff --git a/80386/disassembler/include/alfe/string_functions.h b/80386/disassembler/include/alfe/string_functions.h new file mode 100644 index 0000000..91ef5ca --- /dev/null +++ b/80386/disassembler/include/alfe/string_functions.h @@ -0,0 +1,71 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_STRING_FUNCTIONS_H +#define INCLUDED_STRING_FUNCTIONS_H + +#include "alfe/function.h" + +class AddStringString : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + String l = i->value(); + ++i; + return Value(l + i->value()); + } + Identifier identifier() const { return OperatorPlus(); } + FunctionType type() const + { + return FunctionType(StringType(), StringType(), StringType()); + } + }; +}; + +class MultiplyIntegerString : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + int l = i->value(); + ++i; + return Value(l*i->value()); + } + Identifier identifier() const { return OperatorStar(); } + FunctionType type() const + { + return FunctionType(StringType(), IntegerType(), StringType()); + } + }; +}; + +class MultiplyStringInteger : public Nullary +{ +public: + class Body : public Nullary::Body + { + public: + Value evaluate(List arguments, Span span) const + { + auto i = arguments.begin(); + String l = i->value(); + ++i; + return Value(l*i->value()); + } + Identifier identifier() const { return OperatorStar(); } + FunctionType type() const + { + return FunctionType(StringType(), StringType(), IntegerType()); + } + }; +}; + +#endif // INCLUDED_STRING_FUNCTIONS_H diff --git a/80386/disassembler/include/alfe/structure.txt b/80386/disassembler/include/alfe/structure.txt new file mode 100644 index 0000000..2140f1b --- /dev/null +++ b/80386/disassembler/include/alfe/structure.txt @@ -0,0 +1,25 @@ +Use in DotBody and FunctionCallBody +include\alfe\expression.h: StructureTemplate* p = e. +include\alfe\expression.h: rValue().template value*>(); +include\alfe\expression.h: StructureTemplate* p = l.template +include\alfe\expression.h: value().rValue().template value(); + +Definition of Structure and use in LValue +include\alfe\type.h:template class StructureTemplate +include\alfe\type.h: LValueTemplate(Structure* structure, Identifier identifier) +include\alfe\type.h: Structure* _structure; + +Component is a Structure +berapa\berapa.cpp: Structure* s = value.value(); +berapa\berapa.cpp:template class ComponentTemplate : public Structure +berapa\berapa.cpp: Structure::set(name, value); +berapa\berapa.cpp: return Value(type(), static_cast(&(*v)), +berapa\berapa.cpp: Structure::set(Identifier(OperatorAssignment()), +berapa\berapa.cpp: Structure::set(name, p->getValue()); + +ConfigFile is a Structure +include\alfe\config_file.h:class ConfigFile : public Structure +include\alfe\config_file.h: Value value = ::empty(); +include\alfe\config_file.h: value.value()->set(Identifier("*"), +include\alfe\config_file.h: auto s = p.rValue().value(); + diff --git a/80386/disassembler/include/alfe/swap.h b/80386/disassembler/include/alfe/swap.h new file mode 100644 index 0000000..85ab34b --- /dev/null +++ b/80386/disassembler/include/alfe/swap.h @@ -0,0 +1,11 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_SWAP_H +#define INCLUDED_SWAP_H + +#include +//template void swap(T& x, T& y) { T z = x; x = y; y = z; } + +using std::swap; + +#endif // INCLUDED_SWAP_H diff --git a/80386/disassembler/include/alfe/symbol.h b/80386/disassembler/include/alfe/symbol.h new file mode 100644 index 0000000..0f5dfab --- /dev/null +++ b/80386/disassembler/include/alfe/symbol.h @@ -0,0 +1,605 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_SYMBOL_H +#define INCLUDED_SYMBOL_H + +#include +#include "alfe/linked_list.h" + +String quote(String string) +{ + CharacterSource s(string); + String r("\""); + int start = 0; + int end; + do { + int c = s.get(); + if (c == -1) { + end = s.offset(); + r += s.subString(start, end); + return r + "\""; + } + if (c == '"' || c == '\\') { + end = s.offset(); + r += s.subString(start, end) + "\\"; + start = end; + } + } while (true); +} + +int quotedLength(String string) +{ + CharacterSource s(string); + int r = 2; + do { + int c = s.get(); + if (c == -1) + return r; + if (c == '"' || c == '\\') + ++r; + ++r; + } while (true); +} + +int decimalLength(int v) +{ + int l = 1; + if (v < 0) { + ++l; + v = -v; + } + while (v > 9) { + ++l; + v /= 10; + } + return l; +} + +template class SymbolEntryT; +typedef SymbolEntryT SymbolEntry; + +template class SymbolT; +typedef SymbolT Symbol; + +template class SymbolArrayT; +typedef SymbolArrayT SymbolArray; + +template class SymbolLabelT; +typedef SymbolLabelT SymbolLabel; + +template class SymbolEntryT : public Handle +{ +public: + SymbolEntryT() { } + SymbolEntryT(int value) : Handle(new IntegerBody(value)) { } + SymbolEntryT(String value) : Handle(new StringBody(value)) { } + int integer() const + { + return as()->value(); + } + String string() const + { + return as()->value(); + } + SymbolArrayT array() + { + return SymbolArrayT(body()); + } + SymbolT symbol() + { + return SymbolT(dynamic_cast(body())); + } + SymbolLabelT label() + { + return SymbolLabelT(dynamic_cast(body())); + } + Atom atom() { return symbol().atom(); } + int length(int max) const { return body()->length(max); } + String toString(int width, int spacesPerIndent, int indent, int& x, + bool& more) const + { + return body()->toString(width, spacesPerIndent, indent, x, more); + } + String toString() const + { + int x; + bool more; + return toString(80, 2, 0, x, more); + } + bool isSymbol() const { return body()->isSymbol(); } + bool isArray() const { return body()->isArray(); } +protected: + class Body : public Handle::Body + { + public: + virtual int length(int max) const = 0; + virtual String toString(int width, int spacesPerIndent, int indent, + int& x, bool& more) const = 0; + virtual bool isSymbol() const = 0; + virtual bool isArray() const = 0; + }; + class IntegerBody : public Body + { + public: + IntegerBody(int value) : _value(value) { } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _value == o->_value; + } + String toString(int width, int spacesPerIndent, int indent, int& x, + bool& more) const + { + x += decimalLength(_value); + more = true; + return decimal(_value); + } + int length(int max) const { return decimalLength(_value); } + int value() const { return _value; } + Hash hash() const { return Body::hash().mixin(_value); } + bool isSymbol() const { return false; } + bool isArray() const { return false; } + private: + int _value; + }; + class StringBody : public Body + { + public: + StringBody(String value) : _value(value) { } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _value == o->_value; + } + String toString(int width, int spacesPerIndent, int indent, int& x, + bool& more) const + { + x += quotedLength(_value); + more = true; + return quote(_value); + } + int length(int max) const { return quotedLength(_value); } + String value() const { return _value; } + Hash hash() const { return Body::hash().mixin(_value.hash()); } + bool isSymbol() const { return false; } + bool isArray() const { return false; } + private: + String _value; + }; + SymbolEntryT(Body* body) : Handle(body) { } + const Body* body() const { return as(); } + Body* body() { return as; } +private: + template friend class SymbolT; + template friend class SymbolArrayT; +}; + +class SymbolTail : public Handle::Body +{ +public: + SymbolTail(SymbolEntry head) : _head(head) { } + SymbolTail(SymbolEntry head, SymbolTail* tail) : _head(head), _tail(tail) + { } + SymbolEntry head() const { return _head; } + SymbolEntry& head() { return _head; } + const SymbolTail* tail() const { return _tail; } + SymbolTail* tail() { return _tail; } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _head == o->_head && _tail == o->_tail; + } + int length(int max) const + { + int r = _head.length(max); + if (r < max && _tail.valid()) + r += _tail->length(max - r); + return r; + } +private: + SymbolEntry _head; + Reference _tail; +}; + +class SymbolCache : public ReferenceCounted +{ +}; + +template class SymbolT : public SymbolEntryT +{ +public: + SymbolT() { } + SymbolT(Atom atom, SymbolCache* cache = 0) + : SymbolEntry(new Body(atom, cache, 0)) { } + SymbolT(Atom atom, SymbolEntry symbol1, SymbolCache* cache = 0) + : SymbolEntry( + new Body(atom, cache, new SymbolTail(symbol1, 0))) { } + SymbolT(Atom atom, SymbolEntry symbol1, SymbolEntry symbol2, + SymbolCache* cache = 0) + : SymbolEntry(new Body(atom, cache, new SymbolTail(symbol1, + new SymbolTail(symbol2, 0)))) { } + SymbolT(Atom atom, SymbolEntry symbol1, SymbolEntry symbol2, + SymbolEntry symbol3, SymbolCache* cache = 0) + : SymbolEntry(new Body(atom, cache, new SymbolTail(symbol1, + new SymbolTail(symbol2, new SymbolTail(symbol3, 0))))) { } + SymbolT(Atom atom, SymbolEntry symbol1, SymbolEntry symbol2, + SymbolEntry symbol3, SymbolEntry symbol4, SymbolCache* cache = 0) + : SymbolEntry(new Body(atom, cache, new SymbolTail(symbol1, + new SymbolTail(symbol2, new SymbolTail(symbol3, + new SymbolTail(symbol4, 0)))))) { } + SymbolT(Atom atom, SymbolEntry symbol1, SymbolEntry symbol2, + SymbolEntry symbol3, SymbolEntry symbol4, SymbolEntry symbol5, + SymbolCache* cache = 0) + : SymbolEntry(new Body(atom, cache, new SymbolTail(symbol1, + new SymbolTail(symbol2, new SymbolTail(symbol3, + new SymbolTail(symbol4, new SymbolTail(symbol5, 0))))))) { } + + SymbolT(Atom atom, const SymbolTail* tail, SymbolCache* cache) + : SymbolEntry(new Body(atom, cache, tail)) { } + + Atom atom() const { return body()->atom(); } + SymbolEntry operator[](int n) const + { + const SymbolTail* t = tail(); + while (n > 1) { + if (t == 0) + return Symbol(); + --n; + t = t->tail(); + } + return t->head(); + } + + SymbolEntry& operator[](int n) + { + SymbolTail* t = tail(); + while (n > 1) { + if (t == 0) + throw Exception(String("Out of bounds access in to Symbol")); + --n; + t = t->tail(); + } + return t->head(); + } + + const SymbolTail* tail() const { return body()->tail(); } + SymbolTail* tail() { return body()->tail(); } + + template U* cache() + { + return body()->cache()->cast(); + } +private: + SymbolT(Body* body) + : SymbolEntry(body) { } + + class Body : public SymbolEntry::Body + { + public: + Body(Atom atom, SymbolCache* cache, SymbolTail* tail) + : _atom(atom), _cache(cache), _tail(tail), _labelReferences(0), + _labelNumber(-1) + { } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _atom == o->_atom && _tail == o->_tail; + } + int length(int max) const + { + int r = 2 + atomToString(_atom).length(); + if (_labelReferences > 0) + r += 1 + decimalLength(label()); + if (r < max && _tail.valid()) { + ++r; + r += _tail->length(max - r); + } + return r; + } + + String toString(int width, int spacesPerIndent, int indent, int& x, + bool& more) const + { + ++x; + more = true; + String s("("); + if (_labelReferences > 0) { + s = decimal(label()) + ":" + s; + x += 1 + decimalLength(label()); + } + String a = atomToString(_atom); + x += a.length(); + s += a; + bool canInlineNext = true; + more = true; + + const SymbolTail* tail = _tail; + while (tail != 0) { + SymbolEntry entry = tail->head(); + if (canInlineNext && x + 1 + entry.length(width - x) <= + width - 1) { + // Fits on the line - inline it + s += " "; + ++x; + } + else { + // Doesn't fit on the line - put it on its own line. + s += "\n" + String(" ")*(indent + 2); + x = indent + 2; + more = false; + } + s += entry.toString(width, spacesPerIndent, indent + 2, x, + canInlineNext); + tail = tail->tail(); + } + ++x; + return s + ")"; + } + + Atom atom() const { return _atom; } + + SymbolCache* cache() { return _cache; } + const SymbolTail* tail() const { return _tail; } + SymbolTail* tail() { return _tail; } + + void setCache(Reference cache) { _cache = cache; } + + Hash hash() const + { + Hash h = SymbolEntry::Body::hash().mixin(atom()); + const SymbolTail* t = _tail; + while (t != 0) { + h.mixin(t->head().hash()); + t = t->tail(); + } + return h; + } + bool isSymbol() const { return true; } + bool isArray() const { return false; } + + int label() const + { + if (_labelNumber == -1) { + _labelNumber = _labels; + ++_labels; + } + return _labelNumber; + } + int addLabel() { ++_labelReferences; } + int removeLabel() { --_labelReferences; } + private: + Atom _atom; + Reference _tail; + Reference _cache; + mutable int _labelNumber; + int _labelReferences; + + static int _labels; + }; + + const Body* body() const { return as(); } + Body* body() { return as(); } + + template friend class SymbolEntryT; + template friend class SymbolT; + template friend class SymbolArrayT; + template friend class SymbolLabelT; +}; + +int Symbol::Body::_labels = 0; + +class SymbolList +{ +public: + SymbolList() : _count(0) { } + void add(Symbol symbol) + { + _first = new Body(symbol, _first); + if (_count == 0) + _last = _first; + ++_count; + } + void add(SymbolList list) + { + _first = list._last; + _count += list._count; + } +private: + class Body : public ReferenceCounted + { + public: + Body(Symbol symbol, Reference next) + : _symbol(symbol), _next(next) { } + Symbol symbol() const { return _symbol; } + Reference next() const { return _next; } + private: + Symbol _symbol; + Reference _next; + }; + Reference _first; + Reference _last; + int _count; + + void copyTo(Array* symbols) + { + symbols->allocate(_count); + Reference body = _first; + for (int i = _count - 1; i >= 0; --i) { + (*symbols)[i] = body->symbol(); + body = body->next(); + } + } + + template friend class SymbolArrayT; +}; + +template class SymbolArrayT : public SymbolEntry +{ +public: + SymbolArrayT() : SymbolEntry(_empty) { } + SymbolArrayT(Symbol s1) : SymbolEntry(new Body(s1)) { } + SymbolArrayT(Symbol s1, Symbol s2) + : SymbolEntry(new Body(s1, s2)) { } + SymbolArrayT(SymbolList list) + : SymbolEntry(new Body(list)) { } + int count() const + { + return body()->count(); + } + Symbol operator[](int i) + { + return (*body())[i]; + } +private: + SymbolArrayT(Body* body) + : SymbolEntry(body) { } + + class Body : public SymbolEntry::Body + { + public: + Body(SymbolList list) { list.copyTo(&_symbols); } + Body() + { + _symbols.allocate(0); + } + Body(Symbol s0) + { + _symbols.allocate(1); + _symbols[0] = s0; + } + Body(Symbol s0, Symbol s1) + { + _symbols.allocate(2); + _symbols[0] = s0; + _symbols[1] = s1; + } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _symbols == o->_symbols; + } + Hash hash() const + { + Hash h = SymbolEntry::Body::hash(); + for (int i = 0; i < _symbols.count(); ++i) + h.mixin(_symbols[i].hash()); + return h; + } + int length(int max) const + { + int r = 2; + for (int i = 0; i < _symbols.count(); ++i) { + if (r > max) + break; + if (i != 0) + ++r; + r += _symbols[i].length(max - r); + } + return r; + } + int count() const { return _symbols.count(); } + Symbol operator[](int i) const { return _symbols[i]; } + Symbol& operator[](int i) { return _symbols[i]; } + String toString(int width, int spacesPerIndent, int indent, int& x, + bool& more) const + { + ++x; + int n = _symbols.count(); + more = true; + if (n == 0) { + ++x; + return "[]"; + } + + bool canInlineNext; + String s = "[" + _symbols[0].toString(width, + spacesPerIndent, indent + 2, x, canInlineNext); + + for (int i = 1; i < n; ++i) { + Symbol symbol = _symbols[i]; + if (canInlineNext && x + 1 + symbol.length(width - x) <= + width - 1) { + // Fits on the line - inline it + s += " "; + ++x; + } + else { + // Doesn't fit on the line - put it on its own line. + s += "\n" + String(" ")*(indent + 2); + x = indent + 2; + more = false; + } + s += symbol.toString(width, spacesPerIndent, indent + 2, x, + canInlineNext); + } + ++x; + return s + "]"; + } + bool isSymbol() const { return false; } + bool isArray() const { return true; } + private: + Array _symbols; + }; + static Reference _empty; + + template friend class SymbolEntryT; +}; + +Reference SymbolArray::_empty = + new SymbolArray::Body(); + +template class SymbolLabelT : public SymbolEntry +{ +public: + SymbolLabelT() { } + SymbolLabelT(Symbol target) : _body(new Body(target._body)) { } + Symbol target() { return Symbol(_body->target()); } + void setTarget(Symbol target) + { + _body->setTarget(target._body); + } +private: + class Body : public SymbolEntry::Body + { + public: + Body(Symbol::Body* target) : _target(target) + { + _target->addLabel(); + } + ~Body() { _target->removeLabel(); } + Symbol::Body* target() { return _target; } + void setTarget(Symbol::Body* target) + { + _target->removeLabel(); + _target = target; + _target->addLabel(); + } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _target == o->_target; + } + int length(int max) const + { + return 2 + decimalLength(_target->label()); + } + String toString(int width, int spacesPerIndent, int indent, int& x, + bool& more) const + { + x += length(); + more = true; + return "<" + decimal(_target->label()) + ">"; + } + Hash hash() const + { + return SymbolEntry::Body::hash(). + mixin(reinterpret_cast(_target)); + } + bool isSymbol() const { return false; } + bool isArray() const { return false; } + private: + Symbol::Body* _target; + }; +}; + +#endif // INCLUDED_SYMBOL_H diff --git a/80386/disassembler/include/alfe/terminal6.h b/80386/disassembler/include/alfe/terminal6.h new file mode 100644 index 0000000..b79c6ca --- /dev/null +++ b/80386/disassembler/include/alfe/terminal6.h @@ -0,0 +1,264 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_TERMINAL6_H +#define INCLUDED_TERMINAL6_H + +UInt8 glyphs[0x100*8]={ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x44, 0x6C, 0x44, 0x54, 0x44, 0x38, 0x00, + 0x38, 0x7C, 0x54, 0x7C, 0x44, 0x7C, 0x38, 0x00, + 0x00, 0x28, 0x7C, 0x7C, 0x7C, 0x38, 0x10, 0x00, + 0x00, 0x10, 0x38, 0x7C, 0x7C, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x38, 0x10, 0x7C, 0x7C, 0x10, 0x00, + 0x00, 0x10, 0x38, 0x7C, 0x7C, 0x10, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, + 0xFC, 0xFC, 0xFC, 0xCC, 0xCC, 0xFC, 0xFC, 0xFC, + 0x00, 0x00, 0x78, 0x48, 0x48, 0x78, 0x00, 0x00, + 0xFC, 0xFC, 0x84, 0xB4, 0xB4, 0x84, 0xFC, 0xFC, + 0x00, 0x1C, 0x0C, 0x34, 0x48, 0x48, 0x30, 0x00, + 0x38, 0x44, 0x44, 0x38, 0x10, 0x38, 0x10, 0x00, + 0x10, 0x18, 0x14, 0x10, 0x30, 0x70, 0x60, 0x00, + 0x0C, 0x34, 0x2C, 0x34, 0x2C, 0x6C, 0x60, 0x00, + 0x00, 0x54, 0x38, 0x6C, 0x38, 0x54, 0x00, 0x00, + 0x20, 0x30, 0x38, 0x3C, 0x38, 0x30, 0x20, 0x00, + 0x08, 0x18, 0x38, 0x78, 0x38, 0x18, 0x08, 0x00, + 0x10, 0x38, 0x7C, 0x10, 0x7C, 0x38, 0x10, 0x00, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x28, 0x00, + 0x3C, 0x54, 0x54, 0x34, 0x14, 0x14, 0x14, 0x00, + 0x38, 0x44, 0x30, 0x28, 0x18, 0x44, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x78, 0x00, + 0x10, 0x38, 0x7C, 0x10, 0x7C, 0x38, 0x10, 0x38, + 0x10, 0x38, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x7C, 0x38, 0x10, 0x00, + 0x00, 0x10, 0x18, 0x7C, 0x18, 0x10, 0x00, 0x00, + 0x00, 0x10, 0x30, 0x7C, 0x30, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7C, 0x00, + 0x00, 0x28, 0x28, 0x7C, 0x28, 0x28, 0x00, 0x00, + 0x10, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0x00, 0x00, + 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x38, 0x10, 0x10, 0x00, 0x10, 0x00, + 0x6C, 0x6C, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x28, 0x7C, 0x28, 0x28, 0x7C, 0x28, 0x00, + 0x20, 0x38, 0x40, 0x30, 0x08, 0x70, 0x10, 0x00, + 0x64, 0x64, 0x08, 0x10, 0x20, 0x4C, 0x4C, 0x00, + 0x20, 0x50, 0x50, 0x20, 0x54, 0x48, 0x34, 0x00, + 0x30, 0x30, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x00, + 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, + 0x00, 0x28, 0x38, 0x7C, 0x38, 0x28, 0x00, 0x00, + 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x20, + 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, + 0x38, 0x44, 0x4C, 0x54, 0x64, 0x44, 0x38, 0x00, + 0x10, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, + 0x38, 0x44, 0x04, 0x18, 0x20, 0x40, 0x7C, 0x00, + 0x38, 0x44, 0x04, 0x38, 0x04, 0x44, 0x38, 0x00, + 0x08, 0x18, 0x28, 0x48, 0x7C, 0x08, 0x08, 0x00, + 0x7C, 0x40, 0x40, 0x78, 0x04, 0x44, 0x38, 0x00, + 0x18, 0x20, 0x40, 0x78, 0x44, 0x44, 0x38, 0x00, + 0x7C, 0x04, 0x08, 0x10, 0x20, 0x20, 0x20, 0x00, + 0x38, 0x44, 0x44, 0x38, 0x44, 0x44, 0x38, 0x00, + 0x38, 0x44, 0x44, 0x3C, 0x04, 0x08, 0x30, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x20, + 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, + 0x38, 0x44, 0x04, 0x18, 0x10, 0x00, 0x10, 0x00, + 0x38, 0x44, 0x5C, 0x54, 0x5C, 0x40, 0x38, 0x00, + 0x38, 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x00, + 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x78, 0x00, + 0x38, 0x44, 0x40, 0x40, 0x40, 0x44, 0x38, 0x00, + 0x78, 0x44, 0x44, 0x44, 0x44, 0x44, 0x78, 0x00, + 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x7C, 0x00, + 0x7C, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x00, + 0x38, 0x44, 0x40, 0x5C, 0x44, 0x44, 0x3C, 0x00, + 0x44, 0x44, 0x44, 0x7C, 0x44, 0x44, 0x44, 0x00, + 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, + 0x04, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00, + 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x00, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C, 0x00, + 0x44, 0x6C, 0x54, 0x44, 0x44, 0x44, 0x44, 0x00, + 0x44, 0x64, 0x54, 0x4C, 0x44, 0x44, 0x44, 0x00, + 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, + 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x00, + 0x38, 0x44, 0x44, 0x44, 0x54, 0x48, 0x34, 0x00, + 0x78, 0x44, 0x44, 0x78, 0x48, 0x44, 0x44, 0x00, + 0x38, 0x44, 0x40, 0x38, 0x04, 0x44, 0x38, 0x00, + 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, + 0x44, 0x44, 0x54, 0x54, 0x54, 0x54, 0x28, 0x00, + 0x44, 0x44, 0x28, 0x10, 0x28, 0x44, 0x44, 0x00, + 0x44, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x00, + 0x78, 0x08, 0x10, 0x20, 0x40, 0x40, 0x78, 0x00, + 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x00, + 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, + 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, + 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, + 0x30, 0x30, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, + 0x40, 0x40, 0x78, 0x44, 0x44, 0x44, 0x78, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x00, + 0x04, 0x04, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x78, 0x40, 0x38, 0x00, + 0x18, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x00, + 0x00, 0x00, 0x3C, 0x44, 0x44, 0x3C, 0x04, 0x38, + 0x40, 0x40, 0x70, 0x48, 0x48, 0x48, 0x48, 0x00, + 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x18, 0x00, + 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x48, 0x30, + 0x40, 0x40, 0x48, 0x50, 0x60, 0x50, 0x48, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x00, + 0x00, 0x00, 0x68, 0x54, 0x54, 0x44, 0x44, 0x00, + 0x00, 0x00, 0x70, 0x48, 0x48, 0x48, 0x48, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, + 0x00, 0x00, 0x78, 0x44, 0x44, 0x44, 0x78, 0x40, + 0x00, 0x00, 0x3C, 0x44, 0x44, 0x44, 0x3C, 0x04, + 0x00, 0x00, 0x58, 0x24, 0x20, 0x20, 0x70, 0x00, + 0x00, 0x00, 0x38, 0x40, 0x38, 0x04, 0x38, 0x00, + 0x00, 0x20, 0x78, 0x20, 0x20, 0x28, 0x10, 0x00, + 0x00, 0x00, 0x48, 0x48, 0x48, 0x58, 0x28, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x10, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x54, 0x7C, 0x28, 0x00, + 0x00, 0x00, 0x48, 0x48, 0x30, 0x48, 0x48, 0x00, + 0x00, 0x00, 0x48, 0x48, 0x48, 0x38, 0x10, 0x60, + 0x00, 0x00, 0x78, 0x08, 0x30, 0x40, 0x78, 0x00, + 0x18, 0x20, 0x20, 0x60, 0x20, 0x20, 0x18, 0x00, + 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x00, + 0x30, 0x08, 0x08, 0x0C, 0x08, 0x08, 0x30, 0x00, + 0x28, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6C, 0x44, 0x44, 0x7C, 0x00, 0x00, + 0x38, 0x44, 0x40, 0x40, 0x44, 0x38, 0x10, 0x30, + 0x48, 0x00, 0x48, 0x48, 0x48, 0x58, 0x28, 0x00, + 0x0C, 0x00, 0x38, 0x44, 0x78, 0x40, 0x38, 0x00, + 0x38, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, + 0x28, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, + 0x30, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, + 0x38, 0x28, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, + 0x00, 0x38, 0x44, 0x40, 0x44, 0x38, 0x10, 0x30, + 0x38, 0x00, 0x38, 0x44, 0x78, 0x40, 0x38, 0x00, + 0x28, 0x00, 0x38, 0x44, 0x78, 0x40, 0x38, 0x00, + 0x30, 0x00, 0x38, 0x44, 0x78, 0x40, 0x38, 0x00, + 0x28, 0x00, 0x10, 0x10, 0x10, 0x10, 0x18, 0x00, + 0x10, 0x28, 0x00, 0x10, 0x10, 0x10, 0x18, 0x00, + 0x20, 0x00, 0x10, 0x10, 0x10, 0x10, 0x18, 0x00, + 0x28, 0x00, 0x10, 0x28, 0x44, 0x7C, 0x44, 0x00, + 0x38, 0x28, 0x38, 0x6C, 0x44, 0x7C, 0x44, 0x00, + 0x0C, 0x00, 0x7C, 0x40, 0x78, 0x40, 0x7C, 0x00, + 0x00, 0x00, 0x78, 0x14, 0x7C, 0x50, 0x3C, 0x00, + 0x3C, 0x50, 0x50, 0x7C, 0x50, 0x50, 0x5C, 0x00, + 0x38, 0x00, 0x30, 0x48, 0x48, 0x48, 0x30, 0x00, + 0x28, 0x00, 0x30, 0x48, 0x48, 0x48, 0x30, 0x00, + 0x60, 0x00, 0x30, 0x48, 0x48, 0x48, 0x30, 0x00, + 0x38, 0x00, 0x48, 0x48, 0x48, 0x58, 0x28, 0x00, + 0x60, 0x00, 0x48, 0x48, 0x48, 0x58, 0x28, 0x00, + 0x28, 0x00, 0x48, 0x48, 0x48, 0x38, 0x10, 0x60, + 0x48, 0x30, 0x48, 0x48, 0x48, 0x48, 0x30, 0x00, + 0x28, 0x00, 0x48, 0x48, 0x48, 0x48, 0x30, 0x00, + 0x00, 0x10, 0x38, 0x40, 0x40, 0x38, 0x10, 0x00, + 0x18, 0x24, 0x20, 0x78, 0x20, 0x24, 0x5C, 0x00, + 0x44, 0x28, 0x10, 0x7C, 0x10, 0x7C, 0x10, 0x00, + 0x60, 0x50, 0x50, 0x68, 0x5C, 0x48, 0x48, 0x00, + 0x08, 0x14, 0x10, 0x38, 0x10, 0x10, 0x50, 0x20, + 0x18, 0x00, 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, + 0x18, 0x00, 0x10, 0x10, 0x10, 0x10, 0x18, 0x00, + 0x18, 0x00, 0x30, 0x48, 0x48, 0x48, 0x30, 0x00, + 0x18, 0x00, 0x48, 0x48, 0x48, 0x58, 0x28, 0x00, + 0x28, 0x50, 0x00, 0x70, 0x48, 0x48, 0x48, 0x00, + 0x28, 0x50, 0x00, 0x48, 0x68, 0x58, 0x48, 0x00, + 0x38, 0x04, 0x3C, 0x44, 0x3C, 0x00, 0x3C, 0x00, + 0x30, 0x48, 0x48, 0x48, 0x30, 0x00, 0x78, 0x00, + 0x10, 0x00, 0x10, 0x30, 0x40, 0x44, 0x38, 0x00, + 0x00, 0x00, 0x7C, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x04, 0x04, 0x00, 0x00, 0x00, + 0x40, 0x48, 0x50, 0x38, 0x44, 0x08, 0x1C, 0x00, + 0x40, 0x48, 0x50, 0x2C, 0x54, 0x1C, 0x04, 0x00, + 0x10, 0x00, 0x10, 0x10, 0x38, 0x38, 0x10, 0x00, + 0x00, 0x00, 0x24, 0x48, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x48, 0x24, 0x48, 0x00, 0x00, 0x00, + 0x54, 0x00, 0xA8, 0x00, 0x54, 0x00, 0xA8, 0x00, + 0x54, 0xA8, 0x54, 0xA8, 0x54, 0xA8, 0x54, 0xA8, + 0xA8, 0xFC, 0x54, 0xFC, 0xA8, 0xFC, 0x54, 0xFC, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, 0x10, 0x10, 0x10, + 0x10, 0xF0, 0x10, 0xF0, 0x10, 0x10, 0x10, 0x10, + 0x50, 0x50, 0x50, 0xD0, 0x50, 0x50, 0x50, 0x50, + 0x00, 0x00, 0x00, 0xF0, 0x50, 0x50, 0x50, 0x50, + 0x00, 0xF0, 0x10, 0xF0, 0x10, 0x10, 0x10, 0x10, + 0x50, 0xD0, 0x10, 0xD0, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x00, 0xF0, 0x10, 0xD0, 0x50, 0x50, 0x50, 0x50, + 0x50, 0xD0, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x50, 0x50, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x1C, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0xFC, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x1C, 0x10, 0x1C, 0x10, 0x10, 0x10, 0x10, + 0x50, 0x50, 0x50, 0x5C, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x5C, 0x40, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7C, 0x40, 0x5C, 0x50, 0x50, 0x50, 0x50, + 0x50, 0xDC, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFC, 0x00, 0xDC, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x5C, 0x40, 0x5C, 0x50, 0x50, 0x50, 0x50, + 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x50, 0xDC, 0x00, 0xDC, 0x50, 0x50, 0x50, 0x50, + 0x10, 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x50, 0x50, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFC, 0x00, 0xFC, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0xFC, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x7C, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x1C, 0x10, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1C, 0x10, 0x1C, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x7C, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0xDC, 0x50, 0x50, 0x50, 0x50, + 0x10, 0xFC, 0x00, 0xFC, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x10, 0x10, 0x10, 0x10, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xFC, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0xFC, 0xFC, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x34, 0x48, 0x48, 0x34, 0x00, 0x00, + 0x00, 0x70, 0x48, 0x70, 0x48, 0x48, 0x70, 0x40, + 0x78, 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x7C, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, + 0x78, 0x48, 0x20, 0x10, 0x20, 0x48, 0x78, 0x00, + 0x00, 0x00, 0x3C, 0x48, 0x48, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x48, 0x48, 0x48, 0x70, 0x40, 0x40, + 0x00, 0x00, 0x28, 0x50, 0x10, 0x10, 0x10, 0x00, + 0x38, 0x10, 0x38, 0x44, 0x38, 0x10, 0x38, 0x00, + 0x30, 0x48, 0x48, 0x78, 0x48, 0x48, 0x30, 0x00, + 0x00, 0x38, 0x44, 0x44, 0x28, 0x28, 0x6C, 0x00, + 0x30, 0x40, 0x20, 0x10, 0x38, 0x48, 0x30, 0x00, + 0x00, 0x00, 0x28, 0x54, 0x54, 0x28, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x54, 0x54, 0x38, 0x10, 0x00, + 0x00, 0x38, 0x40, 0x78, 0x40, 0x38, 0x00, 0x00, + 0x00, 0x30, 0x48, 0x48, 0x48, 0x48, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x10, 0x00, 0x38, 0x00, 0x00, + 0x40, 0x30, 0x08, 0x30, 0x40, 0x00, 0x78, 0x00, + 0x08, 0x30, 0x40, 0x30, 0x08, 0x00, 0x78, 0x00, + 0x00, 0x08, 0x14, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x50, 0x20, 0x00, + 0x00, 0x10, 0x00, 0x7C, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x28, 0x50, 0x00, 0x28, 0x50, 0x00, 0x00, + 0x30, 0x48, 0x48, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1C, 0x10, 0x10, 0x50, 0x50, 0x20, 0x00, + 0x50, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x10, 0x20, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +#endif // INCLUDED_TERMINAL6_H diff --git a/80386/disassembler/include/alfe/thread.h b/80386/disassembler/include/alfe/thread.h new file mode 100644 index 0000000..4a09cba --- /dev/null +++ b/80386/disassembler/include/alfe/thread.h @@ -0,0 +1,406 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_THREAD_H +#define INCLUDED_THREAD_H + +#include "alfe/windows_handle.h" +#include "alfe/linked_list.h" + +class Event : public WindowsHandle +{ +public: + Event(bool manualReset = false) + { + HANDLE handle = CreateEvent(NULL, manualReset ? TRUE : FALSE, FALSE, + NULL); + IF_NULL_THROW(handle); + *this = handle; + } + Event(HANDLE handle) : WindowsHandle(handle) { } + void signal() { IF_ZERO_THROW(SetEvent(*this)); } + bool wait(DWORD time = INFINITE) + { + DWORD r = WaitForSingleObject(*this, time); + if (r == 0) + return true; + IF_FALSE_THROW(r == WAIT_TIMEOUT); + return false; + } + void reset() { IF_ZERO_THROW(ResetEvent(*this)); } +}; + +class Thread : Uncopyable +{ +public: + Thread() : _started(false), _error(false) + { + HANDLE handle = CreateThread( + NULL, 0, threadStaticProc, this, CREATE_SUSPENDED, NULL); + IF_NULL_THROW(handle); + _handle = handle; + } + ~Thread() { noFailJoin(); } + void setPriority(int nPriority) + { + IF_ZERO_THROW(SetThreadPriority(_handle, nPriority)); + } + void noFailJoin() + { + if (!_started) + return; + _started = false; + WaitForSingleObject(_handle, INFINITE); + } + void join() + { + if (!_started) + return; + _started = false; + IF_FALSE_THROW( + WaitForSingleObject(_handle, INFINITE) == WAIT_OBJECT_0); + if (_error) + throw _exception; + } + void start() { IF_MINUS_ONE_THROW(ResumeThread(_handle)); } + +private: + static DWORD WINAPI threadStaticProc(LPVOID lpParameter) + { + reinterpret_cast(lpParameter)->process(); + return 0; + } + void process() + { + _started = true; + BEGIN_CHECKED { + threadProc(); + } END_CHECKED(Exception& e) { + _exception = e; + _error = true; + } + } + + virtual void threadProc() = 0; + + bool _started; + bool _error; + Exception _exception; + WindowsHandle _handle; +}; + +class Mutex : Uncopyable +{ +public: + Mutex() { InitializeCriticalSection(&_cs); } + ~Mutex() { DeleteCriticalSection(&_cs); } + void lock() { EnterCriticalSection(&_cs); } + void unlock() { LeaveCriticalSection(&_cs); } + bool tryLock() { return TryEnterCriticalSection(&_cs) != 0; } +private: + CRITICAL_SECTION _cs; +}; + +class Lock : Uncopyable +{ +public: + Lock() : _mutex(0) { } + Lock(Mutex* mutex) : _mutex(mutex) { _mutex->lock(); } + + ~Lock() + { + if (_mutex) + _mutex->unlock(); + } + + bool tryAcquire(Mutex* mutex) + { + if (mutex->tryLock()) { + _mutex = mutex; + return true; + } + return false; + } + +private: + Mutex* _mutex; +}; + +class ThreadPool; + +template class TaskT; +typedef TaskT Task; + +template class TaskThreadT; +typedef TaskThreadT TaskThread; + +template class TaskT : public LinkedListMember +{ +public: + TaskT() : _state(completed), _threadPool(0) { } + ~TaskT() { join(); } + void setPool(ThreadPool* threadPool) + { + _threadPool = threadPool; + _threadPool->addCompleted(this); + } + + void removeFromPool() { _threadPool = 0; } + + // Cancel task and remove from pool as quickly as possible. + void cancel() { _threadPool->cancel(this); } + + // Wait for task to complete. + void join() + { + if (_threadPool != 0) + _threadPool->join(this); + } + + // If task is not running, start it. If task is running, cancel it and then + // start it again. + void restart() { _threadPool->restart(this); } + + // Same as restart(), but waits for previous instance of the task to stop + // running before continuing. + void restartSynchronous() { _threadPool->restartSynchronous(this); } + +protected: + bool cancelling() { return _threadPool->cancelling(this); } +private: + virtual void run() = 0; + + ThreadPool* _threadPool; + TaskThread* _thread; + enum State { + waiting, + running, + cancelPending, + restartPending, + completed + }; + State _state; + + template friend class TaskThreadT; + friend class ThreadPool; +}; + +template class TaskThreadT : public Thread +{ +public: + TaskThreadT() : _next(0) { } +private: + void go() { _go.signal(); } + void threadProc() + { + do { + _go.wait(); + if (_task == 0) + return; + _task->run(); + _threadPool->taskCompleted(this); + } while (true); + } + + TaskThread* _next; + ThreadPool* _threadPool; + Task* _task; + Event _go; + friend class ThreadPool; +}; + +class ThreadPool : Uncopyable +{ +public: + ThreadPool(int threads = 0) + { + if (threads == 0) { + // Count available threads + DWORD_PTR pam, sam; + IF_ZERO_THROW( + GetProcessAffinityMask(GetCurrentProcess(), &pam, &sam)); + for (DWORD_PTR p = 1; p != 0; p <<= 1) + if ((pam&p) != 0) + ++threads; + } + _threads.allocate(threads); + for (int i = 0; i < threads; ++i) { + _threads[i]._threadPool = this; + startTask(&_threads[i], 0); + _threads[i].start(); + } + } + ~ThreadPool() + { + // Wait until queue is empty and all threads are idle. + do { + { + Lock lock(&_mutex); + int i; + for (i = 0; i < _threads.count(); ++i) { + if (_threads[i]._task != 0) + break; + } + if (i == _threads.count()) + break; + } + _done.wait(); + } while (true); + // End all the threads + for (int i = 0; i < _threads.count(); ++i) { + _threads[i].go(); + _threads[i].join(); + } + } + + // Removes all queued tasks and cancels all running tasks, + void abandon() + { + Lock lock(&_mutex); + // Can't use a range-based for loop here because we're + // removing items and continuing. + auto t = _waiting.next(); + while (t != &_waiting) { + auto next = t->next(); + t->remove(); + t = next; + } + for (int i = 0; i < _threads.count(); ++i) { + Task* task = _threads[i]._task; + if (task != 0) + task->_state = Task::cancelPending; + } + } + + // Waits for task to complete. + void join(Task* task) + { + do { + { + Lock lock(&_mutex); + if (task->_state == Task::completed) + return; + } + _done.wait(); + } while (true); + } + + void restart(Task* task) + { + Lock lock(&_mutex); + if (task->_state == Task::completed) { + task->remove(); + addNoLock(task); + } + else { + if (task->_state != Task::waiting) + task->_state = Task::restartPending; + } + } + + void restartSynchronous(Task* task) + { + restart(task); + do { + { + Lock lock(&_mutex); + if (task->_state != Task::restartPending) + return; + } + _done.wait(); + } while (true); + } + + void cancel(Task* task) + { + Lock lock(&_mutex); + if (task->_state == Task::waiting) + task->remove(); + else { + if (task->_state != Task::completed) + task->_state = Task::cancelPending; + } + } + + bool cancelling(Task* task) + { + Lock lock(&_mutex); + return task->_state == Task::cancelPending || + task->_state == Task::restartPending; + } + + // Called by thread when it has completed its task + void taskCompleted(TaskThread* thread) + { + Lock lock(&_mutex); + Task* task = thread->_task; + if (task->_state != task->Task::restartPending) { + task->_state = Task::completed; + _completed.add(task); + task = _waiting.getNext(); + if (task != 0) + task->remove(); + } + startTask(thread, task); + } + + Task* getCompletedTask() + { + Lock lock(&_mutex); + Task* task = _completed.getNext(); + if (task != 0) + task->remove(); + return task; + } + + void setPriority(int nPriority) + { + for (int i = 0; i < _threads.count(); ++i) + _threads[i].setPriority(nPriority); + } + + void addCompleted(Task* task) { _completed.add(task); } +private: + void addNoLock(Task* task) + { + TaskThread* thread = _idle; + if (thread == 0) { + _waiting.add(task); + return; + } + _idle = thread->_next; + startTask(thread, task); + } + void startTask(TaskThread* thread, Task* task) + { + thread->_task = task; + if (task == 0) { + thread->_next = _idle; + _idle = thread; + } + else { + task->_state = Task::running; + thread->go(); + } + _done.signal(); + } + + TaskThread* _idle; + Mutex _mutex; + Event _done; + LinkedList _waiting; + LinkedList _completed; + Array _threads; +}; + +// A ThreadTask has a single thread all to itself. +class ThreadTask : public Task +{ +public: + ThreadTask() : _threadPool(1) { setPool(&_threadPool); } + ~ThreadTask() { removeFromPool(); } + void setPriority(int nPriority) { _threadPool.setPriority(nPriority); } +private: + ThreadPool _threadPool; +}; + +#endif // INCLUDED_THREAD_H diff --git a/80386/disassembler/include/alfe/timer.h b/80386/disassembler/include/alfe/timer.h new file mode 100644 index 0000000..eba3a65 --- /dev/null +++ b/80386/disassembler/include/alfe/timer.h @@ -0,0 +1,47 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_TIMER_H +#define INCLUDED_TIMER_H + +#include + +class Timer +{ +public: + Timer() + { + QueryPerformanceCounter(&_startTime); + } + void output(String caption) + { + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + time.QuadPart -= _startTime.QuadPart; + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + console.write(caption + ": " + decimal(static_cast( + (time.QuadPart*1000000)/frequency.QuadPart)) + + " microseconds\n"); + //printf("%lf us\n",time.QuadPart*1000000.0/frequency.QuadPart); + } +private: + LARGE_INTEGER _startTime; +}; + +//class Timer +//{ +//public: +// Timer() +// { +// _ms = timeGetTime(); +// } +// void output(String caption) +// { +// DWORD ms = timeGetTime(); +// printf("%i ms\n",ms - _ms); +// } +//private: +// DWORD _ms; +//}; + +#endif // INCLUDED_TIMER_H diff --git a/80386/disassembler/include/alfe/tuple.h b/80386/disassembler/include/alfe/tuple.h new file mode 100644 index 0000000..e74a57b --- /dev/null +++ b/80386/disassembler/include/alfe/tuple.h @@ -0,0 +1,20 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_TUPLE_H +#define INCLUDED_TUPLE_H + +template class Tuple +{ +public: + Tuple() { } + Tuple(const T1& t1, const T2& t2) : _t1(t1), _t2(t2) { } + const T1& first() const { return _t1; } + const T2& second() const { return _t2; } + T1& first() { return _t1; } + T2& second() { return _t2; } +private: + T1 _t1; + T2 _t2; +}; + +#endif // INCLUDED_TUPLE_H diff --git a/80386/disassembler/include/alfe/type.h b/80386/disassembler/include/alfe/type.h new file mode 100644 index 0000000..fc98de5 --- /dev/null +++ b/80386/disassembler/include/alfe/type.h @@ -0,0 +1,2081 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_TYPE_H +#define INCLUDED_TYPE_H + +template class TemplateT; +typedef TemplateT Template; + +template class TypeT; +typedef TypeT Type; + +template class PointerTypeT; +typedef PointerTypeT PointerType; + +template class FunctionTypeT; +typedef FunctionTypeT FunctionType; + +template class FunctionTemplateT; +typedef FunctionTemplateT FunctionTemplate; + +template class VoidTypeT; +typedef VoidTypeT VoidType; + +template class TupleTycoT; +typedef TupleTycoT TupleTyco; + +template class StringTypeT; +typedef StringTypeT StringType; + +template class IntegerTypeT; +typedef IntegerTypeT IntegerType; + +template class RationalTypeT; +typedef RationalTypeT RationalType; + +#include "alfe/any.h" +#include "alfe/hash_table.h" +#include "alfe/nullary.h" +#include "alfe/kind.h" +#include "alfe/assert.h" +#include "alfe/identifier.h" +#include "alfe/vectors.h" +#include "alfe/rational.h" +#include "alfe/reference.h" +#include "alfe/statement.h" +#include + +template class ValueT; +typedef ValueT Value; + +template class TycoT; +typedef TycoT Tyco; + +template class IdentifierT; +typedef IdentifierT Identifier; + +template class LValueTypeT; +typedef LValueTypeT LValueType; + +template class StructuredTypeT; +typedef StructuredTypeT StructuredType; + +template class BooleanTypeT; +typedef BooleanTypeT BooleanType; + +template class TycoT : public Handle +{ +public: + TycoT() { } + TycoT(const Handle& other) : Handle(other) { } + String toString() const { return body()->toString(); } + Kind kind() const { return body()->kind(); } +protected: + class Body : public Handle::Body + { + public: + virtual String toString() const = 0; + virtual Kind kind() const = 0; + Tyco tyco() const { return handle(); } + }; +private: + const Body* body() const { return as(); } + + friend class TemplateT; + template friend class EnumerationType; + template friend class StructuredTypeT; +}; + +template class StructureT; +typedef StructureT Structure; + +class StructureOwner +{ +public: + void addOwned(Reference structure) { _owned.add(structure); } +private: + List> _owned; +}; + +template class StructureT +{ +public: + template U get(Identifier identifier) const + { + Value v = getValue(identifier); + StructuredType t(v.type().rValue()); + if (t.valid()) + return t.rValueFromLValue(v).template value(); + return v.template value(); + } + virtual ValueT getValue(Identifier identifier) const + { + return _values[identifier]; + } + bool has(Identifier identifier) const + { + return _values.hasKey(identifier); + } + virtual void set(Identifier identifier, ValueT value, Span span) + { + _values[identifier] = value; + } + HashTable::Iterator begin() const + { + return _values.begin(); + } + HashTable::Iterator end() const + { + return _values.end(); + } +private: + HashTable _values; +}; + +template class ScopeT; +typedef ScopeT Scope; + +template class ScopeT +{ +public: + ScopeT() : _parent(0), _functionScope(this) { } + void addType(TypeT type, TycoIdentifier identifier = TycoIdentifier()) + { + if (!identifier.valid()) + identifier = TycoIdentifier(type.toString()); + _tycos.add(identifier, type); + } + void addObject(Identifier i, VariableDefinition s) + { + _objects[i] = s; + } + void addFunction(Identifier i, FuncoT f) + { + if (_functionScope == this) { + if (_functions.hasKey(i)) + _functions[i].add(f); + else { + List l; + l.add(f); + _functions.add(i, l); + } + } + else + _functionScope->addFunction(i, f); + } + //ValueT valueOfIdentifier(Identifier i) + //{ + // Span s = i.span(); + // if (!_objects.has(i)) + // s.throwError("Unknown identifier " + i.toString()); + // return Value(LValueType::wrap(getValue(i).type()), LValue(this, i), s); + //} + Tyco resolveTycoIdentifier(TycoIdentifier i) const + { + String s = i.name(); + if (!_tycos.hasKey(s)) + return Tyco(); + return _tycos[s]; + } + Tyco resolveTycoSpecifier(TycoSpecifier s) const + { + return s.resolve(this); + } + TypeT resolveType(TycoSpecifier s) const + { + Tyco tyco = resolveTycoSpecifier(s); + TypeT t = resolveTycoSpecifier(s); + if (!t.valid()) { + s.span().throwError("Type constructor specifier " + s.toString() + + " does not specify a type but a type constructor of kind " + + tyco.kind().toString() + "."); + } + return t; + } + VariableDefinition resolveVariable(Identifier identifier, + ResolutionPath* path) + { + if (_objects.hasKey(identifier)) { + VariableDefinition s = _objects[identifier]; + *path = ResolutionPath::local(); + return s; + } + if (_parent == 0) { + identifier.span().throwError("Unknown identifier " + + identifier.toString()); + } + return _parent->resolveVariable(identifier, path); + } + FuncoT resolveFunction(Identifier identifier, List argumentTypes) + { + List>> funcos = getFuncosForIdentifier(identifier); + + List> bestCandidates; + for (auto ff : funcos) { + for (auto f : ff) { + if (!f.argumentsMatch(argumentTypes)) + continue; + List> newBestCandidates; + bool newBest = true; + for (auto b : bestCandidates) { + int r = f.compareTo(b); + if (r == 2) { + // b better than f + newBest = false; + break; + } + if (r != 1) + newBestCandidates.add(b); + } + if (newBest) { + bestCandidates = newBestCandidates; + bestCandidates.add(f); + } + } + } + for (auto f : bestCandidates) { + for (auto b : bestCandidates) { + int r = f.compareTo(b); + if (r == 3) { + identifier.span().throwError( + "Ambiguous function call of " + identifier.toString() + + " with argument types " + + argumentTypesString(argumentTypes) + ". Could be " + + b.toString() + " or " + f.toString() + "."); + } + } + } + if (bestCandidates.count() == 0) { + identifier.span().throwError("No matches for function " + + identifier.toString() + " with argument types " + + argumentTypesString(argumentTypes) + "."); + } + // We have a choice of possible funcos here. Logically they should + // be equivalent, but some may be more optimal. For now we'll just + // choose the first one, but later we may want to try to figure out + // which one is most optimal. + return *bestCandidates.begin(); + } + void setParentScope(Scope* parent) { _parent = parent; } + void setFunctionScope(Scope* scope) { _functionScope = scope; } + Scope* functionScope() { return _functionScope; } +private: + String argumentTypesString(List argumentTypes) const + { + String s; + bool needComma = false; + for (auto t : argumentTypes) { + if (needComma) + s += ", "; + needComma = true; + s += t.toString(); + } + return s; + } + + List> getFuncosForIdentifier(Identifier i) + { + if (_functionScope != this) + return _functionScope->getFuncosForIdentifier(i); + List> r; + if (_parent != 0) + r = _parent->getFuncosForIdentifier(i); + if (_functions.hasKey(i)) + r.add(_functions[i]); + return r; + } + + HashTable _tycos; + HashTable _objects; + HashTable> _functions; + Scope* _parent; + Scope* _functionScope; +}; + +template class ResolutionPathT; +typedef ResolutionPathT ResolutionPath; + +template class ResolutionPathT : public ConstHandle +{ +public: + ResolutionPathT() { } + static ResolutionPathT local() { return create(); } + ValueT evaluate(Structure* context, Identifier identifier) const + { + return body()->evaluate(context, identifier); + } +private: + ResolutionPathT(ConstHandle other) : ConstHandle(other) { } + class Body : public ConstHandle::Body + { + public: + virtual Value evaluate(Structure* context, Identifier identifier) const + = 0; + }; + class ParentBody : public Body + { + public: + ValueT evaluate(Structure* context, Identifier identifier) const + { + throw NotYetImplementedException(); + } + private: + ResolutionPathT _rest; + }; + class OuterBody : public Body + { + public: + ValueT evaluate(Structure* context, Identifier identifier) const + { + throw NotYetImplementedException(); + } + private: + ResolutionPathT _rest; + }; + class HereBody : public Body + { + public: + ValueT evaluate(Structure* context, Identifier identifier) const + { + Span s = identifier.span(); + //if (!has(i)) + // s.throwError("Unknown identifier " + i.name()); + return Value( + LValueTypeT::wrap(context->getValue(identifier).type()), + LValueT(context, identifier), s); + //return context->getValue(identifier); + } + }; + const Body* body() const { return as(); } +}; + +template class LValueT; +typedef LValueT LValue; + +template class LValueT +{ +public: + LValueT(Structure* structure, Identifier identifier) + : _structure(structure), _identifier(identifier) { } + ValueT rValue() const + { + return _structure->getValue(_identifier); + } + void set(ValueT value, Span span) const + { + _structure->set(_identifier, value, span); + } + bool operator==(const LValue& other) const + { + return _structure == other._structure && + _identifier == other._identifier; + } + LValueT member(Identifier identifier) + { + return LValueT(_structure->getValue(_identifier).value(), + identifier); + } +private: + Structure* _structure; + Identifier _identifier; +}; + +template class TypeT : public Tyco +{ +public: + TypeT() { } + TypeT(const Handle& other) : Tyco(other) { } + TypeT(const Tyco& other) : Tyco(to(other)) { } + + Type member(IdentifierT i) const { return body()->member(i); } + Type rValue() const + { + if (LValueTypeT(*this).valid()) + return LValueTypeT(*this).inner(); + return *this; + } + // All measurements in characters (== bytes, no unicode support yet). + // "width" is maximum total width of file not including line terminator + // (e.g. 79 characters). + // "used" is the number of characters that are already used on the left + // (including indentation). + // "indent" is the number of spaces to indent on any new lines. If 0 then + // we'll exit with "*" if the result doesn't fit in the line. + // "delta" is the number of spaces by which the indent should be increased + // when going in a level. + // We will leave enough space at the end for a trailing comma. + String serialize(void* p, int width, int used, int indent, int delta) const + { + return body()->serialize(p, width, used, indent, delta); + } + void deserialize(const Value& value, void* p) const + { + body()->deserialize(value, p); + } + int size() const { return body()->size(); } + ValueT value(void* p) const { return body()->value(p); } + ValueT simplify(const Value& value) const + { + return body()->simplify(value); + } + bool canConvertFrom(const Type& other, String* reason = 0) const + { + if (*this == other) + return true; + if (other == StructuredTypeT::empty().type() && + body()->defaultValue().valid()) + return true; + String reasonFrom; + if (body()->canConvertFrom(other, &reasonFrom)) + return true; + String reasonTo; + if (other.body()->canConvertTo(*this, &reasonTo)) + return true; + if (reason != 0) { + if (reasonFrom != "") + *reason = reasonFrom; + else + *reason = reasonTo; + } + return false; + } + bool canConvertTo(const Type& other, String* reason = 0) const + { + return other.canConvertFrom(*this, reason); + } + ValueT convert(const ValueT& value) const + { + if (*this == value.type()) + return value; + if (value == StructuredTypeT::empty()) { + ValueT v = body()->defaultValue(); + if (v.valid()) + return v; + } + String reasonFrom; + if (body()->canConvertFrom(value.type(), &reasonFrom)) + return body()->convert(value); + return value.type().body()->convertTo(*this, value); + } + ValueT convertTo(const Type& to, const ValueT& value) const + { + assert(*this == value.type()); + return to.convert(value); + } + ValueT defaultValue() const { return body()->defaultValue(); } +protected: + class Body : public Tyco::Body + { + public: + Kind kind() const { return TypeKind(); } + virtual Type member(IdentifierT i) const { return Type(); } + virtual String serialize(void* p, int width, int used, int indent, + int delta) const + { + return ""; + } + virtual void deserialize(const Value& value, void* p) const { } + virtual int size() const { return 0; } + virtual ValueT defaultValue() const { return ValueT(); } + virtual ValueT value(void* p) const { return ValueT(); } + Type type() const { return tyco(); } + virtual ValueT simplify(const Value& value) const + { + return value; + } + virtual bool canConvertFrom(const Type& other, String* reason) const + { + return false; + } + virtual bool canConvertTo(const Type& other, String* reason) const + { + return false; + } + virtual ValueT convert(const ValueT& value) const + { + return ValueT(); + } + virtual ValueT convertTo(const Type& to, const Value& value) + const + { + return ValueT(); + } + virtual ValueT valueFromAny(Any a, Structure* owner) const + { + return ValueT(type(), a); + } + virtual Any anyFromValue(ValueT v) const { return v.value(); } + }; + const Body* body() const { return as(); } + + friend class TemplateT; +}; + +template class LValueTypeT : public Type +{ +public: + LValueTypeT(const Type& type) : Type(to(type)) { } + static LValueType wrap(const Type& inner) + { + if (LValueType(inner).valid()) + return inner; + return create(inner); + } + Type inner() const { return body()->inner(); } +private: + class Body : public Type::Body + { + public: + Body(Type inner) : _inner(inner) { } + Type inner() const { return _inner; } + String toString() const { return "LValue<" + _inner.toString() + ">"; } + private: + Type _inner; + }; + + const Body* body() const { return as(); } + LValueTypeT(const Handle& type) : Type(to(type)) { } +}; + +template class HasType +{ + template struct Check; + template static char func(Check *) { } + template static int func(...) { } +public: + typedef HasType type; + enum { value = sizeof(func(0)) == sizeof(char) }; +}; + +template Type typeFromCompileTimeType() { return T::type(); } +// TODO: For this to work with string literals, need to use class template +// specialization, not function template specialization. +//template Type typeFromCompileTimeType() { return StringType(); } +template::value>* = nullptr> + Type typeFromValue(const T& value) +{ + return value.type(); +} +template::value>* = + nullptr> + Type typeFromValue(const T&) +{ + return typeFromCompileTimeType(); +} + +template class ValueT +{ +public: + ValueT() { } + template::value>* = + nullptr> + ValueT(U type, Any any, Span span = Span()) + : _type(type), _any(any), _span(span) { } + template::value>* = + nullptr> + ValueT(U type, Span span = Span()) + : _type(type), _span(span) + { + _any = StructuredTypeT::empty().convertTo(type).value(); + } + template::value>* = + nullptr> ValueT(const U& value, Span span = Span()) + : _type(typeFromValue(value)), _any(value), _span(span) { } + Type type() const { return _type; } + Any value() const { return _any; } + bool operator==(const Value& other) const + { + return _type == other._type && _any == other._any; + } + bool operator!=(const Value& other) const { return !(*this == other); } + template U value() const { return _any.value(); } + Span span() const { return _span; } + bool valid() const { return _type.valid(); } + Value convertTo(const Type& to) const + { + String reason; + Value v = tryConvertTo(to, &reason); + if (!v.valid()) + span().throwError(reason); + return v; + } + Value tryConvertTo(const Type& to, String* why) const + { + String reason; + if (to.canConvertFrom(_type, &reason)) + return to.convert(*this); + String r = "No conversion"; + String f = _type.toString(); + if (f != "") + r += " from type " + f; + r += " to type " + to.toString() + " is available"; + if (reason.empty()) + r += "."; + else + r += ": " + reason; + *why = r; + return Value(); + } + Value rValue() const + { + LValueType lValueType(_type); + if (lValueType.valid()) { + Value r = value().rValue(); + return Value(r.type(), r.value(), _span); + } + return *this; + } + Value simplify() const { return _type.simplify(*this); } +private: + Type _type; + Any _any; + Span _span; +}; + +template class TemplateT : public Tyco +{ +public: + TemplateT(const Handle& other) : Tyco(other) { } + Tyco instantiate(const Tyco& argument) const + { + return body()->instantiate(argument); + } + Tyco argument() const { return as()->argument(); } +protected: + class Body : public Tyco::Body + { + public: + virtual Tyco instantiate(const Tyco& argument) const + { + if (_instantiations.hasKey(argument)) + return _instantiations[argument]; + + Kind k = kind(); + Kind resultKind = k.instantiate(argument.kind()); + if (!resultKind.valid()) { + throw Exception("Cannot use " + argument.toString() + + " (kind " + argument.kind().toString() + + ") to instantiate " + toString() + + " because it requires a type constructor of kind " + + k.toString()); + } + TemplateKind tk = k; + Tyco t = partialInstantiate(tk.rest() == TypeKind(), argument); + _instantiations.add(argument, t); + return t; + } + virtual Tyco partialInstantiate(bool final, Tyco argument) const + { + if (final) + return finalInstantiate(tyco(), argument); + return create(tyco(), tyco(), argument); + } + virtual Type finalInstantiate(Template parent, Tyco argument) const + = 0; + private: + mutable HashTable _instantiations; + }; + class PartialBody : public Body + { + public: + PartialBody(Template root, Template parent, Tyco argument) + : _root(root), _parent(parent), _argument(argument) { } + + String toString() const + { + return _argument.toString() + "<" + toString2() + ">"; + } + String toString2() const + { + auto p = _parent.to(); + String s; + if (p != 0) + s = p->toString2() + ", "; + return s + _argument.toString(); + } + Kind kind() const + { + return _parent.kind().instantiate(_argument.kind()); + } + Type finalInstantiate(Template parent, Tyco argument) const + { + assert(false); + return Type(); + } + + Tyco partialInstantiate(bool final, Tyco argument) const + { + if (final) + return _root.body()->finalInstantiate(this->tyco(), argument); + return create(_root, this->tyco(), argument); + } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + return o != 0 && Template(_parent) == Template(o->_parent) && + _argument == o->_argument; + } + Hash hash() const { return Body::hash().mixin(_argument.hash()); } + const Body* parent() const { return _parent; } + Tyco argument() const { return _argument; } + private: + TemplateT _root; + TemplateT _parent; + Tyco _argument; + }; + const Body* body() const { return as(); } +}; + +class LessThanType : public Type +{ +public: + LessThanType(Type type) : Type(to(type)) { } + LessThanType(int n) : Type(create(n)) { } + int n() const { return body()->_n; } +private: + class Body : public Type::Body + { + public: + Body(int n) : _n(n) { } + String toString() const { return decimal(_n); } + + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + return o != 0 && _n == o->_n; + } + Hash hash() const { return Type::Body::hash().mixin(_n); } + int _n; + }; + const Body* body() const { return as(); } +}; + +template class StringTypeT : public NamedNullary +{ +public: + static String name() { return "String"; } + class Body : public NamedNullary::Body + { + public: + String serialize(void* p, int width, int used, int indent, int delta) + const + { + String r = "\""; + String s = *static_cast(p); + for (int i = 0; i < s.length(); ++i) { + Byte b = s[i]; + if (b == '\\' || b == '\"') + r += "\\"; + r += String::Byte(b); + } + return r + "\""; + } + void deserialize(const Value& value, void* p) const + { + *static_cast(p) = value.value(); + } + int size() const { return sizeof(String); } + Value defaultValue() const { return String(); } + Value value(void* p) const { return *static_cast(p); } + }; +}; + +template class IntegerTypeT : public NamedNullary +{ +public: + IntegerTypeT() { } + IntegerTypeT(const Handle& other) : NamedNullary(other) { } + static String name() { return "Integer"; } + class Body : public NamedNullary::Body + { + public: + String serialize(void* p, int width, int used, int indent, int delta) + const + { + return decimal(*static_cast(p)); + } + void deserialize(const Value& value, void* p) const + { + *static_cast(p) = value.value(); + } + int size() const { return sizeof(int); } + Value defaultValue() const { return 0; } + Value value(void* p) const { return *static_cast(p); } + }; +}; + +template class BooleanTypeT + : public NamedNullary> +{ +public: + static String name() { return "Boolean"; } + class Body : public NamedNullary::Body + { + public: + String serialize(void* p, int width, int used, int indent, int delta) + const + { + return String::Boolean(*static_cast(p)); + } + void deserialize(const Value& value, void* p) const + { + *static_cast(p) = value.value(); + } + int size() const { return sizeof(bool); } + Value defaultValue() const { return false; } + Value value(void* p) const { return *static_cast(p); } + }; +}; + +class ObjectType : public NamedNullary +{ +public: + static String name() { return "Object"; } +}; + +class LabelType : public NamedNullary +{ +public: + static String name() { return "Label"; } +}; + +template class VoidTypeT : public NamedNullary +{ +public: + static String name() { return "Void"; } +}; + +class DoubleType : public NamedNullary +{ +public: + static String name() { return "Double"; } + class Body : public NamedNullary::Body + { + public: + bool canConvertFrom(const Type& from, String* reason) const + { + return from == IntegerType(); + } + Value convert(const Value& value) const + { + return Value(DoubleType(), static_cast(value.value()), + value.span()); + } + }; +}; + +class ByteType : public NamedNullary +{ +public: + static String name() { return "Byte"; } + class Body : public NamedNullary::Body + { + public: + String serialize(void* p, int width, int used, int indent, int delta) + const + { + return hex(*static_cast(p), 2); + } + void deserialize(const Value& value, void* p) const + { + *static_cast(p) = value.value(); + } + int size() const { return sizeof(Byte); } + Value defaultValue() const { return 0; } + Value value(void* p) const + { + return Value(ByteType(), static_cast(*static_cast(p))); + } + }; +}; + +class WordType : public NamedNullary +{ +public: + static String name() { return "Word"; } + class Body : public NamedNullary::Body + { + public: + String serialize(void* p, int width, int used, int indent, int delta) + const + { + return hex(*static_cast(p), 4); + } + void deserialize(const Value& value, void* p) const + { + *static_cast(p) = value.value(); + } + int size() const { return sizeof(Word); } + Value defaultValue() const { return 0; } + Value value(void* p) const + { + return Value(WordType(), static_cast(*static_cast(p))); + } + }; +}; + +class DWordType : public NamedNullary +{ +public: + static String name() { return "DWord"; } + class Body : public NamedNullary::Body + { + public: + String serialize(void* p, int width, int used, int indent, int delta) + const + { + return hex(*static_cast(p), 4); + } + void deserialize(const Value& value, void* p) const + { + *static_cast(p) = value.value(); + } + int size() const { return sizeof(DWord); } + Value defaultValue() const { return 0; } + Value value(void* p) const + { + return Value(DWordType(), + static_cast(*static_cast(p))); + } + }; +}; + +template class RationalTypeT : public NamedNullary +{ +public: + static String name() { return "Rational"; } + class Body : public NamedNullary::Body + { + public: + bool canConvertFrom(const Type& from, String* reason) const + { + return from == IntegerType(); + } + bool canConvertTo(const Type& to, String* reason) const + { + // Eventually we may want something more sophisticated here, since + // in general the conversion from Rational to Double would be + // lossy. + return to == DoubleType(); + } + Value convert(const Value& value) const + { + return Value(RationalType(), Rational(value.value()), + value.span()); + } + Value convertTo(const Type& to, const Value& value) const + { + return Value(DoubleType(), value.value().value(), + value.span()); + } + Value simplify(const Value& value) const + { + Rational r = value.value(); + if (r.denominator == 1) + return Value(IntegerType(), r.numerator, value.span()); + return value; + } + String serialize(void* p, int width, int used, int indent, int delta) + const + { + auto r = static_cast(p); + return String(decimal(r->numerator)) + "/" + + decimal(r->denominator); + } + void deserialize(const Value& value, void* p) const + { + *static_cast(p) = value.value(); + } + int size() const { return sizeof(Rational); } + Value defaultValue() const + { + return Value(RationalType(), Rational(0)); + } + Value value(void* p) const + { + return Value(RationalType(), *static_cast(p)); + } + }; +}; + +class ArrayType : public Type +{ +public: + ArrayType(const Type& type) : Type(to(type)) { } + ArrayType(const Type& contained, const Type& indexer) + : Type(create(contained, indexer)) { } + ArrayType(const Type& contained, int size) + : Type(create(contained, LessThanType(size))) { } + Type contained() const { return body()->contained(); } + Type indexer() const { return body()->indexer(); } +protected: + class Body : public Type::Body + { + public: + Body(const Type &contained, const Type& indexer) + : _contained(contained), _indexer(indexer) { } + String toString() const + { + return _contained.toString() + "[" + _indexer.toString() + "]"; + } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + return o != 0 && _contained == o->_contained && + _indexer == o->_indexer; + } + Hash hash() const + { + return Type::Body::hash().mixin(_contained.hash()). + mixin(_indexer.hash()); + } + Type contained() const { return _contained; } + Type indexer() const { return _indexer; } + String serialize(void* p, int width, int used, int indent, int delta) + const + { + int n; + char* pc0 = pointerAndCount(p, &n); + char* pc = pc0; + int size = _contained.size(); + Value d(_contained); + do { + if (d != + _contained.value(static_cast(pc + (n - 1)*size))) + break; + --n; + } while (n > 0); + // First try putting everything on one line + String s("{ "); + bool needComma = false; + bool separate = false; + used += 5; + void* pp = p; + for (int i = 0; i < n; ++i) { + if (used > width) { + separate = true; + break; + } + int u = used + (needComma ? 2 : 0); + String v = _contained.serialize(pp, width, u, 0, 0); + if (v == "*") { + separate = true; + s = ""; + break; + } + if (needComma) + s += ", "; + needComma = true; + s += v; + used = u + v.length(); + pc += size; + pp = static_cast(pc); + } + if (s == "{ ") + return "{ }"; + if (!separate && used <= width) + return s + " }"; + else + s = ""; + if (s == "" && indent == 0) + return "*"; + // It doesn't all fit on one line, put each member on a separate + // line. + s = "{\n"; + needComma = false; + pc = pc0; + for (int i = 0; i < n; ++i) { + int u = indent + delta; + String v = "{ }"; + if (_contained.value(p) != d) { + v = _contained.serialize(p, width, u, indent + delta, + delta); + } + if (needComma) + s += ",\n"; + needComma = true; + s += String(" ")*indent + v; + pc += size; + p = static_cast(pc); + } + return s + " }"; + } + void deserialize(const Value& value, void* p) const + { + LessThanType l(_indexer); + if (!l.valid()) { + throw Exception( + "Don't know how many elements to deserialize."); + } + int n = l.n(); + auto v = value.value>(); + char* pc = static_cast(p); + int size = _contained.size(); + for (auto vv : v) { + if (n == 0) + break; + _contained.deserialize(vv, p); + pc += size; + p = static_cast(pc); + --n; + } + for (int i = 0; i < n; ++i) { + _contained.deserialize(Value(_contained), p); + pc += size; + p = static_cast(pc); + } + } + Value value(void* p) const + { + int n; + char* pc = pointerAndCount(p, &n); + List v; + int size = _contained.size(); + for (int i = 0; i < n; ++i) { + v.add(_contained.value(static_cast(pc))); + pc += size; + } + return Value(type(), v); + } + protected: + virtual int elementCount(void* p) const { unknownCount(); return 0; } + virtual void* elementData(void* p) const { return 0; } + private: + char* pointerAndCount(void* p, int *n) const + { + LessThanType l(_indexer); + if (l.valid()) { + *n = l.n(); + return static_cast(p); + } + if (_indexer == IntegerType()) { + *n = elementCount(p); + return static_cast(elementData(p)); + } + unknownCount(); + return 0; + } + void unknownCount() const + { + throw Exception("Don't know how many elements to serialize."); + } + Type _contained; + Type _indexer; + }; +private: + const Body* body() const { return as(); } +}; + +template class ArrayPersistType : public ArrayType +{ +public: + ArrayPersistType(const Type& type) : ArrayType(type) { } + ArrayPersistType(const Type& contained, const Type& indexer) + : ArrayType(contained, indexer) { } + ArrayPersistType(const Type& contained, int size) + : ArrayType(contained, size) { } +protected: + class Body : public ArrayType::Body + { + protected: + virtual int elementCount(void* p) const + { + return static_cast*>(p)->count(); + } + virtual void* elementData(void* p) const + { + return static_cast(&(*static_cast*>(p))[0]); + } + }; +}; + +class ArrayTemplate : public NamedNullary +{ +public: + static String name() { return "Array"; } + + class Body : public NamedNullary::Body + { + public: + Kind kind() const + { + return TemplateKind(TypeKind(), + TemplateKind(TypeKind(), TypeKind())); + } + Type finalInstantiate(Template parent, Tyco argument) const + { + return ArrayType(parent.argument(), argument); + } + }; +}; + +class SequenceType : public Type +{ +public: + SequenceType(const Type& contained) : Type(create(contained)) { } + Type contained() const { return body()->contained(); } +private: + class Body : public Type::Body + { + public: + Body(const Type &contained) : _contained(contained) { } + String toString() const + { + return _contained.toString() + "[]"; + } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + return o != 0 && _contained == o->_contained; + } + Hash hash() const + { + return Type::Body::hash().mixin(_contained.hash()); + } + Type contained() const { return _contained; } + private: + Type _contained; + }; + const Body* body() const { return as(); } +}; + +class SequenceTemplate : public NamedNullary +{ +public: + static String name() { return "Sequence"; } + + class Body : public NamedNullary::Body + { + public: + Kind kind() const { return TemplateKind(TypeKind(), TypeKind()); } + Type finalInstantiate(Template parent, Tyco argument) const + { + return SequenceType(argument); + } + }; +}; + +template class TupleTycoT : public NamedNullary +{ +public: + TupleTycoT() : NamedNullary(instance()) { } + static String name() { return "Tuple"; } + bool isUnit() { return *this == TupleTyco(); } + Tyco instantiate(const Tyco& argument) const + { + return body()->instantiate(argument); + } + Type lastMember() + { + auto i = to(); + if (i == 0) + return Type(); + return i->contained(); + } + TupleTyco firstMembers() + { + auto i = to(); + if (i == 0) + return TupleTyco(); + return i->parent(); + } + class Body : public NamedNullary::Body + { + public: + // Tyco + String toString() const + { + bool needComma = false; + return "(" + toString2(&needComma) + ")"; + } + virtual String toString2(bool* needComma) const { return ""; } + Kind kind() const { return VariadicTemplateKind(); } + + // Template + Tyco instantiate(const Tyco& argument) const + { + if (_instantiations.hasKey(argument)) + return _instantiations[argument]; + + if (argument.kind() != TypeKind()) { + throw Exception(String("Cannot use ") + argument.toString() + + " (kind " + argument.kind().toString() + + ") to instantiate Tuple because it requires a type"); + } + + TupleTyco t(create(handle(), argument)); + _instantiations.add(argument, t); + return t; + } + private: + mutable HashTable _instantiations; + }; + TupleTycoT(const Handle& other) : NamedNullary(other) { } +private: + + class NonUnitBody : public Body + { + public: + NonUnitBody(TupleTyco parent, Type contained) + : _parent(parent), _contained(contained) { } + String toString2(bool* needComma) const + { + String s = _parent.toString2(needComma); + if (*needComma) + s += ", "; + *needComma = true; + return s + _contained.toString(); + } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + return o != 0 && _parent == o->_parent && + _contained == o->_contained; + } + Hash hash() const + { + return Body::hash().mixin(_parent.hash()).mixin(_contained.hash()); + } + + // Type + bool canConvertFrom(const Type& from, String* reason) const + { + if (_parent == TupleTyco()) + return _contained.canConvertFrom(from, reason); + return false; + } + bool canConvertTo(const Type& to, String* reason) const + { + if (_parent == TupleTyco()) + return _contained.canConvertTo(to, reason); + return false; + } + Value convert(const Value& value) const + { + return _contained.convert(value); + } + Value convertTo(const Type& to, const Value& value) const + { + return _contained.convertTo(to, value); + } + Type member(IdentifierT i) const + { + CharacterSource s(i.name()); + Rational r; + if (!Space::parseNumber(&s, &r)) + return Type(); + if (r.denominator != 1) + return Type(); + int n = r.numerator; + if (s.get() != -1) + return Type(); + TupleTyco p(this); + do { + if (p.isUnit()) + return Type(); + if (n == 1) + return p.as()->contained(); + --n; + p = p.parent(); + } while (true); + } + Type contained() const { return _contained; } + TupleTyco parent() const { return _parent; } + private: + TupleTycoT _parent; + Type _contained; + }; +private: + String toString2(bool* needComma) const + { + return body()->toString2(needComma); + } + const Body* body() const { return as(); } + TupleTyco parent() const { return as()->parent(); } + friend class Body; + friend class NonUnitBody; +}; + +template class PointerTypeT : public Type +{ +public: + PointerTypeT(const Type& referent) : Type(create(referent)) { } +private: + class Body : public Type::Body + { + public: + Body(const Type &referent) : _referent(referent) { } + String toString() const { return _referent.toString() + "*"; } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + return o != 0 && _referent == o->_referent; + } + Hash hash() const + { + return Type::Body::hash().mixin(_referent.hash()); + } + private: + Type _referent; + }; +}; + +class PointerTemplate : public NamedNullary +{ +public: + static String name() { return "Pointer"; } + + class Body : public NamedNullary::Body + { + public: + Kind kind() const { return TemplateKind(TypeKind(), TypeKind()); } + Type finalInstantiate(Template parent, Tyco argument) const + { + return PointerType(argument); + } + }; +}; + +template class FunctionTypeT : public Tyco +{ +public: + FunctionTypeT(const Tyco& t) : Tyco(t) { } + + static FunctionType nullary(const Type& returnType) + { + return create(returnType); + } + FunctionTypeT(Type returnType, Type argumentType) + : Tyco(FunctionType( + FunctionTemplateT().instantiate(returnType)). + instantiate(argumentType)) { } + FunctionTypeT(Type returnType, Type argumentType1, + Type argumentType2) + : Tyco(FunctionType(FunctionType(FunctionTemplateT(). + instantiate(returnType)).instantiate(argumentType1)). + instantiate(argumentType2)) { } + bool argumentsMatch(List::Iterator argumentTypes) const + { + return body()->argumentsMatch(&argumentTypes) && argumentTypes.end(); + } + Tyco instantiate(const Tyco& argument) const + { + return body()->instantiate(argument); + } + bool isNullary() const { return body()->isNullary(); } + FunctionType parent() const { return body()->parent(); } + void addParameterTycos(List* list) const + { + body()->addParameterTycos(list); + } + Type returnType() const { return body()->returnType(); } +private: + class Body : public Tyco::Body + { + public: + String toString() const + { + bool needComma = false; + return toString2(&needComma) + ")"; + } + virtual String toString2(bool* needComma) const = 0; + Kind kind() const { return VariadicTemplateKind(); } + // Template + Tyco instantiate(const Tyco& argument) const + { + if (_instantiations.hasKey(argument)) + return _instantiations[argument]; + + if (argument.kind() != TypeKind()) { + throw Exception("Cannot use " + argument.toString() + + " (kind " + argument.kind().toString() + + ") to instantiate Function because it requires a type"); + } + + FunctionType t(create(tyco(), argument)); + _instantiations.add(argument, t); + return t; + } + virtual bool argumentsMatch(List::Iterator* i) const = 0; + virtual void addParameterTycos(List* list) const = 0; + virtual Type returnType() const = 0; + private: + mutable HashTable _instantiations; + }; + class NullaryBody : public Body + { + public: + NullaryBody(const Type& returnType) : _returnType(returnType) { } + String toString2(bool* needComma) const + { + return _returnType.toString() + "("; + } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + return o != 0 && _returnType != o->_returnType; + } + Hash hash() const { return Body::hash().mixin(_returnType.hash()); } + bool argumentsMatch(List::Iterator* i) const { return true; } + virtual void addParameterTycos(List* list) const { } + Type returnType() const { return _returnType; } + private: + Type _returnType; + }; + class ArgumentBody : public Body + { + public: + ArgumentBody(FunctionType parent, const Type& argumentType) + : _parent(parent), _argumentType(argumentType) { } + String toString2(bool* needComma) const + { + String s = _parent.toString2(needComma); + if (*needComma) + s += ", "; + *needComma = true; + return s + _argumentType.toString(); + } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + return o != 0 && _parent == o->_parent && + _argumentType == o->_argumentType; + } + Hash hash() const + { + return Body::hash().mixin(_parent.hash()). + mixin(_argumentType.hash()); + } + bool argumentsMatch(List::Iterator* i) const + { + if (!_parent.body()->argumentsMatch(i)) + return false; + if (i->end()) + return false; + if (!(*i)->canConvertTo(_argumentType)) + return false; + ++*i; + return true; + } + virtual void addParameterTycos(List* list) const + { + _parent.addParameterTycos(list); + list->add(_argumentType); + } + Type returnType() const { return _parent.returnType(); } + private: + FunctionTypeT _parent; + Type _argumentType; + }; + const Body* body() const { return as(); } + String toString2(bool* needComma) const + { + return body()->toString2(needComma); + } + FunctionTypeT(const Handle& t) : Tyco(t) { } +}; + +template class FunctionTemplateT + : public NamedNullary +{ +public: + static String name() { return "Function"; } + + class Body : public NamedNullary::Body + { + public: + virtual Tyco partialInstantiate(bool final, Tyco argument) const + { + return FunctionType::nullary(argument); + } + Kind kind() const + { + return TemplateKind(TypeKind(), VariadicTemplateKind()); + } + Type finalInstantiate(Template parent, Tyco argument) const + { + assert(false); + return Type(); + } + }; +}; + +template class EnumerationType : public Type +{ +public: + class Helper; + EnumerationType(String name, const Helper& helper, String context = "") + : Type(create(name, helper, context)) { } +protected: + class Body : public Type::Body + { + public: + Body(String name, const Helper& helper, String context) + : _name(name), _helper(helper), _context(context) { } + String toString() const { return _name; } + String serialize(void* p, int width, int used, int indent, int delta) + const + { + return _context + _name + "." + + _helper._tToString[*static_cast(p) + 1]; + } + void deserialize(const Value& value, void* p) const + { + *static_cast(p) = value.value(); + } + int size() const { return sizeof(T); } + Value defaultValue() const { return Value(type(), static_cast(0)); } + Value value(void* p) const + { + return Value(type(), *static_cast(p)); + } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + return o != 0 && _context == o->_context && _name == o->_name && + _helper == o->_helper; + } + private: + String _context; + String _name; + const Helper _helper; + }; +public: + class Helper + { + public: + void add(const T& t, String i) + { + _stringToT.add(i, t); + _tToString.add(static_cast(t) + 1, i); + } + bool operator==(const Helper& other) const + { + return _stringToT == other._stringToT && + _tToString == other._tToString; + } + private: + HashTable _stringToT; + HashTable _tToString; + friend class Body; + }; +}; + +// StructuredType is the type of "{...}" literals, not the base type for all +// types which have members. The ALFE compiler will need a more complicated +// body of structures, including using the same conversions at +// compile-time as at run-time. Also we don't want to have to override +// conversion functions in children just to avoid unwanted conversions + +template class StructuredTypeT : public Type +{ +public: + class Member + { + public: + Member() { } + Member(String name, Type type) : _name(name), _default(type) { } + Member(String name, Value defaultValue) + : _name(name), _default(defaultValue) { } + template Member(String name, const U& defaultValue) + : _name(name), _default(defaultValue) { } + String name() const { return _name; } + Type type() const { return _default.type(); } + Value defaultValue() const { return _default; } + bool hasDefault() const { return _default.valid(); } + bool operator==(const Member& other) const + { + return _name == other._name && type() == other.type(); + } + bool operator!=(const Member& other) const + { + return !operator==(other); + } + private: + String _name; + Value _default; + }; + + template static Member member(String name) + { + return Member(name, typeFromCompileTimeType()); + } + + StructuredTypeT() { } + StructuredTypeT(const Tyco& tyco) : Type(to(tyco)) { } + StructuredTypeT(const Handle& other) : Type(other) { } + StructuredTypeT(String name, List members) + : Type(create(name, members)) { } + const HashTable names() const { return body()->names(); } + const Array members() const { return body()->members(); } + static Value empty() + { + static Value e = Value(StructuredType(String(), + List()), HashTable()); + return e; + } + // This is a bit of a hack. In order to allow access to members (e.g. "x" + // and "y" of a Vector) from a ConfigFile, we need to convert the Vector to + // a Structure, and that Structure needs to be owned by something. Hence + // the ConfigFile needs to have a StructureOwner to own those Structure + // objects. + Value lValueFromRValue(Any rValue, StructureOwner* owner) const + { + return body()->lValueFromRValue(rValue, owner); + } + Any rValueFromLValue(Value lValue) const + { + return body()->rValueFromLValue(lValue); + } + Value constructValue(Value value) const + { + return body()->constructValue(value); + } + void setLValue(LValue l, Value rValue) const + { + return body()->setLValue(l, rValue); + } + Type member(Identifier i) const { return body()->member(i); } + Scope* scope() { return body()->scope(); } +protected: + class Body : public Type::Body + { + public: + Body(String name, List members) + : _name(name), _members(members) + { + int n = 0; + for (auto i : members) { + String name = i.name(); + _names.add(name, n); + Identifier identifier(name); + _scope.addObject(identifier, + VariableDefinition(i.type(), identifier)); + ++n; + } + } + String toString() const { return _name; } + const HashTable names() const { return _names; } + const Array members() const { return _members; } + + bool canConvertTo(const Type& to, String* why) const + { + StructuredType s(to); + if (s.valid()) { + // First take all named members in the RHS and assign them to + // the corresponding named members in the LHS. + int count = _members.count(); + int toCount = s.members().count(); + Array assigned(toCount); + for (int i = 0; i < toCount; ++i) + assigned[i] = false; + for (int i = 0; i < count; ++i) { + const Member* m = &_members[i]; + String name = m->name(); + if (name.empty()) + continue; + // If a member doesn't exist, fail conversion. + if (!s.names().hasKey(name)) { + *why = "The target type has no member named " + name; + return false; + } + int j = s.names()[name]; + if (assigned[j]) { + *why = + "The source type has more than one member named " + + name; + return false; + } + // If one of the child conversions fails, fail. + if (!canConvertHelper(member(name), &s.members()[j], + why)) + return false; + assigned[j] = true; + } + // Then take all unnamed arguments in the RHS and in LTR order + // and assign them to unassigned members in the LHS, again in + // LTR order. + int j = 0; + for (int i = 0; i < count; ++i) { + const Member* m = &_members[i]; + if (!m->name().empty()) + continue; + while (assigned[j] && j < toCount) + ++j; + if (j >= toCount) { + *why = "The source type has too many members"; + return false; + } + const Member* toMember = &s.members()[j]; + ++j; + if (!canConvertHelper(m->type(), toMember, why)) + return false; + } + // Make sure any unassigned members have defaults. + for (;j < toCount; ++j) { + if (assigned[j]) + continue; + const Member* toMember = &s.members()[j]; + if (!toMember->hasDefault()) { + *why = "No default value is available for target type " + "member " + toMember->name(); + return false; + } + } + return true; + } + ArrayType toArray = to; + if (toArray.valid()) { + Type contained = toArray.contained(); + LessThanType l(toArray.indexer()); + if (l.valid() && _members.count() > l.n()) { + *why = "The source type has too many members"; + return false; + } + for (int i = 0; i < _members.count(); ++i) { + if (!_members[i].name().empty()) { + *why = "Array cannot be initialized with a structured " + "value containing named members"; + return false; + } + String reason; + if (!_members[i].type().canConvertTo(contained, &reason)) { + *why = "Cannot convert child member " + decimal(i); + if (!reason.empty()) + *why += ": " + reason; + return false; + } + } + return true; + } + TupleTyco toTuple = to; + if (toTuple.valid()) { + int count = _members.count(); + for (int i = _members.count() - 1; i >= 0; --i) { + if (!_members[i].name().empty()) { + *why = "Tuple cannot be initialized with a structured " + "value containing named members"; + return false; + } + if (toTuple.isUnit()) { + *why = "Tuple type does not have enough members to be " + "initialized with this structured value."; + return false; + } + String reason; + if (!_members[i].type(). + canConvertTo(toTuple.lastMember(), &reason)) { + *why = "Cannot convert child member " + decimal(i); + if (!reason.empty()) + *why += ": " + reason; + return false; + } + toTuple = toTuple.firstMembers(); + } + return true; + } + return false; + } + Value convertTo(const Type& to, const Value& value) const + { + StructuredType s(to); + if (s.valid()) { + auto input = value.value>(); + HashTable output; + + // First take all named members in the RHS and assign them to + // the corresponding named members in the LHS. + int count = _members.count(); + int toCount = s.members().count(); + Array assigned(toCount); + for (int i = 0; i < toCount; ++i) + assigned[i] = false; + for (int i = 0; i < count; ++i) { + const Member* m = &_members[i]; + String name = m->name(); + if (name.empty()) + continue; + int j = s.names()[name]; + output[name] = + input[name].convertTo(s.members()[j].type()); + assigned[j] = true; + } + // Then take all unnamed arguments in the RHS and in LTR order + // and assign them to unassigned members in the LHS, again in + // LTR order. + int j = 0; + for (int i = 0; i < count; ++i) { + const Member* m = &_members[i]; + if (!m->name().empty()) + continue; + while (assigned[j] && j < toCount) + ++j; + const Member* toMember = &s.members()[j]; + ++j; + output[toMember->name()] = + input[Identifier(String::Decimal(i))]. + convertTo(toMember->type()); + } + // Make sure any unassigned members have defaults. + for (; j < toCount; ++j) { + if (assigned[j]) + continue; + const Member* toMember = &s.members()[j]; + output[toMember->name()] = toMember->defaultValue(); + } + return Value(type(), output, value.span()); + } + ArrayType toArray = to; + if (toArray.valid()) { + Type contained = toArray.contained(); + auto input = value.value>(); + List results; + int i; + for (i = 0; i < input.count(); ++i) { + String name = decimal(i); + Value v = input[name].convertTo(contained); + results.add(v); + } + LessThanType l(toArray.indexer()); + if (l.valid()) { + for (; i < l.n(); ++i) + results.add(contained.defaultValue()); + } + return Value(to, results, value.span()); + } + TupleTyco toTuple = to; + if (toTuple.valid()) { + auto input = value.value>(); + List results; + int count = _members.count(); + for (int i = input.count() - 1; i >= 0; --i) { + String name = decimal(i); + Value v = input[name].convertTo(toTuple.lastMember()); + results.add(v); + toTuple = toTuple.firstMembers(); + } + return Value(to, results, value.span()); + } + assert(false); + return Value(); + } + Value defaultValue() const + { + HashTable values; + for (auto i : _members) + values.add(i.name(), i.defaultValue()); + return Value(type(), values); + } + + Type member(IdentifierT i) const + { + if (!_names.hasKey(i)) + return Type(); + return _members[_names[i]].type(); + } + bool equals(const Handle::Body* other) const + { + auto o = other->to(); + if (o == 0) + return false; + return _name == o->_name && _names == o->_names && + _members == o->_members; + } + virtual Value lValueFromRValue(Any rValue, StructureOwner* owner) const + { + return Value(type(), rValue); + } + virtual Any rValueFromLValue(Value lValue) const + { + return lValue.value(); + } + virtual Value constructValue(Value value) const { return value; } + void setLValue(LValue l, Value rValue) const + { + } + Scope* scope() { return &_scope; } + private: + bool canConvertHelper(const Type& type, const Member* to, String* why) + const + { + String reason; + if (!type.canConvertTo(to->type(), &reason)) { + *why = "Cannot convert child member " + to->name(); + if (!reason.empty()) + *why += ": " + reason; + return false; + } + return true; + } + + String _name; + HashTable _names; + Array _members; + Scope _scope; + }; + Body* body() { return as(); } + const Body* body() const { return as(); } + + friend class Body; +}; + +class VectorType : public NamedNullary +{ +public: + class Body : public StructuredType::Body + { + public: + Body() : StructuredType::Body("Vector", members()) { } + Value lValueFromRValue(Any rValue, StructureOwner* owner) const + { + auto r = Reference::create(); + owner->addOwned(r); + auto v = rValue.value(); + r->set("x", v.x, Span()); + r->set("y", v.y, Span()); + return Value(LValueType::wrap(type()), &*r); + } + void setLValue(LValue l, Value rValue) const + { + auto v = rValue.value(); + l.member("x").set(v.x, Span()); + l.member("y").set(v.y, Span()); + } + Any rValueFromLValue(Value lValue) const + { + auto s = lValue.value(); + return Vector(s->get("x"), s->get("y")); + } + virtual Value constructValue(Value value) const + { + auto s = value.value>(); + auto i = s.begin(); + Vector v; + v.x = i->value(); + ++i; + v.y = i->value(); + return Value(v, value.span()); + } + private: + List members() + { + List vectorMembers; + vectorMembers.add(StructuredType::member("x")); + vectorMembers.add(StructuredType::member("y")); + return vectorMembers; + } + }; + friend class NamedNullary; +}; + +template<> Type typeFromCompileTimeType() { return IntegerType(); } +template<> Type typeFromCompileTimeType() { return StringType(); } +template<> Type typeFromCompileTimeType() { return BooleanType(); } +template<> Type typeFromCompileTimeType() { return VectorType(); } +template<> Type typeFromCompileTimeType() { return RationalType(); } +template<> Type typeFromCompileTimeType() { return DoubleType(); } +template<> Type typeFromCompileTimeType() { return ByteType(); } +template<> Type typeFromCompileTimeType() { return WordType(); } +template<> Type typeFromCompileTimeType() { return DWordType(); } + +#endif // INCLUDED_TYPE_H diff --git a/80386/disassembler/include/alfe/type_specifier.h b/80386/disassembler/include/alfe/type_specifier.h new file mode 100644 index 0000000..bf0f72c --- /dev/null +++ b/80386/disassembler/include/alfe/type_specifier.h @@ -0,0 +1,654 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_TYPE_SPECIFIER_H +#define INCLUDED_TYPE_SPECIFIER_H + +#include "alfe/parse_tree_object.h" + +template class ExpressionT; +typedef ExpressionT Expression; + +template class IdentifierT; +typedef IdentifierT Identifier; + +template class TycoSpecifierT; +typedef TycoSpecifierT TycoSpecifier; + +template class TypeSpecifierT; +typedef TypeSpecifierT TypeSpecifier; + +template class TycoIdentifierT; +typedef TycoIdentifierT TycoIdentifier; + +template class TemplateArgumentsT; +typedef TemplateArgumentsT TemplateArguments; + +template class ClassTycoSpecifierT; +typedef ClassTycoSpecifierT ClassTycoSpecifier; + +template class TypeOfTypeSpecifierT; +typedef TypeOfTypeSpecifierT TypeOfTypeSpecifier; + +template class TypeParameterT; +typedef TypeParameterT TypeParameter; + +template class TycoT; +typedef TycoT Tyco; + +template class ScopeT; +typedef ScopeT Scope; + +//TycoSpecifier := +// TycoIdentifier ("<" TycoSpecifier \ "," ">")* +// | TycoSpecifier "*" +// | TycoSpecifier "(" +// [(TycoSpecifier [Identifier] \ ","] ")" +// | "Class" "{" ClassDefinition "}" +// | "TypeOf" "(" Expression ")" +template class TycoSpecifierT : public ParseTreeObject +{ +public: + static TycoSpecifier parse(CharacterSource* source) + { + TycoSpecifier tycoSpecifier = parseFundamental(source); + if (!tycoSpecifier.valid()) + return TycoSpecifier(); + do { + Span span; + if (Space::parseCharacter(source, '*', &span)) { + tycoSpecifier = create::PointerBody>( + tycoSpecifier, tycoSpecifier.span() + span); + continue; + } + CharacterSource s2 = *source; + if (Space::parseCharacter(&s2, '(', &span)) { + List typeListSpecifier = parseList(&s2); + if (!Space::parseCharacter(&s2, ')', &span)) + return tycoSpecifier; + *source = s2; + tycoSpecifier = create::FunctionBody>( + tycoSpecifier, typeListSpecifier, + tycoSpecifier.span() + span); + continue; + } + break; + } while (true); + return tycoSpecifier; + } + TycoT resolve(const Scope* scope) const + { + return body()->resolve(scope); + } + String toString() const { return body()->toString(); } + TycoSpecifierT() { } +protected: + TycoSpecifierT(Handle other) : ParseTreeObject(other) { } + + class Body : public ParseTreeObject::Body + { + public: + Body(const Span& span) : ParseTreeObject::Body(span) { } + virtual Tyco resolve(const Scope* scope) const = 0; + virtual String toString() const = 0; + }; + class InstantiationBody : public Body + { + public: + InstantiationBody(const TycoIdentifier& tycoIdentifier, + const TemplateArguments& arguments, const Span& span) + : Body(span), _tycoIdentifier(tycoIdentifier), _arguments(arguments) + { } + TycoT resolve(const ScopeT* scope) const + { + TycoT t = scope->resolveTycoIdentifier(_tycoIdentifier); + List> a = _arguments.resolve(scope); + for (auto argument : a) { + TemplateT te = t; + assert(te.valid()); + t = te.instantiate(argument); + } + return t; + } + String toString() const + { + return _tycoIdentifier.toString() + "<" + _arguments.toString() + + ">"; + } + private: + TycoIdentifierT _tycoIdentifier; + TemplateArgumentsT _arguments; + }; + + const Body* body() const { return as(); } +private: + static TycoSpecifier parseFundamental(CharacterSource* source) + { + TycoIdentifierT tycoIdentifier = + TycoIdentifierT::parse(source); + if (tycoIdentifier.valid()) { + String s = tycoIdentifier.name(); + Span span = tycoIdentifier.span(); + TemplateArgumentsT arguments = + TemplateArgumentsT::parse(source); + if (arguments.valid()) { + return create(tycoIdentifier, arguments, + span + arguments.span()); + } + return tycoIdentifier; + } + TycoSpecifier tycoSpecifier = + ClassTycoSpecifierT::parse(source); + if (tycoSpecifier.valid()) + return tycoSpecifier; + tycoSpecifier = TypeOfTypeSpecifierT::parse(source); + if (tycoSpecifier.valid()) + return tycoSpecifier; + return TycoSpecifier(); + } + static List parseList(CharacterSource* source) + { + List list; + TycoSpecifier argument = parse(source); + if (!argument.valid()) + return list; + list.add(argument); + Span span; + while (Space::parseCharacter(source, ',', &span)) { + argument = parse(source); + if (!argument.valid()) + source->location().throwError("Type specifier expected"); + list.add(argument); + } + return list; + } +}; + +template class TemplateArgumentsT : public ParseTreeObject +{ +public: + static TemplateArguments parse(CharacterSource* source) + { + CharacterSource s2 = *source; + List arguments; + Span span; + Span span2; + while (Space::parseCharacter(&s2, '<', &span2)) { + span += span2; + do { + TycoSpecifier argument = TycoSpecifier::parse(&s2); + if (!argument.valid()) + return TemplateArguments(); + arguments.add(argument); + } while (Space::parseCharacter(&s2, ',', &span2)); + if (!Space::parseCharacter(&s2, '>', &span2)) + return TemplateArguments(); + } + *source = s2; + if (arguments.count() == 0) + return TemplateArguments(); + return create(arguments, span + span2); + } + int count() const + { + const Body* body = to(); + if (body != 0) + return body->count(); + return 0; + } + List resolve(const Scope* scope) const + { + return body()->resolve(scope); + } + String toString() const { return body()->toString(); } + + class Body : public ParseTreeObject::Body + { + public: + Body(const List& arguments, const Span& span) + : ParseTreeObject::Body(span), _arguments(arguments) { } + int count() const { return _arguments.count(); } + List resolve(const ScopeT* scope) const + { + List l; + for (auto s : _arguments) + l.add(scope->resolveTycoSpecifier(s)); + return l; + } + String toString() const + { + bool first = true; + String r; + for (auto s : _arguments) { + if (!first) + r += ", "; + first = false; + r += s.toString(); + } + return r; + } + private: + List _arguments; + }; +private: + const Body* body() const { return as(); } + + TemplateArgumentsT() { } + TemplateArgumentsT(Handle other) : ParseTreeObject(other) { } +}; + +template class TypeSpecifierT : public TycoSpecifier +{ +public: + TypeSpecifierT() { } + TypeSpecifierT(Handle other) : TycoSpecifier(other) { } + +private: + class PointerBody : public TycoSpecifier::Body + { + public: + PointerBody(const TycoSpecifier& referent, const Span& span) + : Body(span), _referent(referent) { } + TycoT resolve(const ScopeT* scope) const + { + Type referent = scope->resolveTycoSpecifier(_referent); + return PointerType(referent); + } + String toString() const { return _referent.toString() + "*"; } + private: + TycoSpecifier _referent; + }; + class FunctionBody : public TycoSpecifier::Body + { + public: + FunctionBody(const TycoSpecifier& returnType, + const List& argumentTypes, const Span& span) + : Body(span), _returnType(returnType), + _argumentTypes(argumentTypes) + { } + TycoT resolve(const ScopeT* scope) const + { + Type ret = scope->resolveType(_returnType); + FunctionType f = FunctionTemplateT().instantiate(ret); + for (auto a : _argumentTypes) { + Type t = scope->resolveType(a); + f = f.instantiate(t); + } + return f; + } + String toString() const + { + String r = _returnType.toString() + "("; + bool first = true; + for (auto s : _argumentTypes) { + if (!first) + r += ", "; + first = false; + r += s.toString(); + } + return r + ")"; + } + private: + TycoSpecifier _returnType; + List _argumentTypes; + }; + + template friend class TycoSpecifierT; +}; + +template class TycoIdentifierT : public TycoSpecifier +{ +public: + TycoIdentifierT() { } + TycoIdentifierT(const String& name) + : TycoSpecifier(create(name, Span())) { } + TycoIdentifierT(const TycoSpecifier& tycoSpecifier) + : TycoSpecifier(to(tycoSpecifier)) { } + static TycoIdentifier parse(CharacterSource* source) + { + CharacterSource s = *source; + Location location = s.location(); + int start = s.offset(); + int c = s.get(); + if (c < 'A' || c > 'Z') + return TycoIdentifier(); + CharacterSource s2; + do { + s2 = s; + c = s.get(); + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || c == '_') + continue; + break; + } while (true); + int end = s2.offset(); + Location endLocation = s2.location(); + Space::parse(&s2); + String name = s2.subString(start, end); + static String keywords[] = { + "Class", +// "Complex", +// "DInt", +// "DUInt", +// "DWord", +// "Fixed", +// "Float", +// "HInt", +// "HUInt", +// "HWord", +// "Integer", +// "QInt", +// "QUInt", +// "QWord", +// "Rational", + "TypeOf" +// "Unsigned", +// "WordString" + }; + for (int i = 0; i < sizeof(keywords)/sizeof(keywords[0]); ++i) + if (name == keywords[i]) + return TycoIdentifier(); + *source = s2; + return create(name, Span(location, endLocation)); + } + String name() const { return as()->name(); } + TycoIdentifierT(Handle other) : TycoSpecifier(other) { } +protected: + class Body : public TycoSpecifier::Body + { + public: + Body(const String& name, const Span& span) + : TycoSpecifier::Body(span), _name(name) { } + String name() const { return _name; } + Hash hash() const + { + return TycoSpecifier::Body::hash().mixin(_name.hash()); + } + bool equals(const ConstHandle::Body* other) const + { + auto o = other->to(); + return o != 0 && _name == o->_name; + } + TycoT resolve(const ScopeT* scope) const + { + return scope->resolveTycoIdentifier(handle()); + } + String toString() const { return _name; } + private: + String _name; + }; +}; + +template class ClassTycoSpecifierT : public TycoSpecifier +{ +public: + ClassTycoSpecifierT() { } + ClassTycoSpecifierT(Handle other) : TycoSpecifier(other) { } + static ClassTycoSpecifier parse(CharacterSource* source) + { + Location start = source->location(); + Span span; + if (!Space::parseKeyword(source, "Class", &span)) + return ClassTycoSpecifier(); + Span span2; + Space::assertCharacter(source, '{', &span2); + // TODO: Parse class contents + Space::assertCharacter(source, '}', &span2); + return create(span + span2); + } +private: + class Body : public TycoSpecifier::Body + { + public: + Body(const Span& span) : TycoSpecifier::Body(span) { } + TycoT resolve(const Scope* scope) const + { + // TODO + return TycoT(); + } + String toString() const + { + // TODO + return String(); + } + }; +}; + +template class TypeOfTypeSpecifierT : public TypeSpecifier +{ +public: + TypeOfTypeSpecifierT() { } + TypeOfTypeSpecifierT(Handle other) : TypeSpecifier(other) { } + static TypeOfTypeSpecifier parse(CharacterSource* source) + { + Span span; + if (!Space::parseKeyword(source, "TypeOf", &span)) + return TypeOfTypeSpecifier(); + Span span2; + Space::assertCharacter(source, '(', &span2); + ExpressionT expression = + ExpressionT::parseOrFail(source); + Space::assertCharacter(source, ')', &span2); + return create(expression, span + span2); + } +private: + class Body : public TypeSpecifier::Body + { + public: + Body(const Expression& expression, const Span& span) + : TypeSpecifier::Body(span), _expression(expression) { } + TycoT resolve(const Scope* scope) const + { + return _expression.type(); + } + String toString() const { return _expression.toString(); } + private: + ExpressionT _expression; + }; +}; + +template class TemplateParametersT; +typedef TemplateParametersT TemplateParameters; + +template class TemplateParameterT; +typedef TemplateParameterT TemplateParameter; + +//TemplateParameter = +// TycoSpecifier +// | "@" TycoIdentifier TemplateParameters +// | TemplateParameter "*" +// | TemplateParameter "(" TemplateParameter \ "," ")" +// ; +template class TemplateParameterT : public ParseTreeObject +{ +public: + TemplateParameterT() { } + TemplateParameterT(Handle other) : ParseTreeObject(other) { } + static TemplateParameter parse(CharacterSource* source) + { + TemplateParameter parameter = parseFundamental(source); + if (!parameter.valid()) + return parameter; + do { + Span span; + if (Space::parseCharacter(source, '*', &span)) { + parameter = create::PointerBody>( + parameter, parameter.span() + span); + continue; + } + if (Space::parseCharacter(source, '(', &span)) { + List parameters = parseList(source); + Space::assertCharacter(source, ')', &span); + parameter = create::FunctionBody>( + parameter, parameters, parameter.span() + span); + continue; + } + } while (true); + return parameter; + } +protected: + class Body : public ParseTreeObject::Body + { + public: + Body(const Span& span) : ParseTreeObject::Body(span) { } + }; +private: + static List parseList(CharacterSource* source) + { + List list; + TemplateParameter parameter = parse(source); + if (!parameter.valid()) + return list; + list.add(parameter); + Span span; + while (Space::parseCharacter(source, ',', &span)) { + parameter = parse(source); + if (!parameter.valid()) + source->location().throwError("Template parameter " + "expected"); + list.add(parameter); + } + return list; + } + static TemplateParameter parseFundamental(CharacterSource* source) + { + TycoSpecifier tycoSpecifier = TycoSpecifier::parse(source); + if (tycoSpecifier.valid()) + return create(tycoSpecifier); + Span span; + if (Space::parseCharacter(source, '@', &span)) { + TycoIdentifier tycoIdentifier = TycoIdentifier::parse(source); + if (!tycoIdentifier.valid()) + source->location().throwError( + "Expected type constructor identifier"); + TemplateParametersT parameters = + TemplateParametersT::parse(source); + return create(tycoIdentifier, parameters, + span + parameters.span()); + } + source->location().throwError("Expected template parameter"); + // Not reachable + return TemplateParameter(); + } + + class TycoSpecifierBody : public Body + { + public: + TycoSpecifierBody(const TycoSpecifier& tycoSpecifier) + : Body(tycoSpecifier.span()), + _tycoSpecifier(tycoSpecifier) { } + private: + TycoSpecifier _tycoSpecifier; + }; + class BoundVariableBody : public Body + { + public: + BoundVariableBody(const TycoIdentifier& tycoIdentifier, + const TemplateParameters& parameters, const Span& span) + : Body(span), _tycoIdentifier(tycoIdentifier), + _parameters(parameters) { } + private: + TycoIdentifier _tycoIdentifier; + TemplateParametersT _parameters; + }; +}; + +template class TypeParameterT : public TemplateParameter +{ +public: + class PointerBody : public TemplateParameter::Body + { + public: + PointerBody(const TemplateParameter& parameter, + const Span& span) + : Body(span), _parameter(parameter) { } + private: + TemplateParameter _parameter; + }; + class FunctionBody : public TemplateParameter::Body + { + public: + FunctionBody(const TemplateParameter& parameter, + const List& parameters, const Span& span) + : Body(span), _parameter(parameter), + _parameters(parameters) { } + private: + TemplateParameter _parameter; + List _parameters; + }; +}; + +// TemplateParameters = ("<" TemplateParameter \ "," ">")*; +template class TemplateParametersT : public ParseTreeObject +{ +public: + TemplateParametersT() { } + TemplateParametersT(Handle other) : ParseTreeObject(other) { } + static TemplateParameters parse(CharacterSource* source) + { + CharacterSource s2 = *source; + List parameters; + Span span, span2; + while (Space::parseCharacter(&s2, '<', &span)) { + do { + TemplateParameter parameter = TemplateParameter::parse(&s2); + if (!parameter.valid()) + return TemplateParameters(); + parameters.add(parameter); + } while (Space::parseCharacter(&s2, ',', &span2)); + if (!Space::parseCharacter(&s2, '>', &span2)) + return TemplateParameters(); + } + *source = s2; + return create(parameters, span + span2); + } +private: + class Body : public ParseTreeObject::Body + { + public: + Body(const List& parameters, + const Span& span) + : ParseTreeObject::Body(span), _parameters(parameters) { } + private: + List _parameters; + }; +}; + +//TycoSignifier := TycoIdentifier TemplateParameters +class TycoSignifier : public ParseTreeObject +{ +public: + TycoSignifier(const TycoIdentifier& identifier, + const TemplateParameters& parameters = TemplateParameters()) + : ParseTreeObject(create(identifier, parameters, Span())) { } + static TycoSignifier parse(CharacterSource* source) + { + CharacterSource s2 = *source; + TycoIdentifier identifier = TycoIdentifier::parse(source); + if (!identifier.valid()) + return TycoSignifier(); + TemplateParameters parameters = TemplateParameters::parse(source); + return create(identifier, parameters, + identifier.span() + parameters.span()); + } +private: + TycoSignifier() { } + TycoSignifier(Handle other) : ParseTreeObject(other) { } + + class Body : public ParseTreeObject::Body + { + public: + Body(const TycoIdentifier& identifier, + const TemplateParameters& parameters, const Span& span) + : ParseTreeObject::Body(span), _identifier(identifier), + _parameters(parameters) { } + private: + TycoIdentifier _identifier; + TemplateParameters _parameters; + }; +}; + +#endif // INCLUDED_TYPE_SPECIFIER_H diff --git a/80386/disassembler/include/alfe/types.txt b/80386/disassembler/include/alfe/types.txt new file mode 100644 index 0000000..a3ecd13 --- /dev/null +++ b/80386/disassembler/include/alfe/types.txt @@ -0,0 +1,24 @@ +Kind Kind::Body + Kind::TypeBody + Kind::VariadicBody + TemplateKind TemplateKind::Body + + +Tyco Tyco::Body + Type Type::Body + AtomicType AtomicType::Body + PointerType PointerType::Body + FunctionType FunctionType::Body + EnumerationType EnumerationType::Body + StructuredType StructuredType::Body + Template Template::Body + Template::UninstantiatedBody + Template::PartiallyInstantiatedBody + Template::VariadicBody + Template::InstantiatedBody + +Valco + Value + +Funco + Function diff --git a/80386/disassembler/include/alfe/uncopyable.h b/80386/disassembler/include/alfe/uncopyable.h new file mode 100644 index 0000000..3740a4f --- /dev/null +++ b/80386/disassembler/include/alfe/uncopyable.h @@ -0,0 +1,15 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_UNCOPYABLE_H +#define INCLUDED_UNCOPYABLE_H + +class Uncopyable +{ +public: + Uncopyable() { } +private: + Uncopyable(const Uncopyable& other); + const Uncopyable& operator=(const Uncopyable& other); +}; + +#endif // INCLUDED_UNCOPYABLE_H diff --git a/80386/disassembler/include/alfe/user.h b/80386/disassembler/include/alfe/user.h new file mode 100644 index 0000000..c8130e6 --- /dev/null +++ b/80386/disassembler/include/alfe/user.h @@ -0,0 +1,1516 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_USER_H +#define INCLUDED_USER_H + +#include "alfe/bitmap.h" +#include "alfe/linked_list.h" +#include "alfe/thread.h" + +// TODO: Xlib port + +#include +#include +#include +#include +#include + +template class WindowsWindowT; +typedef WindowsWindowT WindowsWindow; + +template class PaintHandleT; +typedef PaintHandleT PaintHandle; + +class GDIObject : public ConstHandle +{ +public: + GDIObject() { } + GDIObject(HGDIOBJ object) : _object(object) + { + IF_NULL_THROW(object); + ConstHandle::operator=(create(object)); + } + operator HGDIOBJ() const { return _object; } + HGDIOBJ object() const { return _object; } +protected: + class Body : public ConstHandle::Body + { + public: + Body(HGDIOBJ object) : _object(object) { } + ~Body() { DeleteObject(_object); } + HGDIOBJ _object; + }; + HGDIOBJ _object; +}; + +class Font : public GDIObject +{ +public: + Font() : GDIObject(object()) { } + operator HFONT() const { return static_cast(_object); } +private: + HGDIOBJ object() + { + NONCLIENTMETRICS ncm; + ncm.cbSize = sizeof(NONCLIENTMETRICS) - sizeof(ncm.iPaddedBorderWidth); + IF_FALSE_THROW(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, + ncm.cbSize, &ncm, 0)); + return CreateFontIndirect(&ncm.lfMessageFont); + } +}; + +template class WindowsT : Uncopyable +{ +public: + WindowsT() : _failed(false) { } + void check() + { + if (!_failed) + return; + _failed = false; + throw _exception; + } + void stashException(Exception exception) + { + _failed = true; + _exception = exception; + } + bool failed() const { return _failed; } + + const Font* font() const { return &_font; } + +private: + Font _font; + Exception _exception; + bool _failed; +}; + +typedef WindowsT Windows; + +class ContainerWindow; + +template class WindowT; +typedef WindowT Window; + +template class WindowT + : public LinkedListMember> +{ +public: + WindowT() : _parent(0), _topLeft(Vector(0, 0)) { } + ~WindowT() { remove(); } + virtual void create() { layout(); } + virtual void layout() { } + void setParent(ContainerWindow* window) { _parent = window; } + ContainerWindow* parent() const { return _parent; } + + // We call these functions to notify derived classes about events + virtual void innerSizeSet(Vector size) { } + virtual void positionSet(Vector topLeft) { } + // Derived classes override these to implement windows with frames + virtual Vector outerSize() const { return _innerSize; } + virtual Vector outerTopLeft() const { return Vector(0, 0); } + virtual void setInnerSize(Vector size) + { + if (size == _innerSize) + return; + _innerSize = size; + innerSizeSet(size); + } + Vector innerSize() const { return _innerSize; } + Vector origin() const { return _topLeft; } + // These all return outer edges/corners in the parent coordinate system, + // useful for laying out. + int left() const { return _topLeft.x + outerTopLeft().x; } + int top() const { return _topLeft.y + outerTopLeft().y; } + int right() const { return _topLeft.x + outerTopLeft().x + outerSize().x; } + int bottom() const + { + return _topLeft.y + outerTopLeft().y + outerSize().y; + } + Vector topLeft() const { return _topLeft + outerTopLeft(); } + Vector topRight() const { return topLeft() + Vector(outerSize().x, 0); } + Vector bottomRight() const { return topLeft() + outerSize(); } + Vector bottomLeft() const { return topLeft() + Vector(0, outerSize().y); } + virtual void setTopLeft(Vector tl) + { + _topLeft = tl - outerTopLeft(); + positionSet(_topLeft); + } + void setTopRight(Vector topRight) + { + setTopLeft(topRight - Vector(outerSize().x, 0)); + } + void setBottomLeft(Vector bottomLeft) + { + setTopLeft(bottomLeft - Vector(0, outerSize().y)); + } + void setBottomRight(Vector bottomRight) + { + setTopLeft(bottomRight - outerSize()); + } + + virtual void doneResize() { } + virtual void keyboardCharacter(int character) { } + virtual bool keyboardEvent(int key, bool up) { return false; } + //virtual void draw(Bitmap bitmap) { } + + // mouseInput() should return true if the mouse should be captured + virtual bool mouseInput(Vector position, int buttons, int wheel) + { + return false; + } + virtual void releaseCapture() { } + void remove() + { + if (_parent != 0) { + _parent->childRemoved(this); + LinkedListMember>::remove(); + } + } + + // The draw() function should do any updates necessary for an animation and + // (for a BitmapWindow) initiate the process of populating the bitmap. It + // should not take a long time though, as it is called on the UI thread. If + // longer is spent in draw() than the time between animation frames, + // WM_PAINT starvation can result. + virtual void draw() { } + +private: + ContainerWindow* _parent; + Vector _innerSize; + + // _topLeft is the position within the parent window of the origin + // (top-left of inner/client rectangle) of this window. + Vector _topLeft; +}; + +class ContainerWindow : public Window +{ +public: + ContainerWindow() : _focus(0), _capture(0) { } + void create() + { + for (auto& window : _container) { + window.setParent(this); + window.create(); + } + Window::create(); + } + void remove() + { + // Can't use a range-based for loop here because we're + // removing items and continuing. + auto window = _container.next(); + while (window != &_container) { + auto next = window->next(); + window->remove(); + window = next; + } + Window::remove(); + } + void add(Window* window) + { + _container.add(window); + window->setParent(this); + if (_focus == 0) + _focus = window; + } + virtual void childRemoved(Window* child) + { + if (_focus == child) { + _focus = _container.getNext(child); + if (_focus == 0) { + // No more windows after child, try starting from the beginning + // again. + _focus = _container.getNext(); + if (_focus == child) { + // It's an only child, so there's nowhere left to put the + // focus. + _focus = 0; + } + } + } + } + //void draw(Bitmap bitmap) + //{ + // for (auto& window : _container) + // window.draw(bitmap.subBitmap(window.topLeft(), window.outerSize())); + //} + void keyboardCharacter(int character) + { + if (_focus != 0) + _focus->keyboardCharacter(character); + } + bool keyboardEvent(int key, bool up) + { + if (_focus != 0) + return _focus->keyboardEvent(key, up); + return false; + } + bool mouseInput(Vector position, int buttons, int wheel) + { + // If the mouse is captured, send the input to the capturing window + if (_capture != 0) { + _capture->mouseInput(position - _capture->topLeft(), buttons, + wheel); + if (buttons == 0) + releaseCapture(); + return false; + } + // Otherwise, send the input the window under the mouse + Window* window = windowForPosition(position); + if (window != 0) { + bool capture = window->mouseInput(position - window->topLeft(), + buttons, wheel); + if ((buttons & ~_buttons) != 0) { + // A button is newly pressed - put focus on this child window + _focus = window; + } + _buttons = buttons; + if (capture) + _capture = window; + return capture; + } + return false; + } + void releaseCapture() { _capture = 0; } + void repositionChildren() + { + Window* window = _container.getNext(); + while (window != 0) { + window->setTopLeft(window->topLeft()); + window = _container.getNext(window); + } + } + virtual void enableWindow(bool enabled) + { + for (auto& window : _container) + dynamic_cast(&window)->enableWindow(enabled); + } +protected: + LinkedList _container; + Window* _focus; + Window* _capture; + int _buttons; +private: + Window* windowForPosition(Vector p) + { + for (auto& window : _container) { + if ((p - window.topLeft()).inside(window.outerSize())) + return &window; + } + return 0; + } +}; + + +class Menu +{ +public: + Menu(WORD resourceId) + { + HMODULE moduleHandle = GetModuleHandle(NULL); + IF_NULL_THROW(moduleHandle); + _menu = LoadMenu(moduleHandle, MAKEINTRESOURCE(resourceId)); + IF_NULL_THROW(_menu); + } + ~Menu() { DestroyMenu(_menu); } + HMENU hMenu() { return _menu; } +private: + HMENU _menu; +}; + + +class DeviceContext : Uncopyable +{ +public: + void setDC(HDC hdc) { _hdc = hdc; } + void NoFailSelectObject(HGDIOBJ hObject) { ::SelectObject(_hdc, hObject); } + HGDIOBJ SelectObject(HGDIOBJ hObject) + { + HGDIOBJ r = ::SelectObject(_hdc, hObject); + IF_NULL_THROW(r); + return r; + } + void SetROP2(int fnDrawMode) + { + IF_ZERO_THROW(::SetROP2(_hdc, fnDrawMode)); + } + void Polyline(CONST POINT* lppt, int cPoints) + { + IF_ZERO_THROW(::Polyline(_hdc, lppt, cPoints)); + } + operator HDC() const { return _hdc; } +protected: + HDC _hdc; +}; + +class SelectedObject : public ConstHandle +{ +public: + SelectedObject() { } + SelectedObject(DeviceContext* dc, const GDIObject& object) + : ConstHandle(create(dc, object)) { } +private: + class Body : public ConstHandle::Body + { + public: + Body(DeviceContext* dc, const GDIObject& object) : _dc(dc) + { + _previous = dc->SelectObject(object); + } + ~Body() + { + _dc->NoFailSelectObject(_previous); + } + private: + DeviceContext* _dc; + HGDIOBJ _previous; + }; +}; + +class Pen : public GDIObject +{ +public: + Pen(int fnPenStyle, int nWidth, COLORREF crColor) + : GDIObject(CreatePen(fnPenStyle, nWidth, crColor)) { } + operator HPEN() { return static_cast(_object); } +}; + +template class WindowsWindowT : public ContainerWindow +{ + friend class WindowsT; +public: + WindowsWindowT() + : _hWnd(NULL), _resizing(false), _origWndProc(0), _className(0), + _style(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN), _extendedStyle(0), + _menu(NULL), _windowsParent(0), _outerSize(0, 0), _outerTopLeft(0, 0) + { + _dc.setDC(NULL); + ContainerWindow::setInnerSize(Vector(CW_USEDEFAULT, CW_USEDEFAULT)); + ContainerWindow::setTopLeft(Vector(CW_USEDEFAULT, CW_USEDEFAULT)); + } + void setWindows(Windows* windows) { _windows = windows; } + Vector clientToScreen(Vector client) + { + POINT p; + p.x = client.x; + p.y = client.y; + IF_ZERO_THROW(ClientToScreen(_hWnd, &p)); + return Vector(p.x, p.y); + } + Vector mousePosition() + { + POINT point; + IF_ZERO_THROW(GetCursorPos(&point)); + return Vector(point.x, point.y) - clientToScreen(Vector(0, 0)); + } + virtual HWND hWndParent() + { + if (_windowsParent != 0) + return _windowsParent->hWnd(); + return NULL; + } + virtual void create() + { + reset(); + Vector s = adjustRect(innerSize()); + Vector position = topLeft(); + Vector o(0, 0); + + Window* p = parent(); + while (p != 0) { + auto w = dynamic_cast(p); + if (w != 0) { + _windowsParent = w; + _windows = w->_windows; + break; + } + else + o += p->origin(); + p = p->parent(); + } + + position += o; + if (topLeft().x == CW_USEDEFAULT) + position.x = CW_USEDEFAULT; + if (topLeft().y == CW_USEDEFAULT) + position.y = CW_USEDEFAULT; + if (innerSize().x == CW_USEDEFAULT) + s.x = CW_USEDEFAULT; + if (innerSize().y == CW_USEDEFAULT) + s.y = CW_USEDEFAULT; + + NullTerminatedWideString caption(_text); + + HMENU menu = _menu; + if ((_style & WS_CHILD) != 0) + menu = reinterpret_cast(this); + + LPCWSTR className = _className; + // We don't really need to register our own window class - we can use + // one of the built-in classes. Some demoscene sizecoded demos use + // "Edit" for example (but that sets the cursor to the I-beam). And + // WC_STATIC doesn't work with SetLayeredWindowAttributes. + if (className == 0) + className = L"MDIClient"; + + HINSTANCE hInstance = GetModuleHandle(NULL); + IF_ZERO_THROW(hInstance); + _hWnd = CreateWindowEx( + _extendedStyle, + className, + caption, + _style, + position.x, + position.y, + s.x, + s.y, + hWndParent(), + menu, + hInstance, + this); + IF_NULL_THROW(_hWnd); + SetLastError(0); + IF_ZERO_CHECK_THROW_LAST_ERROR(SetWindowLongPtr(_hWnd, GWLP_USERDATA, + reinterpret_cast(this))); + if (_className == 0) + _origWndProc = DefWindowProc; + else { + SetLastError(0); + LONG_PTR r = GetWindowLongPtr(_hWnd, GWLP_WNDPROC); + IF_ZERO_CHECK_THROW_LAST_ERROR(r); + _origWndProc = reinterpret_cast(r); + } + SetLastError(0); + IF_ZERO_CHECK_THROW_LAST_ERROR(SetWindowLongPtr(_hWnd, GWLP_WNDPROC, + reinterpret_cast(wndProc))); + HDC hdc = GetDC(_hWnd); + IF_NULL_THROW(hdc); + _dc.setDC(hdc); + RECT clientRect; + IF_ZERO_THROW(GetClientRect(_hWnd, &clientRect)); + RECT windowRect; + IF_ZERO_THROW(GetWindowRect(_hWnd, &windowRect)); + Vector origin = clientToScreen(Vector(0, 0)); + Vector stl(windowRect.left, windowRect.top); + _outerTopLeft = stl - origin; + _outerSize = Vector(windowRect.right, windowRect.bottom) - stl; + Vector pOrigin(0, 0); + if (_windowsParent != 0) + pOrigin = _windowsParent->clientToScreen(Vector(0, 0)); + + ContainerWindow::setInnerSize(Vector( + clientRect.right - clientRect.left, + clientRect.bottom - clientRect.top)); + ContainerWindow::setTopLeft(origin - (pOrigin + o)); + + SendMessage(_hWnd, WM_SETFONT, reinterpret_cast(font()), + static_cast(FALSE)); + SelectObject(_dc, font()); + + ContainerWindow::create(); + } + + ~WindowsWindowT() { reset(); } + + void show(int nShowCmd) { ShowWindow(_hWnd, nShowCmd); } + + void setText(String text) + { + _text = text; + if (_hWnd != NULL) { + NullTerminatedWideString w(text); + IF_ZERO_THROW(SetWindowText(_hWnd, w)); + } + } + String getText() + { + int l = GetWindowTextLength(_hWnd) + 1; + Array buf(l); + IF_ZERO_CHECK_THROW_LAST_ERROR(GetWindowText(_hWnd, &buf[0], l)); + return String(&buf[0]); + } + + void setInnerSize(Vector size) + { + _outerSize = adjustRect(size); + if (!_resizing) { + if (_hWnd != NULL) { + IF_ZERO_THROW(SetWindowPos( + _hWnd, // hWnd + NULL, // hWndInsertAfter + 0, // X + 0, // Y + _outerSize.x, // cx + _outerSize.y, // cy + SWP_NOZORDER | SWP_NOMOVE | + SWP_NOACTIVATE | SWP_NOREPOSITION | + SWP_NOREDRAW | SWP_ASYNCWINDOWPOS)); // uFlags + // ContainerWindow::setInnerSize() will be called via WM_SIZE, + // but we want to make sure our size is set correctly now so it + // can be used for layout before the message loop next runs. + } + } + ContainerWindow::setInnerSize(size); + } + + void setTopLeft(Vector position) + { + if (_hWnd != NULL) { + Vector tl = position + _outerTopLeft; + Window* p = parent(); + while (p != 0 && p != static_cast(_windowsParent)) { + tl += p->origin(); + p = p->parent(); + } + IF_ZERO_THROW(SetWindowPos( + _hWnd, // hWnd + NULL, // hWndInsertAfter + tl.x, // X + tl.y, // Y + 0, // cx + 0, // cy + SWP_NOZORDER | SWP_NOSIZE | + SWP_NOACTIVATE | SWP_NOREPOSITION | + SWP_NOREDRAW | SWP_ASYNCWINDOWPOS)); // uFlags + // ContainerWindow::setTopLeft() will be called via WM_MOVE, but we + // want to make sure our position is set correctly now so it can be + // used for layout before the message loop next runs. + } + ContainerWindow::setTopLeft(position); + } + HWND hWnd() const { return _hWnd; } + HDC getDC() { return _dc; } + HFONT font() { return *_windows->font(); } + + void postMessage(UINT msg, WPARAM wParam = 0, LPARAM lParam = 0) + { + PostMessage(_hWnd, msg, wParam, lParam); + } + + void updateWindow() + { + if (_hWnd != NULL) + IF_ZERO_THROW(UpdateWindow(_hWnd)); + } + void redrawWindow(Vector topLeft, Vector size, UINT flags) + { + if (_hWnd == NULL) + return; + RECT rect; + rect.left = topLeft.x; + rect.top = topLeft.y; + rect.right = topLeft.x + size.x; + rect.bottom = topLeft.y + size.y; + IF_ZERO_THROW(RedrawWindow(_hWnd, &rect, NULL, flags)); + } + void redrawWindow(UINT flags) + { + redrawWindow(Vector(0, 0), outerSize(), flags); + } + void enableWindow(bool enabled) + { + EnableWindow(_hWnd, enabled ? TRUE : FALSE); + ContainerWindow::enableWindow(enabled); + } + void invalidate() { redrawWindow(RDW_INVALIDATE | RDW_FRAME); } + Vector outerSize() const { return _outerSize; } + Vector outerTopLeft() const { return _outerTopLeft; } + Vector screenToClient(Vector screen) + { + POINT p; + p.x = screen.x; + p.y = screen.y; + IF_ZERO_THROW(ScreenToClient(_hWnd, &p)); + return Vector(p.x, p.y); + } +private: + Vector adjustRect(Vector size) + { + RECT rect; + rect.left = 0; + rect.right = size.x; + rect.top = 0; + rect.bottom = size.y; + AdjustWindowRectEx(&rect, _style, FALSE, _extendedStyle); + return Vector(rect.right - rect.left, rect.bottom - rect.top); + } + + void destroy() + { + if (getDC() != NULL) { + ReleaseDC(_hWnd, _dc); + _dc.setDC(NULL); + } + _hWnd = NULL; + } + + void reset() + { + if (getDC() != NULL) { + ReleaseDC(_hWnd, _dc); + _dc.setDC(NULL); + } + if (_hWnd != NULL) { + DestroyWindow(_hWnd); + _hWnd = NULL; + } + } + + void setHwnd(HWND hWnd) { _hWnd = hWnd; } +protected: + virtual bool command(WORD code) { return false; } + virtual bool hScroll(WORD code, WORD position) { return false; } + virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + int w = static_cast(wParam); + switch (uMsg) { + case WM_SIZING: + { + _resizing = true; + RECT* r = reinterpret_cast(lParam); + Vector requestedSize(r->right - r->left, + r->bottom - r->top); + Vector adjust = adjustRect(innerSize()) - innerSize(); + ContainerWindow::setInnerSize(requestedSize - adjust); + Vector adjustedSize = adjustRect(innerSize()); + if (wParam == WMSZ_TOPLEFT || wParam == WMSZ_LEFT || + wParam == WMSZ_BOTTOMLEFT) + r->left = r->right - adjustedSize.x; + if (wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOP || + wParam == WMSZ_TOPRIGHT) + r->top = r->bottom - adjustedSize.y; + if (wParam == WMSZ_TOPRIGHT || wParam == WMSZ_RIGHT || + wParam == WMSZ_BOTTOMRIGHT) + r->right = r->left + adjustedSize.x; + if (wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOM || + wParam == WMSZ_BOTTOMRIGHT) + r->bottom = r->top + adjustedSize.y; + } + return TRUE; + case WM_MOVE: + ContainerWindow::setTopLeft( + vectorFromLParam(lParam) + _outerTopLeft); + break; + case WM_EXITSIZEMOVE: + if (_resizing) + doneResize(); + _resizing = false; + break; + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MOUSEMOVE: + case WM_MOUSEWHEEL: + { + int buttons; + int wheel; + Vector position = vectorFromLParam(lParam); + if (uMsg == WM_MOUSEWHEEL) { + buttons = GET_KEYSTATE_WPARAM(wParam); + wheel = GET_WHEEL_DELTA_WPARAM(wParam); + position = screenToClient(position); + } + else { + buttons = w; + wheel = 0; + } + if (mouseInput(position, buttons, wheel)) + SetCapture(_hWnd); + } + break; + case WM_CHAR: + keyboardCharacter(w); + break; + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (keyboardEvent(w, false)) + return 0; + break; + case WM_KEYUP: + case WM_SYSKEYUP: + if (keyboardEvent(w, true)) + return 0; + break; + case WM_KILLFOCUS: + releaseCapture(); + break; + case WM_GETDLGCODE: + return DLGC_WANTMESSAGE; + case WM_COMMAND: + if (lParam != 0) { + WindowsWindow* window = getContext(lParam); + if (window != 0 && window->command(HIWORD(wParam))) + return 0; + } + else { + if (LOWORD(wParam) == IDCANCEL) + keyboardCharacter(VK_ESCAPE); + } + break; + case WM_HSCROLL: + if (lParam != 0) { + if (getContext(lParam)->hScroll(LOWORD(wParam), + HIWORD(wParam))) + return 0; + } + break; + case WM_NCDESTROY: + destroy(); + remove(); + break; + } + return originalHandleMessage(uMsg, wParam, lParam); + } + void erase(bool invalidateChildren = false) + { + PaintHandle paintHandle(this); + if (paintHandle.zeroArea()) + return; + if (!paintHandle.erase()) + return; + HBRUSH hBrush = GetSysColorBrush(COLOR_BTNFACE); + SelectedObject bo(&paintHandle, hBrush); + Pen pen(PS_SOLID, 1, GetSysColor(COLOR_BTNFACE)); + SelectedObject po(&paintHandle, pen); + Vector tl = paintHandle.topLeft(); + Vector br = paintHandle.bottomRight(); + Rectangle(paintHandle, tl.x, tl.y, br.x, br.y); + if (invalidateChildren) { + redrawWindow(tl, br - tl, + RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); + } + } + LRESULT originalHandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + return CallWindowProc(_origWndProc, _hWnd, uMsg, wParam, lParam); + } + + void releaseCapture() + { + ReleaseCapture(); + ContainerWindow::releaseCapture(); + } + + static Vector vectorFromLParam(LPARAM lParam) + { + return Vector(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + } + + void setClassName(LPCWSTR className) { _className = className; } + + void setStyle(DWORD style) { _style = style; } + void setExtendedStyle(DWORD extendedStyle) + { + _extendedStyle = extendedStyle; + } + + HWND _hWnd; + DeviceContext _dc; + String _text; + DWORD _style; + Vector _outerSize; + Vector _outerTopLeft; +private: + bool _resizing; + Windows* _windows; + WindowsWindow* _windowsParent; + DWORD _extendedStyle; + LPCWSTR _className; + HMENU _menu; + WNDPROC _origWndProc; + + static WindowsWindow* getContext(LPARAM lParam) + { + return getContext(reinterpret_cast(lParam)); + } + + static WindowsWindow* getContext(HWND hWnd) + { + SetLastError(0); + LONG_PTR r = GetWindowLongPtr(hWnd, GWLP_USERDATA); + IF_ZERO_CHECK_THROW_LAST_ERROR(r); + return reinterpret_cast(r); + } + + LRESULT windowProcedure(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + // Avoid reentering and causing a cascade of alerts if an assert fails. + if (!alerting && !_windows->failed()) { + BEGIN_CHECKED { + return handleMessage(uMsg, wParam, lParam); + } END_CHECKED(Exception& e) { + PostQuitMessage(0); + _windows->stashException(e); + } + } + return originalHandleMessage(uMsg, wParam, lParam); + } + + static LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam) + { + return getContext(hWnd)->handleMessage(uMsg, wParam, lParam); + } +}; + +template class PaintHandleT : public DeviceContext +{ +public: + PaintHandleT(const WindowsWindow* window) : _window(window) + { + IF_NULL_THROW(BeginPaint(_window->hWnd(), &_ps)); + _hdc = _ps.hdc; + } + ~PaintHandleT() { EndPaint(_window->hWnd(), &_ps); } + Vector topLeft() const + { + return Vector(_ps.rcPaint.left, _ps.rcPaint.top); + } + Vector bottomRight() const + { + return Vector(_ps.rcPaint.right, _ps.rcPaint.bottom); + } + bool zeroArea() const { return (topLeft() - bottomRight()).zeroArea(); } + bool erase() const { return _ps.fErase != 0; } +private: + const WindowsWindow* _window; + PAINTSTRUCT _ps; +}; + +class CompoundWindow : public WindowsWindow +{ +public: + LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + if (uMsg == WM_PAINT) { + erase(); + return 0; + } + if (uMsg == WM_ERASEBKGND) + return 0; + if (uMsg == WM_SIZE) { + Vector s = vectorFromLParam(lParam); + if (s != innerSize()) { + ContainerWindow::setInnerSize(s); + redrawWindow(RDW_INVALIDATE | RDW_ALLCHILDREN); + } + return 0; + } + return WindowsWindow::handleMessage(uMsg, wParam, lParam); + } +}; + +class RootWindow : public CompoundWindow +{ +public: + void childRemoved(Window* child) + { + if (_container.getNext(child) == 0 && _container.getNext() == child) { + // Once there are no more child windows left, the thread must + // end. + PostQuitMessage(0); + } + CompoundWindow::childRemoved(child); + } +}; + +class AnimatedWindow : public WindowsWindow +{ +public: + AnimatedWindow() + : _period(50), _timerExpired(true), _delta(0), _lastTickCount(0) { } + void setDrawWindow(Window* window) + { + _drawWindow = window; + } + void setRate(float rate) { _period = 1000.0f/rate; } + void stop() { KillTimer(_hWnd, _timer); _stopped = true; } + void start() + { + stop(); + _stopped = false; + _timerExpired = true; + _drawWindow->draw(); + } + // Invalidation window needs to call this on paint or invalidate to restart + // timer. + void restart() + { + if (_timerExpired && !_stopped) { + DWORD tickCount = GetTickCount(); + _delta += static_cast(tickCount - _lastTickCount); + _lastTickCount = tickCount; + int ms = static_cast(-_delta); + _delta -= _period; + if (ms < -2.0f*_period) { + // Rather than trying to catch up by generating lots of + // events, we'll reset the clock if we're running too + // far behind. + _delta = 0; + ms = 0; + } + if (ms > 2.0f*max( + _period, static_cast(USER_TIMER_MINIMUM))) { + // Chances are we're starting up and the tick count + // wrapped. + _delta = 0; + ms = static_cast(_period) + 1; + } + if (ms < 0) + ms = 0; + if (ms >= USER_TIMER_MINIMUM) { + _timer = SetTimer(_hWnd, 1, static_cast(ms), NULL); + IF_ZERO_THROW(_timer); + } + else + postMessage(WM_TIMER, 1, 0); + _timerExpired = false; + } + } + +protected: + virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + switch (uMsg) { + case WM_TIMER: + if (wParam == 1) + start(); + break; + } + return WindowsWindow::handleMessage(uMsg, wParam, lParam); + } + +private: + UINT_PTR _timer; + bool _timerExpired; + float _period; + float _delta; + DWORD _lastTickCount; + bool _stopped; + Window* _drawWindow; +}; + +class Button : public WindowsWindow +{ +public: + Button() : _checked(false) + { + setClassName(WC_BUTTON); + setStyle(BS_PUSHBUTTON | BS_TEXT | WS_CHILD | WS_VISIBLE | WS_TABSTOP); + } + virtual void clicked(bool value) { _clicked(value); } + void setClicked(std::function clicked) { _clicked = clicked; } + void create() + { + WindowsWindow::create(); + SIZE s; + NullTerminatedWideString w(_text); + IF_ZERO_THROW(GetTextExtentPoint32(_dc, w, _text.length(), &s)); + Vector size(s.cx + 20, s.cy + 10); + setInnerSize(size); + setCheckState(_checked); + } + bool checked() { return _checked; } + void uncheck() + { + if (_hWnd != NULL) + SendMessage(_hWnd, BM_SETCHECK, static_cast(FALSE), 0); + _checked = false; + } + void check() + { + if (_hWnd != NULL) + SendMessage(_hWnd, BM_SETCHECK, static_cast(TRUE), 0); + _checked = true; + } + void setCheckState(bool checked) + { + if (checked) + check(); + else + uncheck(); + } + bool command(WORD code) + { + if (code == BN_CLICKED) { + clicked( + (Button_GetState(_hWnd) & (BST_CHECKED | BST_PUSHED)) != 0); + return true; + } + return false; + } +private: + bool _checked; + std::function _clicked; +}; + +class ToggleButton : public Button +{ +public: + void create() + { + setStyle(BS_AUTOCHECKBOX | BS_PUSHLIKE | BS_PUSHBUTTON | BS_TEXT | + WS_CHILD | WS_VISIBLE | WS_TABSTOP); + Button::create(); + } +}; + +class CheckBox : public Button +{ +public: + void create() + { + setStyle(BS_AUTOCHECKBOX | BS_TEXT | WS_CHILD | WS_VISIBLE | + WS_TABSTOP); + Button::create(); + } +}; + +class GroupBox : public Button +{ +public: + GroupBox() + { + setStyle(BS_GROUPBOX | BS_TEXT | WS_CHILD | WS_VISIBLE); + } + // The code in Button::create() isn't appropriate for GroupBox + void create() { WindowsWindow::create(); } + LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + if (uMsg == WM_PAINT) + erase(true); + if (uMsg == WM_ERASEBKGND) + return 0; + return WindowsWindow::handleMessage(uMsg, wParam, lParam); + } +}; + +class TextWindow : public WindowsWindow +{ +public: + TextWindow() + { + setClassName(WC_STATIC); + setStyle(WS_CHILD | WS_VISIBLE | /*SS_CENTER |*/ SS_CENTERIMAGE); + } + void layout() + { + if (_hWnd != NULL) { + SIZE s; + NullTerminatedWideString w(_text); + IF_ZERO_THROW(GetTextExtentPoint32(_dc, w, _text.length(), &s)); + setInnerSize(Vector(s.cx, s.cy)); + } + } +}; + +class EditWindow : public WindowsWindow +{ +public: + EditWindow() + { + setClassName(WC_EDIT); + setStyle(WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL); + } + virtual void changed() { } + void layout() + { + TEXTMETRIC metric; + GetTextMetrics(getDC(), &metric); + setInnerSize(Vector(44, metric.tmHeight)); + } + bool command(WORD code) + { + if (code == EN_CHANGE) { + changed(); + return true; + } + return false; + } +}; + +class Slider : public WindowsWindow +{ +public: + Slider() : _min(0), _pos(0), _max(1) + { + setClassName(TRACKBAR_CLASS); + setStyle(WS_CHILD | WS_VISIBLE | WS_TABSTOP); + } + virtual void valueSet(double value) { } + void create() + { + WindowsWindow::create(); + SendMessage(_hWnd, TBM_SETRANGE, static_cast(TRUE), + static_cast(MAKELONG(0, 16384))); + setValue(_pos); + } + void setValue(double pos) + { + _pos = pos; + if (_hWnd != NULL) { + int iPos = + static_cast(((pos - _min) * 16384)/(_max - _min) + 0.5); + SendMessage(_hWnd, TBM_SETPOS, static_cast(TRUE), + static_cast(iPos)); + } + valueSet(pos); + } + void setRange(double min, double max) { _min = min; _max = max; } + void updateValue(int pos) + { + _pos = pos*(_max - _min) / 16384 + _min; + valueSet(_pos); + } + double getValue() const { return _pos; } + bool hScroll(WORD code, WORD position) + { + updateValue(static_cast(SendMessage(_hWnd, TBM_GETPOS, 0, 0))); + return true; + } +private: + double _min; + double _max; + double _pos; +}; + +class ProgressBar : public WindowsWindow +{ +public: + ProgressBar() : _pos(0) + { + setClassName(PROGRESS_CLASS); + setStyle(WS_CHILD | WS_VISIBLE | PBS_SMOOTH); + } + virtual void valueSet(double value) { } + void create() + { + WindowsWindow::create(); + SendMessage(_hWnd, PBM_SETRANGE, static_cast(TRUE), + static_cast(MAKELONG(0, 16384))); + setValue(_pos); + } + void setValue(float pos) + { + _pos = pos; + if (_hWnd != NULL) { + int iPos = static_cast(pos*16384 + 0.5); + SendMessage(_hWnd, PBM_SETPOS, static_cast(iPos), + static_cast(0)); + } + } +private: + float _pos; +}; + +template class NumericSliderWindow +{ +public: + void setText(String text) { _caption.setText(text); } + void setHost(T* host) + { + _host = host; + host->add(&_slider); + host->add(&_caption); + host->add(&_text); + _slider.setHost(this); + } + void setPositionAndSize(Vector position, Vector size) + { + _slider.setInnerSize(size); + _slider.setTopLeft(position); + _caption.setTopLeft(_slider.bottomLeft() + Vector(0, 15)); + _text.setTopLeft(_caption.topRight()); + } + Vector bottomLeft() { return _caption.bottomLeft(); } + int right() const { return _slider.right(); } + void setRange(double low, double high) + { + _slider.setRange(positionFromValue(low), positionFromValue(high)); + } + void setValue(double value) { _slider.setValue(positionFromValue(value)); } + double getValue() { return valueFromPosition(_slider.getValue()); } + +protected: + virtual void create() { } + virtual void valueSet(double value) { } + virtual double positionFromValue(double value) { return value; } + virtual double valueFromPosition(double position) { return position; } + + T* _host; +private: + void valueSet1(double value) + { + double v = valueFromPosition(value); + _text.setText(format("%f", v)); + _text.layout(); + valueSet(v); + } + + class NumericSlider : public Slider + { + public: + void setHost(NumericSliderWindow* host) { _host = host; } + void valueSet(double value) { _host->valueSet1(value); } + void create() { _host->create(); Slider::create(); } + private: + NumericSliderWindow* _host; + }; + NumericSlider _slider; + TextWindow _caption; + TextWindow _text; + friend class NumericSlider; +}; + +class DropDownList : public WindowsWindow +{ +public: + DropDownList() : _value(0) + { + setClassName(WC_COMBOBOX); + setStyle(WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP); + } + virtual void changed(int value) { _changed(value); } + void setChanged(std::function changed) { _changed = changed; } + void create() + { + WindowsWindow::create(); + for (auto s : _entries) { + NullTerminatedWideString ns(s); + int r = static_cast(SendMessage(_hWnd, CB_ADDSTRING, 0, + reinterpret_cast(ns.operator WCHAR *()))); + IF_FALSE_THROW(r != CB_ERR && r != CB_ERRSPACE); + } + set(_value); + } + void set(int value) + { + if (_hWnd != NULL) + IF_FALSE_THROW(ComboBox_SetCurSel(_hWnd, value) != CB_ERR); + _value = value; + } + void add(String s) { _entries.add(s); } + void layout() + { + int width = 0; + for (auto s : _entries) { + NullTerminatedWideString ns(s); + SIZE size; + IF_ZERO_THROW(GetTextExtentPoint32(_dc, ns, s.length(), &size)); + width = max(width, static_cast(size.cx)); + } + COMBOBOXINFO info = { sizeof(COMBOBOXINFO) }; + IF_ZERO_THROW(GetComboBoxInfo(_hWnd, &info)); + setInnerSize(Vector(10 + width + + info.rcButton.right - info.rcButton.left, 200)); + RECT rect; + IF_ZERO_THROW(GetClientRect(info.hwndCombo, &rect)); + _outerSize = Vector(rect.right - rect.left, rect.bottom - rect.top); + } + bool command(WORD code) + { + if (code == CBN_SELCHANGE) { + int v = ComboBox_GetCurSel(_hWnd); + IF_FALSE_THROW(v != CB_ERR); + changed(v); + return true; + } + return false; + } +private: + List _entries; + int _value; + std::function _changed; +}; + +class CaptionedDropDownList : public ContainerWindow +{ +public: + CaptionedDropDownList() + { + ContainerWindow::add(&_caption); + ContainerWindow::add(&_list); + } + void setText(String text) { _caption.setText(text); } + void add(String s) { _list.add(s); } + void set(int value) { _list.set(value); } + void layout() + { + int captionHeight = _caption.outerSize().y; + int listHeight = _list.outerSize().y; + int captionY = 0; + int listY = 0; + if (captionHeight > listHeight) + listY = (captionHeight - listHeight)/2; + else + captionY = (listHeight - captionHeight)/2; + _caption.setTopLeft(Vector(0, captionY)); + _list.setTopLeft(Vector(_caption.right() + 10, listY)); + setInnerSize( + Vector(_list.right(), max(_caption.bottom(), _list.bottom()))); + } + void setChanged(std::function changed) + { + _list.setChanged(changed); + } + void setTopLeft(Vector topLeft) + { + ContainerWindow::setTopLeft(topLeft); + repositionChildren(); + } +private: + TextWindow _caption; + DropDownList _list; +}; + +class WindowDeviceContext : public DeviceContext +{ +public: + WindowDeviceContext(HWND hWnd) : _hWnd(hWnd) + { + _hdc = GetDC(_hWnd); + IF_NULL_THROW(_hdc); + } + ~WindowDeviceContext() { ReleaseDC(_hWnd, _hdc); } +private: + HWND _hWnd; +}; + +class OwnedDeviceContext : public DeviceContext +{ +public: + OwnedDeviceContext(HDC hdc) + { + _hdc = hdc; + IF_NULL_THROW(_hdc); + } + ~OwnedDeviceContext() { DeleteDC(_hdc); } +}; + + +class BitmapWindow : public WindowsWindow +{ +public: + BitmapWindow() + { + setClassName(WC_STATIC); + setStyle(WS_CHILD | WS_VISIBLE | SS_OWNERDRAW); + } + void create() + { + ZeroMemory(&_bmi, sizeof(BITMAPINFO)); + _bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + _bmi.bmiHeader.biPlanes = 1; + _bmi.bmiHeader.biBitCount = 32; + _bmi.bmiHeader.biCompression = BI_RGB; + _bmi.bmiHeader.biSizeImage = 0; + _bmi.bmiHeader.biXPelsPerMeter = 0; + _bmi.bmiHeader.biYPelsPerMeter = 0; + _bmi.bmiHeader.biClrUsed = 0; + _bmi.bmiHeader.biClrImportant = 0; + draw(); + WindowsWindow::create(); + } + + // Override this if you just want a simple bitmap that is updated from the + // UI thread. + virtual void draw2() { } + + // Override this to have more control, e.g. for a rendering from a + // different thread. + void draw() + { + _bitmap.ensure(innerSize()); + draw2(); + invalidate(); + } + + void innerSizeSet(Vector size) + { + if (!size.zeroArea()) + draw(); + } + + virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) + { + switch (uMsg) { + case WM_PAINT: + { + PaintHandle paintHandle(this); + if (paintHandle.zeroArea()) + return 0; + if (!_bitmap.valid()) + return 0; + Vector ptl = paintHandle.topLeft(); + Vector pbr = paintHandle.bottomRight(); + Vector br = _bitmap.size(); + pbr = Vector(min(pbr.x, br.x), min(pbr.y, br.y)); + Vector ps = pbr - ptl; + if (ps.x <= 0 || ps.y <= 0) + return 0; + Vector s = _bitmap.size(); + _bmi.bmiHeader.biWidth = + _bitmap.stride() / sizeof(DWORD); + _bmi.bmiHeader.biHeight = -s.y; + paint(); + IF_ZERO_THROW(SetDIBitsToDevice( + paintHandle, + ptl.x, + ptl.y, + ps.x, + ps.y, + ptl.x, + s.y - pbr.y, + 0, + s.y, + _bitmap.data(), + &_bmi, + DIB_RGB_COLORS)); + return 0; + } + case WM_USER: + { + Lock lock(&_mutex); + _lastBitmap = _bitmap; + _bitmap = _nextBitmap; + return 0; + } + } + return WindowsWindow::handleMessage(uMsg, wParam, lParam); + } + + // Override this to restart animation only when painting actually happens. + virtual void paint() { }; + + Bitmap setNextBitmap(Bitmap nextBitmap) + { + Lock lock(&_mutex); + _nextBitmap = nextBitmap; + postMessage(WM_USER); + invalidate(); + return _lastBitmap; + } + + int stride() const { return _bitmap.stride(); } + const Byte* data() const { return _bitmap.data(); } + Byte* data() { return _bitmap.data(); } + Bitmap bitmap() { return _bitmap; } +protected: + Bitmap _bitmap; + +private: + Mutex _mutex; + + Bitmap _nextBitmap; + Bitmap _lastBitmap; + + BITMAPINFO _bmi; +}; + +#endif // INCLUDED_USER_H diff --git a/80386/disassembler/include/alfe/user.txt b/80386/disassembler/include/alfe/user.txt new file mode 100644 index 0000000..a364eb8 --- /dev/null +++ b/80386/disassembler/include/alfe/user.txt @@ -0,0 +1,66 @@ +Window is a lightweight class that represents an element in the layout hierarchy. Examples: + Image + Button + +Some windows can contain other windows - these are ContainerWindow objects + +WindowsWindow is a ContainerWindow that has an HWND + + + +ImageWindow inherits from Window rather than WindowsWindow but you can get around this by putting an ImageWindow inside a WindowsWindow + + + + + +Consider the case of calibrate4: + We want to have some customizations (caption, size) on the WindowsWindow + Therefore the WindowsWindow should be the one that is specified in the template argument of WindowProgram + The CalibrateWindow class should be responsible for adding any child windows that it needs + + + + + +When a window is clicked, give it focus and pass the click on to the child +Handle capture +Fix focus when child window with focus is removed + Have a null focus? + Null focus means that the focus is on the container window itself + Pass focus onto the next child? + Still need a null focus if there are no children remaining +If a child has focus then the parent has focus as well + + + + + +How does invalidation work? + A window calls invalidate() to request that it be repainted + If it is a WindowsWindow this calls InvalidateRect + If it is a child window then it calls invalidate() on the parent window with the region + + + +How does resize work for a BitmapWindow + + + +Figure out animation + Assume a WM_TIMER message does an invalidate and a timer reset + i.e. just include the functionality in WindowsWindow + Or, should we allow any Window to be animated? + In that case, we might want to use thread rather than windows timer messages + thread is not interruptable (unless we do a WaitForObject kind of thing) + This kind of animation is one that automatically pauses if the window is covered - i.e. not synchronous with a simulation + + + + +We would like to be able to write programs in an OS-native style or a portable style (and even mix styles) + OS-native style puts OS-native controls directly into a WindowsWindow + Portable style uses a BitmapWindow and draws controls on the bitmap + + + diff --git a/80386/disassembler/include/alfe/vectors.h b/80386/disassembler/include/alfe/vectors.h new file mode 100644 index 0000000..db15fed --- /dev/null +++ b/80386/disassembler/include/alfe/vectors.h @@ -0,0 +1,472 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_VECTORS_H +#define INCLUDED_VECTORS_H + +#include "alfe/rotors.h" + +template class Complex; + +template class Vector2 +{ +public: + Vector2() { } + Vector2(T xx, T yy) : x(xx), y(yy) { } + Vector2(const Vector2& other) : x(other.x), y(other.y) { } + template Vector2(const Vector2& o) : x(o.x), y(o.y) { } + template Vector2(const Complex& o) : x(o.x), y(o.y) { } + const Vector2& operator=(const Vector2& o) + { + x = o.x; + y = o.y; + return *this; + } + bool operator==(const Vector2& o) const { return x == o.x && y == o.y; } + bool operator!=(const Vector2& o) const { return x != o.x || y != o.y; } + const Vector2& operator+=(const T& n) { x += n; y += n; return *this; } + const Vector2& operator-=(const T& n) { x -= n; y -= n; return *this; } + const Vector2& operator*=(const T& n) { x *= n; y *= n; return *this; } + const Vector2& operator/=(const T& n) { x /= n; y /= n; return *this; } + const Vector2& operator%=(const T& n) { x %= n; y %= n; return *this; } + const Vector2& operator&=(const T& n) { x &= n; y &= n; return *this; } + const Vector2& operator|=(const T& n) { x |= n; y |= n; return *this; } + const Vector2& operator+=(const Vector2& o) + { + x += o.x; + y += o.y; + return *this; + } + const Vector2& operator-=(const Vector2& o) + { + x -= o.x; + y -= o.y; + return *this; + } + const Vector2& operator*=(const Vector2& o) + { + x *= o.x; + y *= o.y; + return *this; + } + const Vector2& operator/=(const Vector2& o) + { + x /= o.x; + y /= o.y; + return *this; + } + const Vector2& operator%=(const Vector2& o) + { + x %= o.x; + y %= o.y; + return *this; + } + const Vector2& operator&=(const Vector2& o) + { + x &= o.x; + y &= o.y; + return *this; + } + const Vector2& operator|=(const Vector2& o) + { + x |= o.x; + y |= o.y; + return *this; + } + const Vector2& operator>>=(int n) { x >>= n; y >>= n; return *this; } + const Vector2& operator<<=(int n) { x <<= n; y <<= n; return *this; } + Vector2 operator+(const T& n) const { Vector2 t = *this; return t += n; } + Vector2 operator-(const T& n) const { Vector2 t = *this; return t -= n; } + Vector2 operator*(const T& n) const { Vector2 t = *this; return t *= n; } + Vector2 operator/(const T& n) const { Vector2 t = *this; return t /= n; } + Vector2 operator%(const T& n) const { Vector2 t = *this; return t %= n; } + Vector2 operator&(const T& n) const { Vector2 t = *this; return t &= n; } + Vector2 operator|(const T& n) const { Vector2 t = *this; return t |= n; } + Vector2 operator+(const Vector2& o) const + { + Vector2 t = *this; + return t += o; + } + Vector2 operator-(const Vector2& o) const + { + Vector2 t = *this; + return t -= o; + } + Vector2 operator*(const Vector2& o) const + { + Vector2 t = *this; + return t *= o; + } + Vector2 operator/(const Vector2& o) const + { + Vector2 t = *this; + return t /= o; + } + Vector2 operator%(const Vector2& o) const + { + Vector2 t = *this; + return t %= o; + } + Vector2 operator&(const Vector2& o) const + { + Vector2 t = *this; + return t &= o; + } + Vector2 operator|(const Vector2& o) const + { + Vector2 t = *this; + return t |= o; + } + Vector2 operator>>(int n) const { Vector2 t = *this; return t >>= n; } + Vector2 operator<<(int n) const { Vector2 t = *this; return t <<= n; } + template Vector2 operator*(const Rotor2& r) const + { + T2 matrix[4]; + r.toMatrix(matrix); + return Vector2( + matrix[0]*x + matrix[1]*y, + matrix[2]*x + matrix[3]*y); + } + template Vector2 operator/(const Rotor2& r) const + { + return (*this) * r.conjugate(); + } + Vector2 operator-() const { return Vector2(-x, -y); } + bool zeroArea() const { return x == 0 || y == 0; } + T modulus2() const { return x*x + y*y; } + bool inside(const Vector2& area) const + { + return x >= 0 && y >= 0 && x < area.x && y < area.y; + } + + T x; + T y; +}; + +template T dot(const Vector2& a, const Vector2& b) +{ + return a.x*b.x + a.y*b.y; +} + +template T cross(const Vector2& a, const Vector2& b) +{ + return a.x*b.y - a.y*b.x; +} + +template Vector2 operator+(const T& n, const Vector2& v) +{ + return v + n; +} +template Vector2 operator-(const T& n, const Vector2& v) +{ + return (-v) + n; +} +template Vector2 operator*(const T& n, const Vector2& v) +{ + return v * n; +} +template Vector2 operator/(const T& n, const Vector2& v) +{ + return Vector2(n/v.x, n/v.y); +} +template Vector2 operator%(const T& n, const Vector2& v) +{ + return Vector2(n%v.x, n%v.y); +} +template Vector2 operator&(const T& n, const Vector2& v) +{ + return v & n; +} +template Vector2 operator|(const T& n, const Vector2& v) +{ + return v | n; +} +template Vector2 operator^(const T& n, const Vector2& v) +{ + return v ^ n; +} + +template Vector2 floor(const Vector2& vector) +{ + return Vector2(floor(vector.x), floor(vector.y)); +} + +template class Vector2Cast : public Vector2 +{ +public: + template Vector2Cast(const Vector2& other) + : Vector2(static_cast(other.x), static_cast(other.y)) { } + template Vector2Cast(const T2& x, const T2& y) + : Vector2(static_cast(x), static_cast(y)) { } +}; + +typedef Vector2 Vector; + +template class Vector3 +{ +public: + Vector3() { } + Vector3(T xx, T yy, T zz) : x(xx), y(yy), z(zz) { } + Vector3(const Vector3& other) : x(other.x), y(other.y), z(other.z) { } + template Vector3(const Vector3& o) : x(o.x), y(o.y), z(o.z) + { } + const Vector3& operator=(const Vector3& o) + { + x = o.x; + y = o.y; + z = o.z; + return *this; + } + bool operator==(const Vector3& o) const + { + return x == o.x && y == o.y && z == o.z; + } + bool operator!=(const Vector3& o) const + { + return x != o.x || y != o.y || z != o.z; + } + const Vector3& operator+=(const T& n) + { + x += n; + y += n; + z += n; + return *this; + } + const Vector3& operator-=(const T& n) + { + x -= n; + y -= n; + z -= n; + return *this; + } + const Vector3& operator*=(const T& n) + { + x *= n; + y *= n; + z *= n; + return *this; + } + const Vector3& operator/=(const T& n) + { + x /= n; + y /= n; + z /= n; + return *this; + } + const Vector3& operator%=(const T& n) + { + x %= n; + y %= n; + z %= n; + return *this; + } + const Vector3& operator&=(const T& n) + { + x &= n; + y &= n; + z &= n; + return *this; + } + const Vector3& operator|=(const T& n) + { + x |= n; + y |= n; + z |= n; + return *this; + } + const Vector3& operator+=(const Vector3& o) + { + x += o.x; + y += o.y; + z += o.z; + return *this; + } + const Vector3& operator-=(const Vector3& o) + { + x -= o.x; + y -= o.y; + z -= o.z; + return *this; + } + const Vector3& operator*=(const Vector3& o) + { + x *= o.x; + y *= o.y; + z *= o.z; + return *this; + } + const Vector3& operator/=(const Vector3& o) + { + x /= o.x; + y /= o.y; + z /= o.z; + return *this; + } + const Vector3& operator%=(const Vector3& o) + { + x %= o.x; + y %= o.y; + z %= o.z; + return *this; + } + const Vector3& operator&=(const Vector3& o) + { + x &= o.x; + y &= o.y; + z &= o.z; + return *this; + } + const Vector3& operator|=(const Vector3& o) + { + x |= o.x; + y |= o.y; + z |= o.z; + return *this; + } + const Vector3& operator>>=(int n) + { + x >>= n; + y >>= n; + z >>= n; + return *this; + } + const Vector3& operator<<=(int n) + { + x <<= n; + y <<= n; + z <<= n; + return *this; + } + Vector3 operator+(const T& n) const { Vector3 t = *this; return t += n; } + Vector3 operator-(const T& n) const { Vector3 t = *this; return t -= n; } + Vector3 operator*(const T& n) const { Vector3 t = *this; return t *= n; } + Vector3 operator/(const T& n) const { Vector3 t = *this; return t /= n; } + Vector3 operator%(const T& n) const { Vector3 t = *this; return t %= n; } + Vector3 operator&(const T& n) const { Vector3 t = *this; return t &= n; } + Vector3 operator|(const T& n) const { Vector3 t = *this; return t |= n; } + Vector3 operator+(const Vector3& o) const + { + Vector3 t = *this; + return t += o; + } + Vector3 operator-(const Vector3& o) const + { + Vector3 t = *this; + return t -= o; + } + Vector3 operator*(const Vector3& o) const + { + Vector3 t = *this; + return t *= o; + } + Vector3 operator/(const Vector3& o) const + { + Vector3 t = *this; + return t /= o; + } + Vector3 operator%(const Vector3& o) const + { + Vector3 t = *this; + return t %= o; + } + Vector3 operator&(const Vector3& o) const + { + Vector3 t = *this; + return t &= o; + } + Vector3 operator|(const Vector3& o) const + { + Vector3 t = *this; + return t |= o; + } + Vector3 operator>>(int n) const { Vector3 t = *this; return t >>= n; } + Vector3 operator<<(int n) const { Vector3 t = *this; return t <<= n; } + template Vector3 operator*(const Rotor3& r) const + { + T2 matrix[9]; + r.toMatrix(&matrix); + return Vector3( + matrix[0]*x + matrix[1]*y + matrix[2]*z, + matrix[3]*x + matrix[4]*y + matrix[5]*z, + matrix[6]*x + matrix[7]*y + matrix[8]*z); + } + template Vector3 operator/(const Rotor3& r) const + { + return (*this) * r.conjugate(); + } + Vector3 operator-() const { return Vector3(-x, -y, -z); } + bool zeroVolume() const { return x == 0 || y == 0 || z == 0; } + T modulus2() const { return x*x + y*y + z*z; } + T modulus() const { return sqrt(modulus2()); } + T dot(const Vector3& o) { return x*o.x + y*o.y + z*o.z; } + void normalize() { *this /= modulus(); } + Vector3 normalized() const { return *this / modulus(); } + bool inside(const Vector3& volume) const + { + return x >= 0 && y >= 0 && z >= 0 && x < volume.x && y < volume.y && + z < volume.z; + } + Hash hash() const + { + return Hash(typeid(Vector3)).mixin(x).mixin(y).mixin(z); + } + + + T x; + T y; + T z; +}; + +template Vector3 operator+(const T& n, const Vector3& v) +{ + return v + n; +} +template Vector3 operator-(const T& n, const Vector3& v) +{ + return (-v) + n; +} +template Vector3 operator*(const T& n, const Vector3& v) +{ + return v * n; +} +template Vector3 operator/(const T& n, const Vector3& v) +{ + return Vector2(n/v.x, n/v.y, n/v.z); +} +template Vector3 operator%(const T& n, const Vector3& v) +{ + return Vector2(n%v.x, n%v.y, n%v.z); +} +template Vector3 operator&(const T& n, const Vector3& v) +{ + return v & n; +} +template Vector3 operator|(const T& n, const Vector3& v) +{ + return v | n; +} +template Vector3 operator^(const T& n, const Vector3& v) +{ + return v ^ n; +} + +template Vector3 floor(const Vector3& vector) +{ + return Vector3(floor(vector.x), floor(vector.y), floor(vector.z)); +} + +template T dot(const Vector3& a, const Vector3& b) +{ + return a.x*b.x + a.y*b.y + a.z*b.z; +} + +template class Vector3Cast : public Vector3 +{ +public: + template Vector3Cast(const Vector3& other) + : Vector3(static_cast(other.x), static_cast(other.y), + static_cast(other.z)) { } + template Vector3Cast(const T2& x, const T2& y, const T2& z) + : Vector3(static_cast(x), static_cast(y), static_cast(z)) { } +}; + +#endif // INCLUDED_VECTORS_H diff --git a/80386/disassembler/include/alfe/windows_handle.h b/80386/disassembler/include/alfe/windows_handle.h new file mode 100644 index 0000000..8e807a5 --- /dev/null +++ b/80386/disassembler/include/alfe/windows_handle.h @@ -0,0 +1,44 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_WINDOWS_HANDLE_H +#define INCLUDED_WINDOWS_HANDLE_H + +#ifdef _WIN32 + +class WindowsHandle : public ConstHandle +{ +public: + WindowsHandle() : _handle(INVALID_HANDLE_VALUE) { } + WindowsHandle(HANDLE handle, bool own = true) + : _handle(handle), + ConstHandle((own && handle != INVALID_HANDLE_VALUE) + ? create(handle) : ConstHandle()) + { } + bool valid() const { return _handle != INVALID_HANDLE_VALUE; } + operator HANDLE() const { return _handle; } + void setHandleInformation(DWORD dwMask, DWORD dwFlags) + { + IF_ZERO_THROW(SetHandleInformation(*this, dwMask, dwFlags)); + } +protected: + WindowsHandle(const ConstHandle& other, HANDLE handle) + : ConstHandle(other), _handle(handle) { } + class Body : public ConstHandle::Body + { + public: + Body(HANDLE handle) : _handle(handle) { } + ~Body() + { + if (_handle != INVALID_HANDLE_VALUE) + CloseHandle(_handle); + } + private: + HANDLE _handle; + }; +private: + HANDLE _handle; +}; + +#endif + +#endif // INCLUDED_WINDOWS_HANDLE_H diff --git a/80386/disassembler/include/alfe/wrap.h b/80386/disassembler/include/alfe/wrap.h new file mode 100644 index 0000000..06e7695 --- /dev/null +++ b/80386/disassembler/include/alfe/wrap.h @@ -0,0 +1,12 @@ +#include "alfe/main.h" + +#ifndef INCLUDED_WRAP_H +#define INCLUDED_WRAP_H + +// Works like the % operator but doesn't reflect around 0 +template T wrap(const T& a, const T& b) +{ + return a < 0 ? b - (-a)%b : a%b; +} + +#endif // INCLUDED_WRAP_H diff --git a/80386/fields.txt b/80386/fields.txt new file mode 100644 index 0000000..0a1f946 --- /dev/null +++ b/80386/fields.txt @@ -0,0 +1,1026 @@ +ABCDEF = ALU source / jump offset +GHIJKLM = destination +NOPQRS = source +TUVWXYZ = ALU operation / jump condition +012 = opcode +34 = subcode +56789& = buscode + +ABCDEF register numbering: + regnames_alu [0x00] = "EAX "; // 1 902 + regnames_alu [0x01] = "ECX "; // 2 rot + regnames_alu [0x02] = "EDX "; + regnames_alu [0x03] = "EBX "; + regnames_alu [0x04] = "ESP "; // 1 60C + regnames_alu [0x05] = "EBP "; + regnames_alu [0x06] = "ESI "; // 2 + regnames_alu [0x07] = "EDI "; // 2 + regnames_alu [0x08] = "IMM8 "; // 10 JCXZ/LOOP/LOOPE/LOOPNE/Jcond/JMP/CALL/ENTER/VERR/VERW + regnames_alu [0x09] = "IMM "; // 12 + // regnames_alu [0x0A] = " "; + regnames_alu [0x0B] = "TMPB "; // 96 + regnames_alu [0x0C] = "TMPC "; // 52 + regnames_alu [0x0D] = "TMPD "; // 37 + // regnames_alu [0x0E] = " "; + // regnames_alu [0x0F] = " "; + // regnames_alu [0x10] = " "; + // regnames_alu [0x11] = " "; + // regnames_alu [0x12] = " "; + // regnames_alu [0x13] = " "; + regnames_alu [0x14] = "0x3ddc0c2c"; // 1 9B8 Expected result of built-in self-test (BIST) + regnames_alu [0x15] = "0x0303"; // 1 9B5 + regnames_alu [0x16] = "0x37fd7"; // 5 + regnames_alu [0x17] = "0x4000"; // 7 + regnames_alu [0x18] = "~0x200"; // 1 790 + regnames_alu [0x19] = "8 "; // 3 + regnames_alu [0x1A] = "0x40 "; // 2 + regnames_alu [0x1B] = "0xf0000"; // 2 + regnames_alu [0x1C] = "0x0d "; // 9 + regnames_alu [0x1D] = "0x5d "; // 4 + regnames_alu [0x1E] = "0x800000f8"; // 3 + regnames_alu [0x1F] = "0x800000fc"; // 5 + regnames_alu [0x20] = "0x70 "; // 2 + regnames_alu [0x21] = "0x73 "; // 1 9A9 + regnames_alu [0x22] = "0x1ff "; // 1 336 + regnames_alu [0x23] = "0x8200"; // 11 + regnames_alu [0x24] = "0x47 "; // 1 091 + regnames_alu [0x25] = "3 "; // 16 + regnames_alu [0x26] = "6 "; // 5 + regnames_alu [0x27] = "0xffff0000"; // 9 + regnames_alu [0x28] = "0x60 "; // 2 + regnames_alu [0x29] = "0x7ff "; // 3 + regnames_alu [0x2A] = "9 "; // 4 + regnames_alu [0x2B] = "0x29 "; // 9 LDCNTR in reset (002) + regnames_alu [0x2C] = "7 "; // 13 + regnames_alu [0x2D] = "0x0f "; // 5 + regnames_alu [0x2E] = "0x65 "; // 3 + regnames_alu [0x2F] = "0x1f "; // 2 + regnames_alu [0x30] = "1 "; // 43 + regnames_alu [0x31] = "2 "; // 13 + regnames_alu [0x32] = "0x10 "; // 11 + regnames_alu [0x33] = "4 "; // 16 + regnames_alu [0x34] = "-1 "; // 10 + regnames_alu [0x35] = "-2 "; // 3 + regnames_alu [0x36] = "0xffff"; // 39 + regnames_alu [0x37] = "-4 "; // 8 + // regnames_alu [0x38] = " "; + regnames_alu [0x39] = "WORDSZ"; // 25 + regnames_alu [0x3A] = "NEGWSZ"; // 22 negative word size in bytes (-2 or -4) (0xfffffffe or 0xfffffffc) + regnames_alu [0x3B] = "INCREM"; // 32 eSI/eDI increment for string instructions (+/- 1/2/4) + regnames_alu [0x3C] = "BITS_V"; // 21 one less than word size in bits (15 or 31) + regnames_alu [0x3D] = "DSTREG"; // 12 + regnames_alu [0x3E] = "SRCREG"; // 7 + regnames_alu [0x3F] = "0 "; + +GHIJKLM register numbering: + regnames_dest [0x00] = "EAX "; // 3 + // regnames_dest [0x01] = "ECX "; + regnames_dest [0x02] = "EDX "; // 1 BOOTUP + // regnames_dest [0x03] = "EBX "; + regnames_dest [0x04] = "ESP "; // 2 + regnames_dest [0x05] = "EBP "; // 2 ENTER/LEAVE + // regnames_dest [0x06] = "ESI "; + // regnames_dest [0x07] = "EDI "; + regnames_dest [0x08] = "EIP "; // 3 RPTI, DR/TR, ??? - always used with [-16-] + regnames_dest [0x09] = "EFLAGS"; // 10 + regnames_dest [0x0A] = "CR0 "; // 7 + regnames_dest [0x0B] = "TMPB "; // 125 + regnames_dest [0x0C] = "TMPC "; // 73 + regnames_dest [0x0D] = "TMPD "; // 44 + regnames_dest [0x0E] = "TMPE "; // 22 + regnames_dest [0x0F] = "TMPF "; // 11 + regnames_dest [0x10] = "FLAGSB"; // 14 + regnames_dest [0x11] = "TMPH "; // 18 + regnames_dest [0x12] = "TMPG "; // 32 + regnames_dest [0x13] = "SLCTR2"; // 11 + regnames_dest [0x14] = "MDTMP4"; // 11 Could this be the same as (-1D-)/MDTMP? Some routines outside of mul/div seem to use [-1D-]/(-14-) as a temp. Maybe (-1D-) has special powers? + regnames_dest [0x15] = "PROTUN"; // 59 + regnames_dest [0x16] = "TMPeIP"; // 9 + regnames_dest [0x17] = "TMPeSP"; // 7 + regnames_dest [0x18] = "DR6 "; // 9 + regnames_dest [0x19] = "DR7 "; // 7 + regnames_dest [0x1A] = "CSOPCD"; // 6 + regnames_dest [0x1B] = "FSVeIP"; // 7 + regnames_dest [0x1C] = "OPROFF"; // 6 + regnames_dest [0x1D] = "MDTMP "; // 7 one of the multiplier inputs? + // regnames_dest [0x1E] = " "; + // regnames_dest [0x1F] = " "; + regnames_dest [0x20] = "ES "; // 7 + regnames_dest [0x21] = "CS "; // 6 + regnames_dest [0x22] = "SS "; // 5 + regnames_dest [0x23] = "DS "; // 6 + regnames_dest [0x24] = "FS "; // 4 + regnames_dest [0x25] = "GS "; // 4 + regnames_dest [0x26] = "LDTR "; // 4 + // regnames_dest [0x27] = " "; + regnames_dest [0x28] = "eAX_AL"; // 7 MUL/IMUL/DIV/IDIV/[REP] LODS/XLATB/IN + regnames_dest [0x29] = "TR "; // 5 + regnames_dest [0x2A] = "eDX_AH"; // 4 MUL/IMUL/DIV/IDIV/CWD/CDQ + regnames_dest [0x2B] = "CR2 "; // 4 + // regnames_dest [0x2C] = " "; + regnames_dest [0x2D] = "OPR_W "; // 102 ...however, on line 083 OPR_R is never copied to OPR_W. Maybe "wr" writes from OPR_R? + // regnames_dest [0x2E] = " "; + // regnames_dest [0x2F] = " "; + // regnames_dest [0x30] = " "; + regnames_dest [0x31] = "eCX "; // 16 + regnames_dest [0x32] = "COUNTR"; // 60 IRF index? Temp related to [-14-]? + // regnames_dest [0x33] = " "; + // regnames_dest [0x34] = " "; + regnames_dest [0x35] = "SLCTR "; // 33 selector to load (pointer into LDT/GDT)? + regnames_dest [0x36] = "eSI "; // 11 + regnames_dest [0x37] = "eDI "; // 13 + regnames_dest [0x38] = "FLAGSL"; // 1 0DA SAHF + regnames_dest [0x39] = "IRF "; // 38 Indirect access to Register File + regnames_dest [0x3A] = "COUNT5"; // 6 COUNTR except that all but low 5 bits are masked off RCL/RCR/ENTER_COMMON/CALL_FAR_PM_GATE + // regnames_dest [0x3B] = " "; + regnames_dest [0x3C] = "SEGREG"; // 9 + regnames_dest [0x3D] = "DSTREG"; // 30 + regnames_dest [0x3E] = "SRCREG"; // 22 + // regnames_dest [0x3F] = " "; + regnames_dest [0x40] = "AX "; // 2 AAA/AAS and FSTSW AX + // regnames_dest [0x41] = "CX "; + // regnames_dest [0x42] = "DX "; + // regnames_dest [0x43] = "BX "; + // regnames_dest [0x44] = "SP "; + regnames_dest [0x45] = "BP "; // 2 ENTER/LEAVE + // regnames_dest [0x46] = "SI "; + // regnames_dest [0x47] = "DI "; + regnames_dest [0x48] = "IP "; // 1 649 + regnames_dest [0x49] = "FLAGS "; // 3 IRETd/POPFd/INT ib + // regnames_dest [0x4A] = " "; + // regnames_dest [0x4B] = " "; + // regnames_dest [0x4C] = " "; + regnames_dest [0x4D] = "DESPTR"; // 7 LIDTGDT_COMMON/LD_SEGREG_PASS/PRESENT_TSS/PROT_TESTS_PASSED/PROT_TESTS_PASSED2/PASSED_0B_0D descriptor mentioned in dest of last SPTR + regnames_dest [0x4E] = "DESSDT"; // 6 LTR/? Either DESGDT or DESIDT depending on the Table Indictor bit in the selector? Which selector? SLCTR? source? + // regnames_dest [0x4F] = " "; + regnames_dest [0x50] = "AL "; // 5 SALC/DAA/DAS/AAM/AAD + // regnames_dest [0x51] = "CL "; + // regnames_dest [0x52] = "DL "; + // regnames_dest [0x53] = "BL "; + regnames_dest [0x54] = "AH "; // 3 LAHF/AAM/AAD + // regnames_dest [0x55] = "CH "; + // regnames_dest [0x56] = "DH "; + // regnames_dest [0x57] = "BH "; + regnames_dest [0x58] = "DESCSW"; // 5 Descriptor that uses base and limit from CS descriptor but is writeable + regnames_dest [0x59] = "DESCOD"; // 23 Descriptor for eIP changes (DES_CS is only used for updating the CS descriptor) + regnames_dest [0x5A] = "DESSTK"; // 24 Descriptor for stack reads/writes (DES_SS is only used for updating the stack descriptor) + // regnames_dest [0x5B] = " "; + regnames_dest [0x5C] = "eSP "; // 39 + regnames_dest [0x5D] = "DES_OS"; // 37 strings, XLAT, - but used in "POP m" and SGDT with no ALU op - like IND_DS but "overrideable segment" (uses DS for bus operation unless a segment override is active, in which case use that segment) + regnames_dest [0x5E] = "DES_SR"; // 11 Like other IND_ registers but are written to when segment registers are updated + regnames_dest [0x5F] = "eIP "; // 9 + regnames_dest [0x60] = "DES_ES"; // 33 + regnames_dest [0x61] = "DES_CS"; // 25 + regnames_dest [0x62] = "DES_SS"; // 8 + regnames_dest [0x63] = "DES_DS"; // 5 + regnames_dest [0x64] = "DES_FS"; // 4 + regnames_dest [0x65] = "DES_GS"; // 4 + regnames_dest [0x66] = "DESLDT"; // 5 + regnames_dest [0x67] = "DESGDT"; // 3 + regnames_dest [0x68] = "DESIDT"; // 5 + regnames_dest [0x69] = "DES_TR"; // 28 + regnames_dest [0x6A] = "DESABS"; // 14 bus operation in which IND is placed on the address bus without any paging translation - used for halt/shutdown/interrupt acknowledge bus cycles and other debugging information placed on the address bus + regnames_dest [0x6B] = "DES_IO"; // 33 used for access to IO ports DES_IO + regnames_dest [0x6C] = "DESERR"; // 1 ACCESS_VIOLATI - descriptor that caused the fault + // regnames_dest [0x6D] = " "; + // regnames_dest [0x6E] = " "; + // regnames_dest [0x6F] = " "; + // regnames_dest [0x70] = "DR0 "; + // regnames_dest [0x71] = "DR1 "; + // regnames_dest [0x72] = "DR2 "; + // regnames_dest [0x73] = "DR3 "; + // regnames_dest [0x74] = "TR4 "; + // regnames_dest [0x75] = "TR5 "; + // regnames_dest [0x76] = "TR6 "; + // regnames_dest [0x77] = "TR7 "; + regnames_dest [0x78] = "LATTTF"; // 1 PAGE_FAULT Related to paging linear address that triggered the fault + regnames_dest [0x79] = "PGUNUS"; // 1 unused? Related to paging linear address that triggered the fault again (value ends up in CR2 anyway like LATTTF - could have had a different meaning here) + regnames_dest [0x7A] = "PFERRC"; // 2 PAGE_FAULT/unused? Related to paging page fault error code + regnames_dest [0x7B] = "PDBR "; // 11 Page directory base register (aka CR3) - write to this to flush TLB cache + // regnames_dest [0x7C] = " "; + regnames_dest [0x7D] = "PAGER5"; // 12 + // regnames_dest [0x7E] = " "; + regnames_dest [0x7F] = " "; // 550 + +NOPQRS register numbering: + regnames_source[0x00] = "EAX "; // 3 AAA/AAS/DAA/DAS and REP STOS Could be EAX - STOS copies to OPR_W but that needs to know size anyway + regnames_source[0x01] = "ECX "; // 4 rot/SHxD + regnames_source[0x02] = "EDX "; // 8 + // regnames_source[0x03] = "EBX "; + regnames_source[0x04] = "ESP "; // 25 + regnames_source[0x05] = "EBP "; // 4 ENTER/LEAVE + regnames_source[0x06] = "ESI "; // 10 [REP] MOVS/[REP] CMPS/[REP] LODS/[REP] OUTS + regnames_source[0x07] = "EDI "; // 19 PUSHAd(?)/[REP] MOVS/[REP] CMPS/[REP] SCAS/[REP] STOS/[REP] INS + regnames_source[0x08] = "EIP "; // 44 + regnames_source[0x09] = "EFLAGS"; // 22 LAHF , RPTI, + regnames_source[0x0A] = "CR0 "; // 30 MSW is the low 16 bits of CR0 + regnames_source[0x0B] = "TMPB "; // 67 + regnames_source[0x0C] = "TMPC "; // 31 + regnames_source[0x0D] = "TMPD "; // 10 + regnames_source[0x0E] = "TMPE "; // 29 + regnames_source[0x0F] = "TMPF "; // 9 Low 16 bits of TMPF are used for FP (opcode?). Bits 16-18 are used for error code + regnames_source[0x10] = "FLAGSB"; // 8 + regnames_source[0x11] = "TMPH "; // 25 + regnames_source[0x12] = "TMPG "; // 43 + regnames_source[0x13] = "SLCTR2"; // 32 Related to SLCTR? + regnames_source[0x14] = "COUNTR"; // 63 + regnames_source[0x15] = "PROTUN"; // 18 protection test unit + regnames_source[0x16] = "TMPeIP"; // 23 + regnames_source[0x17] = "TMPeSP"; // 33 + regnames_source[0x18] = "DR6 "; // 9 + regnames_source[0x19] = "DR7 "; // 8 + regnames_source[0x1A] = "CSOPCD"; // 7 CSOPCD, TMPN and TMPO are only used by FSAVE. + regnames_source[0x1B] = "FSVeIP"; // 2 + regnames_source[0x1C] = "OPROFF"; // 12 + regnames_source[0x1D] = "MDTMP "; // 15 quotient after division, product after multiplication? + regnames_source[0x1E] = "SIGMA "; // 533 + regnames_source[0x1F] = "IMM "; // 36 + regnames_source[0x20] = "ES "; // 5 + regnames_source[0x21] = "CS "; // 49 + regnames_source[0x22] = "SS "; // 26 + regnames_source[0x23] = "DS "; // 6 + regnames_source[0x24] = "FS "; // 4 + regnames_source[0x25] = "GS "; // 8 + regnames_source[0x26] = "LDTR "; // 6 + // regnames_source[0x27] = " "; + regnames_source[0x28] = "eAX_AL"; // 15 AAM/AAD/MUL/IMUL/DIV/IDIV/CWD/CDQ/[REP] SCAS/XLATB/STOS/OUT + regnames_source[0x29] = "TR "; // 9 + regnames_source[0x2A] = "eDX_AH"; // 6 SAHF/AAD/DIV/IDIV + regnames_source[0x2B] = "CR2 "; // 1 378 Contains a value called Page Fault Linear Address (PFLA). When a page fault occurs, the address the program attempted to access is stored in the CR2 register. + // regnames_source[0x2C] = " "; + regnames_source[0x2D] = "OPR_R "; // 156 It's tempting to call both OPR_R and OPR_W just OPR, but they do seem to be separate: look at 07E - OPR_R is available here (used on uop after DLY in other instructions) and used at line 080 but OPR_W is overwritten with eIP... + regnames_source[0x2E] = "IRF2 "; // 53 + regnames_source[0x2F] = "BIST1 "; // 1 9B5 + regnames_source[0x30] = "BIST2 "; // 1 9B7 + regnames_source[0x31] = "eCX "; // 11 + // regnames_source[0x32] = " "; + // regnames_source[0x33] = " "; + // regnames_source[0x34] = " "; + regnames_source[0x35] = "SLCTR "; // 6 selector to load (pointer into LDT/GDT)? + regnames_source[0x36] = "EA "; // 3 not eSI + // regnames_source[0x37] = "eDI "; + regnames_source[0x38] = "0 "; // 106 + regnames_source[0x39] = "IRF "; // 7 + // regnames_source[0x3A] = " "; + regnames_source[0x3B] = "OPCODE"; // 8 As stored by FSAVE/FSTENV - 0 to 0x7ff + regnames_source[0x3C] = "SEGREG"; // 3 + regnames_source[0x3D] = "DSTREG"; // 37 + regnames_source[0x3E] = "SRCREG"; // 21 + regnames_source[0x3F] = "-1 "; // 95 SALC + +TUVWXYZ alujump operations: + alujump_names[0x00] = "+-&|^ "; // 5 + alujump_names[0x01] = "++--~-"; // 2 + alujump_names[0x02] = "<<>>? "; // 13 + alujump_names[0x03] = "CMPTST"; // 5 + alujump_names[0x04] = "IMCS "; // 1 1BA IMUL Correct Sign. Corrects for sign regardless of opcode + alujump_names[0x05] = "SERECO"; // 4 BTS/BTR/BTC SEt, REset, COmplement according to which opcode used. Actual operation is either ALU1 OR ALU2, ALU1 AND NOT ALU2 or ALU1 XOR ALU2. There's a shift in there too? + alujump_names[0x06] = "SZ_EXT"; // 4 MOVZX/MOVSX/CBW/CWDE + alujump_names[0x07] = "SZ_EX2"; // 1 1AC MUL/IMUL rm - binary operation. Correct upper part of multiplication for sign in IMUL case. Not sure how this is different from SZ_EXT + alujump_names[0x08] = "AND "; // 84 ok + alujump_names[0x09] = "OR "; // 41 probably not SUB - used to clear (or set?) resume flag in RPTI? - AND NOT? Also used in JMP cp + alujump_names[0x0A] = "XOR "; // 13 + alujump_names[0x0B] = "SIGN "; // 4 probably not CMP - BT/BTS/BTR/BTC/CWD/CDQ/77a SIGMA is sign-extension of input + alujump_names[0x0C] = "ADD "; // 123 ok + alujump_names[0x0D] = "ADC "; // 2 Used in AAM and AAD + alujump_names[0x0E] = "SUB "; // 36 probably not ADC - SUB? + alujump_names[0x0F] = "CMP "; // 8 porbably not SBB - SUB? CMP? + alujump_names[0x10] = "SHIFT "; // 72 + alujump_names[0x11] = "BITTST"; // 11 BT/BTS/BTR/BTC/BSF - does a shift and copies the lowest bit into the carry flag? + alujump_names[0x12] = ">>< 0) in CLTS/HLT/LIDT/LGDT/LLDT/LMSW/CRn/DRn/TRn/LTR/LOADALL386, (PM && CPL > IOPL) in PORTIO_PROTCHK + alujump_names[0x73] = "LJMPVM"; // 6 IRETd (p)/??? long jump only in virtual 8086 mode + alujump_names[0x74] = "LJMPP "; // 17 long jump only in protected mode + alujump_names[0x75] = "ICEENT"; // 2 ICE_SINGLESTEP/ICE_PIN - send some signal to ICE? Always happens right before STOREALL - enter ICE mode + alujump_names[0x76] = "ICEEXT"; // 1 LOADALL386 - tell ICE that LOADALL completed successfully - exit ICE mode + // alujump_names[0x77] = " "; + alujump_names[0x78] = "LDBSRM"; // 14 SHRCNT = alu2 & BITS_V; initialise the barrel shift amount (right) with the value from the register mentioned in the ALU2 source? + alujump_names[0x79] = "LDBSLM"; // 5 SHLCNT = alu2 & BITS_V; + alujump_names[0x7A] = "LDBSRU"; // 26 SHRCNT = alu2 & 0x1f; BT/BTS/BTR/BTC/BSF/PORTIO_PROTCHK/MOV r<->DR/MOV r<->TR/FSAVE/FRSTOR/LSL initialise the barrel shift amount (right) with the value from the register mentioned in the ALU2 source? + alujump_names[0x7B] = "LDBSLU"; // 37 SHLCNT = alu2 & 0x1f; + alujump_names[0x7C] = "RETURN"; // 14 + alujump_names[0x7D] = "ICESIG"; // 10 HLT/FPU_FLAG*/HARDWARE_IRQ/TRIPLE_FAULT*/FAULT*/INTERRUPT/PAGE_FAULT*/SINGLE_STEP*/ICE_PIN* - send a signal to the ICE that something interesting is happening (*ICE has the opportunity to pause the microcode right after this) + alujump_names[0x7E] = "PAGEFT"; // 1 PAGE_FAULT - not sure if this notifies ICE or the paging unit or both or something else that page fault handling has started + alujump_names[0x7F] = " "; // 801 + +012 opcodes: + opnames[0] = "RNI"; // 162 RNI must be suppressed if it's in the delay slot - see 3a8 + opnames[1] = "RNi"; // 25 RNI but only if it's executed in the delay slot + opnames[2] = "RnI"; // 5 RNI but disable interrupts for the next instruction + // opnames[3] = " "; + // opnames[4] = " "; + opnames[5] = "FIO"; // 14 FP IO - FSAVE_REGFILE, FRSTOR_REGFILE, FPU_LOAD_CORE, FLDCW, FPU_STORE_CORE, FPU_STORE_287 (when on its own there is a [5] (2) on the line after) - precedes some (but not all) accesses to the FPU port 0x800000fc + opnames[6] = "RPT"; // 19 AAM/AAD/MUL/IMUL/DIV/IDIV/ARPL/ + opnames[7] = " "; // 2141 + +34 subcodes: + subopnames[0] = "DLY"; // 559 Wait for bus operation to complete and update OPR_R if it was a read + subopnames[1] = "UNL"; // 182 Used after a read is complete (but not always immedidately) - to do with bus unlocking? + subopnames[2] = "WIO"; // 12 Used in HLT, FSAVE_REGFILE, FRSTOR_REGFILE, FPU_LOAD_CORE, FLDCW, FPU_STORE_CORE, FPU_STORE_287 (in conjunction with [5] except in HLT) - wait for IO? + subopnames[3] = " "; // 1613 + +56789& buscodes: + // busop_names[0x00] = " "; + // busop_names[0x01] = " "; + // busop_names[0x02] = " "; + // busop_names[0x03] = " "; + // busop_names[0x04] = "rd B"; + busop_names[0x05] = "rd W"; // 1 IRETd_HELPER4 + busop_names[0x06] = "rd "; // 1 0B1 XCHG rm,r + busop_names[0x07] = "rd D"; // 9 LSSFSGS_HELPER/LOAD_SEGR_HELP/RETF_HELPER3/LAR_LSL_VERRW2/INT_HELPER TODO: Figure out the difference between rd and RD . rd automatically asserts LOCK#? "LOCK# is also asserted automatically for an XCHG instruction, a descriptor update, interrupt acknowledge cycles, and a page table update" (HRM 3.5.1) + busop_names[0x08] = "CW B"; // 4 FSAVE_CORE/FPU_STORE_CORE Perform access/limit/paging checks for writes but don't actually do a write + // busop_names[0x09] = "CW W"; + busop_names[0x0A] = "CW "; // 4 RCL/RCR rm,CL / INS / ENTER_COMMON + // busop_names[0x0B] = "CW D"; + busop_names[0x0C] = "CR B"; // 4 FRSTOR_CORE/FPU_LD80_CORE Perform access/limit/paging checks for reads but don't actually do a read + // busop_names[0x0D] = "CR W"; + // busop_names[0x0E] = "CR "; + // busop_names[0x0F] = "CR D"; + // busop_names[0x10] = "WR B"; + busop_names[0x11] = "WR W"; // 41 + busop_names[0x12] = "WR "; // 49 + busop_names[0x13] = "WR D"; // 11 + // busop_names[0x14] = "RD B"; + busop_names[0x15] = "RD W"; // 43 + busop_names[0x16] = "RD "; // 101 + busop_names[0x17] = "RD D"; // 21 LGDT/PR_LD_SS/LLDT/LOADALL386/??? + // busop_names[0x18] = "wr B"; + busop_names[0x19] = "wr W"; // 5 The difference between wr* and WR* seems to be that WR* is used in combination with a copy to OPR_W whereas wr* is for writing back something that was just read, so the data is in OPR_R + busop_names[0x1A] = "wr "; // 24 + // busop_names[0x1B] = "wr D"; + busop_names[0x1C] = "PREF"; // 19 Start prefetch at IND? + busop_names[0x1D] = "IN+D"; // 70 PUSHAd, IRETd IND += IND_DELTA + // busop_names[0x1E] = " "; + busop_names[0x1F] = "IN+="; // 61 IND = IND + alu2 IND_DELTA = alu2 <-3F-> (0?), -2, -4, 0x0d, 0x5d, 1, 2, 3, 4, 7, 9, INCREM, NEGWSZ, TMPB, TMPC, WORDSZ + // busop_names[0x20] = " "; + // busop_names[0x21] = " "; + // busop_names[0x22] = " "; + // busop_names[0x23] = " "; + busop_names[0x24] = "IN=2"; // 25 IND = alu2 dest = IND_IO, IND_Rf, IND_TR, // Theory: {2C}-{39} all select parts/fields of a descriptor cache entry or selector in conjunction with IND_* sources/dests + busop_names[0x25] = "IND="; // 103 IND = source dest = n/a (LJUMP), (-58), INDIDT, INDSTK, INC_CS, IND_ES, IND_IO, IND_IP, IND_OS, IND_RF, IND_TR + busop_names[0x26] = "IN=+"; // 53 IND = source + alu2 IND_DELTA = alu2 dest = (-4E), (-58-), INDIDT, INDSTK, IND_ES, IND_IP, IND_OS, IND_RF, IND_TR + // busop_names[0x27] = " "; + busop_names[0x28] = "IACK"; // 2 Interrupt Acknowledge bus cycle HARDWARE_IRQ (asserts LOCK# like "rd") + // busop_names[0x29] = " "; + // busop_names[0x2A] = " "; + // busop_names[0x2B] = " "; + busop_names[0x2C] = "SBRM"; // 23 Set BASE in Real Mode (to segment << 4) dest = DS, ES, FS, GS, IND_CS, IND_DS, IND_ES, IND_FS, IND_GS, IND_SR, IND_SS, IRF, SS Also set LIMIT to 0xffff? Sets Access Rights? + busop_names[0x2D] = "SDEH"; // 11 dest = (-4D-), INDLDT, IND_CS, IND_SS, IND_TR, IRF LD_SEGREG_PASS/PRESENT_TSS/PROT_TESTS_PASSED/PROT_TESTS_PASSED2/CALL_UNPRIV/RETF_HELPERRET/LLDT_TEST_PASS/CALL_SAVE_TASK/SWITCH_TASK/PASSED_0B_0D set descriptor high dword (sets byte 3 of base, byte 2 (G/DB/-/A bits) of access, and byte 2 (bits 16-19) of limit) + busop_names[0x2E] = "SDES"; // 7 LD_SEGREG_PASS/PROT_TESTS_PASSED/PROT_TESTS_PASSED2/CALL_UNPRIV/CALL_SAVE_TASK/SWITCH_TASK uses alu2 (TMPB, TMPC, TMPD) set descriptor shifted dword (sets byte 3 (P/DPL/S/Type) bits of access, and bytes 0-2 of base) + busop_names[0x2F] = "SDEL"; // 30 segreg load/JMP_FAR_PM/CALL_FAR_PM/CALL_UNPRIV/TASK_RETURN/IRETd/RETF_HELPER3/LTR/LLDT/LOAD_TASK/TASK_FINAL_V86/TASK_FINAL_PM/TRAPGATE/INTGATE uses alu2 (mostly TMPC, one TMPD) set descriptor low dword (sets bytes 0-1 of limit) + busop_names[0x30] = "SPCR"; // 18 dest = (-7B-), (-7D-), IRF Store Page Cache Register? + busop_names[0x31] = "SAR "; // 21 select AR field of descriptor cache dest = ES, FS, GS, IND_CS, IND_ES, IRF, INDLDT, IND_GS, IND_FS, IND_DS, IND_SS, IND_ES, IND_TR, DS + busop_names[0x32] = "SBAS"; // 9 select BASE field of descriptor cache dest = DS, (-4D), IRF, IND_TR, IND_RF, IND_IR + busop_names[0x33] = "SLIM"; // 14 select LIMIT field of descriptor cache dest = (-4D-), IRF, IND_TR, IND_RF, IND_IP, IND_CS, IND_ES + busop_names[0x34] = "LPCR"; // 9 MOV rd,CR3/MOV rd,TRn/IRETd_HELPER4/unused?/pla/LOADALL386/DR_ICEBP_HELP2 dest = (-78-), (-79-), (-7A-), (-7B-), IRF Related to paging? - store CR3 to IND? Read special register? Used with TRn Load Page Cache Register into IRF2 + busop_names[0x35] = "LAR "; // 11 JMP cp/RETF_HELPER/RETF_HELPER_*/pla/EXCEPTION/LOADALL386/DR_ICEBP_HELP2 dest = (-15-), (-6C-), IND_CS, IND_DS, IND_ES, IND_FS, IND_GS, IND-SS, IND-TR, IRF load access rights from descriptor cache into IRF2 + busop_names[0x36] = "LBAS"; // 5 SIDT/SGDT/DR_ICEBP_HELP2 dest = INDGDT, INDIDT, IND_TR, IRF load base from descriptor cache into IRF2 + busop_names[0x37] = "LLIM"; // 9 FARJUMP/JMP mp/SIDT/SGDT/SOFTWARE INT/LOADALL386/pla/DR_ICEBP_HELP2 dest = INDGDT, INDIDT, IND_CS, IND_TR, IRF, n/a (LJUMP), (-3F-) load limit from descriptor cache into IRF2 + busop_names[0x38] = "TSDB"; // 3 TASK_RETURN/LOAD_TASK_16B/LOAD_TASK - task switch debug: some external signal that signifies that the address bus contains the old and new values of TR + busop_names[0x39] = "SPTR"; // 40 makes DESPTR correspond to dest + // busop_names[0x3A] = " "; + // busop_names[0x3B] = " "; + busop_names[0x3C] = "HLTS"; // 1 HLT_HELPER dest = (-7F-) - probably outputs HLT/SHUTDOWN signal to motherboard, then the actual waiting is done in the RPT (2) loop at 32b. + // busop_names[0x3D] = " "; + // busop_names[0x3E] = " "; + busop_names[0x3F] = " "; // 1504 + + +EntryPoint entryPoints[] = { + {0, 0x003, 2, " MOV r,r"}, + {0, 0x005, 2, " MOV r,i"}, + {0, 0x007, 2, " MOVZX rv,segreg"}, + {0, 0x009, 2, " r MOV ES/SS/DS/FS/GS,rw"}, + {1, 0x00b, 5, " MOV SS,mw"}, + {1, 0x00f, 5, " MOV ES/DS/FS/GS,mw"}, + {1, 0x013, 2, " MOV [i],A MOV m,r"}, + {1, 0x015, 2, " MOV m,i"}, + {1, 0x017, 2, " MOV mw,segreg"}, + {1, 0x019, 4, " MOV A,[i] MOV r,m"}, + {0, 0x01d, 2, " ADD/OR/ADC/SBB/AND/SUB/XOR r,r"}, + {0, 0x01f, 2, " CMP r,r TEST r,r"}, // TEST reg,reg has cycle count of 1? + {0, 0x021, 2, " INC/DEC/NOT/NEG r"}, + {0, 0x023, 2, " ADD/OR/ADC/SBB/AND/SUB/XOR r,i"}, + {0, 0x025, 2, " CMP/TEST A,i"}, + {1, 0x027, 6, " ADD/OR/ADC/SBB/AND/SUB/XOR r,m"}, + {1, 0x02c, 6, " CMP r,m"}, + {1, 0x031, 5, " CMP/TEST m,i"}, + {1, 0x035, 5, " CMP/TEST m,r"}, + {9, 0x039, 7, " ADD/OR/ADC/SBB/AND/SUB/XOR m,i"}, + {0, 0x03d, 4, " SETcond rb"}, + { 0, 0x041, 0, "SETCONDR_FALSE"}, + {1, 0x043, 5, " SETcond mb"}, + {1, 0x043, 5, " SETcond mb"}, + { 0, 0x046, 0, "WRITE_RESULT "}, + { 0, 0x048, 0, "SETCONDM_FALSE"}, + {9, 0x04a, 7, " ADD/OR/ADC/SBB/AND/SUB/XOR m,r"}, + {9, 0x04e, 6, " INC/DEC/NOT/NEG m"}, + {0, 0x051, 5, " JeCXZ cb"}, // cycle count is 5/9+m + {0, 0x057,11, " LOOP cb"}, // cycle count is 11+m/? + { 0, 0x05b, 0, "LOOP_DONE "}, + { 0, 0x05d, 0, "LOOP_UNTAKEN "}, + {0, 0x05f,11, " LOOPE/LOOPNE cb"}, // cycle count is 11+m/? + {0, 0x065, 3, " Jcond cb/cv"}, // cycle count is 3/7+m + { 0, 0x067, 0, "JMP_PREFINAL "}, + { 0, 0x068, 0, "JMP_FINAL "}, + { 0, 0x069, 0, "Jcond_DONE "}, + {0, 0x06a, 7, " JMP c"}, // cycle count is 7+m + { 0, 0x06b, 0, "JMP_PREF "}, + {0, 0x06d, 7, " JMP rv"}, // cycle count is 7+m + {1, 0x06f,10, " JMP mv"}, // cycle count is 10+m + {3, 0x072,10, " RET/RET iw"}, // cycle count is 10+m + {2, 0x075, 7, " CALL cw"}, // cycle count is 7+m + {2, 0x079, 7, " CALL rv"}, // cycle count is 7+m + {1, 0x07c,10, " CALL mv"}, // cycle count is 10+m + {1, 0x081, 5, " PUSH mv"}, + {2, 0x086, 2, " PUSH rv"}, + {0, 0x088,24, " PUSHAd"}, + { 0, 0x08d, 0, "PUSHAd_LOOP "}, + {3, 0x091,24, " POPA"}, + { 0, 0x092, 0, "POPAd_LOOP "}, + {3, 0x097,24, " POPAD"}, + {2, 0x09b, 2, " PUSH segreg"}, + {2, 0x09d, 2, " PUSH i"}, + {3, 0x09f, 4, " POP rv"}, // number of cycles doesn't seem to match + {3, 0x0a2, 7, " POP SS"}, + {3, 0x0a7, 7, " POP ES/DS/FS/GS"}, + {3, 0x0ac, 5, " POP mv"}, + {9, 0x0b1, 5, " XCHG m,r"}, + {0, 0x0b6, 3, " XCHG eAX,rv XCHG r,r"}, + {1, 0x0b9, 2, " LEA rv,m"}, + {1, 0x0bb, 7, " LDS rv,m"}, // cycle count is 7/22 + {1, 0x0c2, 7, " LES rv,m"}, // cycle count is 7/22 + {1, 0x0c9, 7, " LSS rv,m"}, // cycle count is 7/22 + {1, 0x0d0, 7, " LFS/LGS rv,m"}, // cycle count is 7/22 + {0, 0x0d7, 2, " LAHF"}, + {0, 0x0d9, 3, " SAHF"}, + {0, 0x0dc, 5, " CLTS"}, + {0, 0x0e1, 0, " SALC"}, // don't know cycle count + { 0, 0x0e4, 0, "SALC_DONE "}, + {0, 0x0e5, 9, " RCL/RCR r,ib"}, + {0, 0x0e9, 9, " RCL/RCR r,CL"}, + { 0, 0x0ed, 0, "RCLRCR_R_COMM "}, // common to register ib and CL forms of RCL/RCR + { 0, 0x0f1, 0, "RCLRCR_R_LOOP "}, + {0, 0x0f9, 3, " ROL/ROR/SHL/SHR/SAR r,ib"}, + {0, 0x0fc, 3, " SHxD rv,rv,ib"}, + {0, 0x0ff, 3, " ROL/ROR/SHL/SHR/SAR r,CL"}, + {0, 0x102, 3, " SHxD rv,rv,CL"}, + {0, 0x105, 9, " rot r,1"}, + {1, 0x108,10, " RCL/RCR m,ib"}, + {1, 0x10c,10, " RCL/RCR m,CL"}, + { 0, 0x110, 0, "RCLRCR_M_COMM "}, // common to memory ib and CL forms of RCL/RCR + { 0, 0x115, 0, "RCLRCR_M_LOOP "}, + {1, 0x11e, 7, " ROL/ROR/SHL/SHR/SAR m,ib"}, + { 0, 0x120, 0, "ROSHSA_M_COMM "}, // common to memory ib and CL forms of ROL/ROR/SHL/SHR/SAR + {1, 0x124, 7, " SHxD mv,rv,ib"}, + { 0, 0x126, 0, "SHxD_M_COMM "}, // common to memory ib and CL forms of ROL/ROR/SHL/SHR/SAR + {1, 0x12a,10, " rot m,1"}, + {1, 0x12d, 7, " ROL/ROR/SHL/SHR/SAR m,CL"}, + {1, 0x12f, 7, " SHxD mv,rv,CL"}, + {0, 0x131, 3, " BT rv,rv"}, + {1, 0x134,12, " BT m,rv"}, + {0, 0x13f, 3, " BT rv,ib"}, + {1, 0x142, 6, " BT m,ib"}, + {0, 0x147, 6, " BTS/BTR/BTC rv,rv"}, + {9, 0x14d,13, " BTS/BTR/BTC m,rv"}, + {0, 0x15a, 6, " BTS/BTR/BTC rv,ib"}, + {9, 0x160, 8, " BTS/BTR/BTC m,ib"}, + {0, 0x168,10, " BSF rv,rv"}, // 10+3n + { 0, 0x169, 0, "BSF_COMMON "}, // common to register and memory forms of BSF + { 0, 0x171, 0, "BSF_DONE " }, + { 0, 0x172, 0, "BSF_LOOP "}, + {1, 0x177,10, " BSF rv,mv"}, // 10+3n + {0, 0x17a,10, " BSR rv,rv"}, // 10+3n + { 0, 0x17b, 0, "BSR_COMMON "}, // common to register and memory forms of BSR + { 0, 0x17f, 0, "BSR_LOOP "}, + { 0, 0x183, 0, "BSR_DONE " }, + {1, 0x184,10, " BSR rv,mv"}, // 10+3n + {0, 0x187, 4, " AAA/AAS"}, + {0, 0x18b, 4, " DAA/DAS"}, + {0, 0x18f,17, " AAM ib"}, + {0, 0x199,19, " AAD ib"}, + {0, 0x1a5, 9, " MUL/IMUL r"}, // cycle count is 9-14/9-22/9-38 + { 0, 0x1a7, 0, "iMUL_COMMON "}, // common to register and memory forms of MUL/IMUL rm + {1, 0x1af,12, " MUL/IMUL m"}, // cycle count is 12-17/12-25/12-41 + {0, 0x1b3, 9, " IMUL rv,rv"}, // cycle count is 9-22/9-38 + { 0, 0x1b5, 0, "IMUL2_COMMON "}, // common to register and memory forms of IMUL rv,rmv and IMUL rv,rmv,i + {1, 0x1bd,12, " IMUL rv,mv"}, // cycle count is 12-25/12-41 + {1, 0x1c1, 9, " IMUL rv,mv,i"}, // cycle count is 9-22/9-38 + {0, 0x1c4,12, " IMUL rv,rv,i"}, // cycle count is 12-25/12-41 + {0, 0x1c7,14, " DIV r "}, // cycle count is 14/22/38 + { 0, 0x1ca, 0, "DIV_COMMON " }, // common to register and memory forms of DIV + {1, 0x1cf,17, " DIV m"}, // cycle count is 17/25/41 + {0, 0x1d3,19, " IDIV r"}, // cycle count is 19/27/43 + { 0, 0x1d8, 0, "IDIV_COMMON " }, // common to register and memory forms of IDIV + {1, 0x1e1,22, " IDIV m"}, // cycle count is 22/30/46 + {0, 0x1e6, 2, " CWD / CDQ"}, + {0, 0x1e8, 3, " CBW / CWDE MOVZX/MOVSX r,r (16-bit?)"}, + {1, 0x1eb, 6, " MOVZX/MOVSX r,m (16-bit?)"}, + {0, 0x1f0, 3, " CBW / CWDE MOVZX/MOVSX r,r (32-bit?)"}, + {1, 0x1f3, 6, " MOVZX/MOVSX r,m (32-bit?)"}, + {0, 0x1f8, 7, " REP MOVS"}, + { 0, 0x1fd, 0, "REP_MOVS_NOT0 " }, + { 0, 0x201, 0, "REP_MOVS_LOOP " }, + { 0, 0x205, 0, "REP_MOVS_DONE " }, + { 0, 0x207, 0, "REP_MOVS_RPTI " }, + { 0, 0x208, 0, "RPTI "}, + {0, 0x211, 7, " MOVS"}, + {0, 0x218,12, " REP CMPS"}, + { 0, 0x21c, 0, "REP_CMPS_DONE " }, + { 0, 0x21d, 0, "REP_CMPS_LOOP " }, + { 0, 0x220, 0, "REP_CMPS_NOT0 " }, + {0, 0x22b,10, " CMPS"}, + {0, 0x235, 9, " REP SCAS"}, + { 0, 0x239, 0, "REP_SCAS_DONE " }, + { 0, 0x23a, 0, "REP_SCAS_LOOP " }, + { 0, 0x23d, 0, "REP_SCAS_NOT0 " }, + {0, 0x247, 7, " SCAS"}, + {0, 0x24e, 7, " REP LODS"}, + { 0, 0x24f, 0, "REP_LODS_DONE " }, + { 0, 0x250, 0, "REP_LODS_LOOP " }, + {0, 0x25a, 5, " LODS"}, + {0, 0x25f, 5, " XLATB"}, + {0, 0x263, 6, " REP STOS"}, + { 0, 0x264, 0, "REP_STOS_DONE " }, + { 0, 0x265, 0, "REP_STOS_LOOP " }, + {0, 0x26e, 4, " STOS"}, + {0, 0x272, 6, " p IN A,ib"}, // cycle count is 6/26 + {0, 0x274,12, " r IN A,ib"}, + { 0, 0x276, 0, "IN_IMM_NOCHK " }, + { 0, 0x278, 0, "IN_DONE " }, + {0, 0x279, 7, " p IN A,DX"}, // cycle count is 7/27 + {0, 0x27a,13, " r IN A,DX"}, + { 0, 0x27c, 0, "IN_DX_NOCHK " }, + {0, 0x27f, 9, " p INS"}, // cycle count is 9/29 + {0, 0x281,15, " r INS"}, + { 0, 0x284, 0, "INS_NOCHK " }, + {0, 0x28a,11, " p REP INS"}, + {0, 0x28b,17, " r REP INS"}, + { 0, 0x28d, 0, "REP_INS_NOCHK " }, + { 0, 0x290, 0, "REP_INS_DONE " }, + { 0, 0x291, 0, "REP_INS_LOOP " }, + { 0, 0x293, 0, "REP_INS_NOT0 " }, + {0, 0x29b, 4, " p OUT ib,A"}, // cycle count is 4/24 + {0, 0x29d,10, " r OUT ib,A"}, + { 0, 0x29f, 0, "OUT_IMM_NOCHK " }, + {0, 0x2a1, 5, " p OUT DX,A"}, // cycle count is 5/25 + {0, 0x2a2,11, " r OUT DX,A"}, + { 0, 0x2a4, 0, "OUT_DX_NOCHK " }, + {0, 0x2a7, 8, " p OUTS"}, // cycle count is 8/28 + {0, 0x2a9,14, " r OUTS"}, + { 0, 0x2ac, 0, "OUTS_NOCHK " }, + {0, 0x2b1,10, " p REP OUTS"}, + {0, 0x2b2,16, " r REP OUTS"}, + { 0, 0x2b4, 0, "REP_OUTS_NOCHK" }, + { 0, 0x2b7, 0, "REP_OUTS_DONE " }, + { 0, 0x2b8, 0, "REP_OUTS_LOOP " }, + { 0, 0x2ba, 0, "REP_OUTS_NOT0 " }, + { 0, 0x2c1, 0, "PORTIO_PROTCHK" }, + { 0, 0x2c4, 0, "IO_PERM_BITMAP" }, + { 0, 0x2d3, 0, "PORTIO_16BIT " }, + { 0, 0x2d4, 0, "PORTIO_ALLOWED" }, + {2, 0x2d6,17, " CALL cp"}, // cycle count is 17+m/34+m + {1, 0x2da,22, " CALL mp"}, // cycle count is 22+m/38+m + { 0, 0x2e2, 0, "CALL_FAR_RM " }, // common to cp and mp far CALLs in real mode + {0, 0x2e5,12, " JMP cp"}, // cycle count is 12+m/27+m/45+m/TS/TS + { 0, 0x2eb, 0, "JMP_FAR_RM " }, + { 0, 0x2ed, 0, "JMP_FAR_RM_1 " }, // Jumps to COUNTR:TMPG ? TMPB is previous CS limit (set by 2fb)? + { 0, 0x2f0, 0, "JMP_FAR_COMMON" }, + { 0, 0x2f1, 0, "JMP_FAR_DONE " }, + {1, 0x2f5,43, " JMP mp"}, // cycle count is 43+m/31+m/49+m/5+TS/5+TS + {3, 0x2fc,18, " RETF/RETF iw"}, // cycle count is 18+m/32+m/68 + {2, 0x304,10, " ENTER (16-bit?)"}, // cycle count is 10 (0), 12 (1), 15+4*(n-1) (n) + {2, 0x308,10, " ENTER (32-bit?)"}, // cycle count is 10 (0), 12 (1), 15+4*(n-1) (n) + { 0, 0x30c, 0, "ENTER_COMMON " }, + { 0, 0x316, 0, "ENTER_LOOP " }, + { 0, 0x31a, 0, "ENTER_LAST " }, + { 0, 0x31c, 0, "ENTER_LASTW " }, + { 0, 0x31d, 0, "ENTER_DONE " }, + {0, 0x31f, 4, " LEAVE (16-bit?)"}, + {0, 0x323, 4, " LEAVE (32-bit?)"}, + {0, 0x327, 5, " HLT"}, + { 0, 0x329, 0, "HLT_SHUTDOWN " }, + {1, 0x32e,11, " LIDT mw"}, + {1, 0x332,11, " LGDT mw"}, + { 0, 0x336, 0, "LIDTGDT_COMMON" }, + {0, 0x33d, 9, " SIDT mw"}, // Number of cycles doesn't seem to match? + {0, 0x340, 9, " SGDT mw"}, // Number of cycles doesn't seem to match? + { 0, 0x343, 0, "SIDTGDT_COMMON" }, + {1, 0x349,13, " LMSW mw"}, + {0, 0x34e,10, " LMSW rw"}, + { 0, 0x351, 0, "LMSW_COMMON " }, + {0, 0x358,10, " SMSW rw"}, + {1, 0x35a, 3, " SMSW mw"}, + {0, 0x35c,10, " MOV CR0,rd"}, + { 0, 0x366, 0, "PAGING_RM " }, + {0, 0x368, 4, " MOV CR2,rd"}, + {0, 0x36c, 5, " MOV CR3,rd"}, + {0, 0x371, 6, " MOV rd,CR0"}, + { 0, 0x373, 0, "STORE_CR " }, // Common code to "MOV rd,CRn" + {0, 0x377, 6, " MOV rd,CR2"}, + {0, 0x379, 6, " MOV rd,CR3"}, + {0, 0x37b,16, " MOV DR4/6,rd"}, + {0, 0x37f,16, " MOV DR5/7,rd"}, + { 0, 0x383, 0, "LD_DR4567_DONE" }, + { 0, 0x385, 0, "SELECT_DR_TR " }, + {0, 0x38a,22, " MOV DR0-3,rd"}, + {0, 0x391,12, " MOV TRn,rd"}, + { 0, 0x398, 0, "GENERAL_DETECT" }, // Do the breakpoint on TR/DR access if bit 13 of DR7 is set + { 0, 0x3a2, 0, "GD_HIT " }, // General detect condition has been triggered + {0, 0x3a6,22, " MOV rd,DR4/6"}, + {0, 0x3aa,22, " MOV rd,DR5/7"}, + {0, 0x3ae,22, " MOV rd,DR0-3"}, + {0, 0x3b6,12, " MOV rd,TRn"}, + {0, 0x3bd, 6, " WAIT"}, + { 0, 0x3be, 0, "WAIT_LOOP " }, + { 0, 0x3c1, 0, "WAIT_IRQT " }, // Continuation of WAIT loop after subroutine - check if IRQ is pending + { 0, 0x3c5, 0, "WAIT_ERRT " }, // Subroutine to handle && in error test + { 0, 0x3c8, 0, "WAIT_DONE " }, + { 0, 0x3cb, 0, "FPU_ERROR6 " }, + {0, 0x3cd, 0, " FENI/FDISI/FCLEX/FINIT/FSETPM/FRSTPM r"}, // FPU flag instructions (no memory access) - these need to reset prefetching for some reason? Same reason that CLI/STI do? + { 0, 0x3d1, 0, "FPU_FLAG_LOOP " }, + {0, 0x3d9, 0, " FSTCW/FSTSW mw"}, // Number of cycles doesn't seem to match? + {0, 0x3da, 0, " FSTSW AX/FNSTDW/FNSTSG r"}, + { 0, 0x3db, 0, "FPU_MISC_WAIT " }, + { 0, 0x3e2, 0, "FPU_MISC_CORE " }, + { 0, 0x3e8, 0, "FPU_MISC_WRITE" }, + { 0, 0x3eb, 0, "FPU_ERROR5 " }, // Unreachable? + {1, 0x3ed, 0, " FSTENV m"}, + {1, 0x3f0, 0, " FSAVE m"}, + { 0, 0x3f3, 0, "FSAVE_WAIT " }, // Common entry point to FSTENV and FSAVE - wait for FPU to be ready + { 0, 0x3fa, 0, "FSAVE_CORE " }, + { 0, 0x42f, 0, "FSAVE_COR_WAIT" }, + { 0, 0x42f, 0, "FSAVE_PM " }, // FSAVE protected mode helper + { 0, 0x436, 0, "FSAVE_REGFILE " }, // FSAVE subroutine to save register file (i.e. the part that isn't done in FSTENV) + { 0, 0x43c, 0, "FSAVE_LOOP " }, + { 0, 0x442, 0, "FSAVE_DONEFILE" }, + { 0, 0x444, 0, "FSAVE_NOWRITE " }, + { 0, 0x449, 0, "FSAVE_387 " }, //pla4 ?????1????<3E> 0000 10" }, + { 0, 0x451, 0, "FSAVE_287 " }, //pla4 ?????0????<3E> 0000 10" }, + { 0, 0x451, 0, "FSAVE_DONE " }, + {1, 0x459, 0, " FLDENV m"}, + {1, 0x45c, 0, " FRSTOR m"}, + { 0, 0x45f, 0, "FPU_ERROR4 " }, + { 0, 0x461, 0, "FRSTOR_WAIT " }, // Common entry point to FSTENV and FSAVE - wait for FPU to be ready + { 0, 0x466, 0, "FRSTOR_IRQT " }, + { 0, 0x46a, 0, "FRSTOR_ERRT " }, + { 0, 0x46e, 0, "FRSTOR_CORE " }, + { 0, 0x47b, 0, "FRSTOR_CORWAIT" }, + { 0, 0x49b, 0, "FRSTOR_PM " }, // FRSTOR protected mode helper + { 0, 0x4a7, 0, "FRSTOR_REGFILE" }, // FRSTOR subroutine to save register file (i.e. the part that isn't done in FLDENV) + { 0, 0x4ad, 0, "FRSTOR_LOOP " }, + { 0, 0x4b3, 0, "FRSTOR_DONEFIL" }, + { 0, 0x4b5, 0, "FRSTOR_387 " }, //pla4 ?????1????<3F> 0000 10" }, + { 0, 0x4ba, 0, "FRSTOR_DONE " }, + { 0, 0x4bb, 0, "FRSTOR_287 " }, //pla4 ?????0????<3F> 0000 10" }, + {0, 0x4c1, 0, " FP instructions that don't access memory"}, + { 0, 0x4c2, 0, "FPU_REG_WAIT " }, + { 0, 0x4c5, 0, "FPU_REG_IRQT " }, + { 0, 0x4c9, 0, "FPU_REG_ERRT " }, + { 0, 0x4cc, 0, "FPU_REG_CORE " }, + { 0, 0x4ce, 0, "FPU_REG_CORWAI" }, + { 0, 0x4d1, 0, "FPU_ERROR3 " }, + {1, 0x4d3, 0, " FBLD/FLD mt"}, + {1, 0x4d7, 0, " FADD/FMUL/FCOM/FCOMP/FSUB/FSUBR/FDIV/FDIVR/FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FLD/FILD md"}, + {1, 0x4db, 0, " FLD/FILD/FADD/FMUL/FCOM/FCOMP/FSUBR/FSUB/FDIVR/FDIV mq"}, + {1, 0x4df, 0, " FLDCW mw"}, + {1, 0x4e0, 0, " FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FILD mw"}, + { 0, 0x4e7, 0, "FPU_LD80_287 " }, + { 0, 0x4e8, 0, "FPU_LD3264_287" }, + { 0, 0x4ee, 0, "FPU_LD80_387 " }, + { 0, 0x4f0, 0, "FPU_LOAD_WAIT " }, + { 0, 0x4f4, 0, "FPU_LOAD_IRQT " }, + { 0, 0x4f8, 0, "FPU_LOAD_ERRT " }, + { 0, 0x4fc, 0, "FPU_LOAD_CORE " }, + { 0, 0x503, 0, "FPU_LOAD_CORWA" }, + { 0, 0x506, 0, "FPU_LOAD_LOOP " }, + { 0, 0x50c, 0, "FPU_LOAD_DONE " }, + { 0, 0x50e, 0, "FPU_LD80_DONE " }, + { 0, 0x514, 0, "FPU_ERROR2 " }, + { 0, 0x516, 0, "FLDCW " }, + { 0, 0x518, 0, "FLDCW_COR_WAIT" }, + { 0, 0x51c, 0, "FPU_LD3264_387" }, + { 0, 0x51f, 0, "FPU_LD3264_WAI" }, + { 0, 0x523, 0, "FPU_LD3264_IRQ" }, + { 0, 0x527, 0, "FPU_LD3264_ERR" }, + { 0, 0x52a, 0, "FPU_LD3264_COR" }, + { 0, 0x531, 0, "FPU_LD32 " }, + { 0, 0x533, 0, "FPU_LD32_WAIT " }, // Why wait after the data has been transferred? CPU bug? + { 0, 0x536, 0, "#NM " }, //pla4 ??????1???<3B><38><39><3C><3D> ??????01??<3B><38><39><3C><3D> ??????1?1?<34> 0000 10" }, coprocessor not available exception + {1, 0x538, 0, " FBSTP/FSTP mt"}, + {1, 0x53c, 0, " FST/FSTP/FIST/FISTP md"}, + {1, 0x540, 0, " FST/FSTP/FISTP mq"}, + {1, 0x544, 0, " FIST/FISTP mw"}, + { 0, 0x54b, 0, "FPU_ERROR ", }, + { 0, 0x54d, 0, "FPU_ST80_287 " }, + { 0, 0x54e, 0, "FPU_ST3264_287" }, + { 0, 0x554, 0, "FPU_ST80_387 " }, + { 0, 0x555, 0, "FPU_ST3264_387" }, + { 0, 0x556, 0, "FPU_STORE_WAIT" }, + { 0, 0x55a, 0, "FPU_STORE_IRQT" }, + { 0, 0x55e, 0, "FPU_STORE_ERRT" }, + { 0, 0x562, 0, "FPU_STORE_CORE" }, + { 0, 0x568, 0, "FPU_STORE_CORW" }, + { 0, 0x56f, 0, "FPU_STORE_LOOP" }, + { 0, 0x575, 0, "FPU_STORE_DONE" }, + { 0, 0x578, 0, "FPU_STORE_287 " }, + { 0, 0x57d, 0, "FPU_STORE_ABRT" }, + {0, 0x580, 2, " p MOV ES/DS/FS/GS,rw"}, + {0, 0x585, 2, " p MOV SS,rw"}, + { 0, 0x58a, 0, "PM_LD_DSESFSGS" }, // only called in protected mode, called before load of DS/ES/FS/GS happens + { 0, 0x58e, 0, "PM_LD_SS " }, + { 0, 0x592, 0, "NULL_SELECTOR " }, + { 0, 0x595, 0, "PM_LES " }, + { 0, 0x59a, 0, "PM_LSS " }, + { 0, 0x59f, 0, "PM_LDS " }, + { 0, 0x5a4, 0, "PM_LFS_LGS " }, + { 0, 0x5ac, 0, "JUMP_FAR_PM " }, + { 0, 0x5b3, 0, "JUMP_FAR_PM_GATE" }, + { 0, 0x5b8, 0, "CALL_FAR_PM_GATE" }, + { 0, 0x5bb, 0, "GENERAL_FAULTP" }, + { 0, 0x5bd, 0, "CALLGATE286 " }, + { 0, 0x5be, 0, "CALLGATE386 " }, + { 0, 0x5c4, 0, "LD_DES_SSFSGS " }, + { 0, 0x5c9, 0, "LD_DESCRIPTOR " }, + { 0, 0x5ce, 0, "LD_DESCRIPTOR2" }, + { 0, 0x5d3, 0, "PRESENT_TSS " }, // Available (<1F>) or Busy (<1E>) + { 0, 0x5d5, 0, "PROT_TESTS_PASSED" }, + { 0, 0x5d8, 0, "PROT_TESTS_CMN" }, + { 0, 0x5da, 0, "PROT_TESTS_PASSED2" }, + { 0, 0x5df, 0, "PROT_TESTS_P16" }, + { 0, 0x5e0, 0, "CALL_FAR_PM " }, + { 0, 0x5ec, 0, "MORE_PRIV16 " }, + { 0, 0x5f0, 0, "GENERAL_FAUL2P" }, + { 0, 0x5f2, 0, "PUSH_V86_SREGS" }, // Push(GS) code in https://www.felixcloutier.com/x86/intn:into:int3:int1 ? + { 0, 0x5fb, 0, "MORE_PRIVILEGE" }, // CALL MORE-PRIVILEGE case in PRM + { 0, 0x602, 0, "FOUND_STACK " }, // We have found the offset of the SS/eSP pair in the TSS + { 0, 0x60b, 0, "MORE_PRIV2 " }, + { 0, 0x613, 0, "MORE_PRIV3 " }, + { 0, 0x615, 0, "MORE_PRIV_INT " }, + { 0, 0x619, 0, "COPY_PARAMS " }, + { 0, 0x61e, 0, "COPY_PRMS_LOOP" }, + { 0, 0x622, 0, "COPY_PRMS_DONE" }, + { 0, 0x623, 0, "COPY_PRMS_SKIP" }, + { 0, 0x62b, 0, "NO_ERROR_CODE " }, + { 0, 0x633, 0, "MORE_PRIV_DONE" }, + { 0, 0x63b, 0, "ZERO_V86_SREGS" }, // GS := 0 code in https://www.felixcloutier.com/x86/intn:into:int3:int1 ? + { 0, 0x63f, 0, "IRETd_V86 " }, // Returns to? from? v86 mode? real mode? + { 0, 0x657, 0, "IRETd_V86_LOOP" }, + { 0, 0x65c, 0, "TASK_RETURN " }, // TASK-RETURN described in https ://www.felixcloutier.com/x86/iret:iretd:iretq ? + { 0, 0x671, 0, "LOAD_TASK_16B " }, + {3, 0x673,38, " p IRETd"}, // cycle count is 38/82/TS/60 + { 0, 0x67f, 0, "RETF_PM " }, + { 0, 0x686, 0, "RETF_OUTER_LEV" }, + { 0, 0x699, 0, "RETF_OL_ES " }, + { 0, 0x69d, 0, "RETF_OL_DS " }, + { 0, 0x6a1, 0, "RETF_OL_FS " }, + { 0, 0x6a5, 0, "RETF_OL_GS " }, + { 0, 0x6a8, 0, "ZERO_SLCTR_AR " }, + {1, 0x6aa,21, " p ARPL mw,rw"}, + { 0, 0x6b3, 0, "ARPL_FAILED " }, + {0, 0x6b6,20, " p ARPL rw,rw"}, + {1, 0x6be,27, " p LTR mw"}, + {0, 0x6c3,23, " p LTR rw"}, + { 0, 0x6c5, 0, "LTR_COMMON " }, + {1, 0x6cd, 2, " p STR mw"}, + {0, 0x6cf, 2, " p STR rw"}, + {1, 0x6d1,24, " p LLDT mw"}, + {0, 0x6d6,20, " p LLDT rw"}, + { 0, 0x6c8, 0, "LLDT_COMMON " }, + { 0, 0x6dd, 0, "LLDT_TEST_PASS" }, + {1, 0x6e0, 2, " p SLDT mw"}, + {0, 0x6e2, 2, " p SLDT rw"}, + {1, 0x6e4,16, " p LAR rv,mv"}, + {0, 0x6e7,15, " p LAR rv,rv"}, + {1, 0x6ea,21, " p LSL rv,mv"}, // cycle count is 21/26 + {0, 0x6ec,20, " p LSL rv,rv"}, // cycle count is 20/25 + { 0, 0x6ee, 0, "LSL_HELPER "}, + { 0, 0x6f5, 0, "LSL_GRANULARITY_COARSE" }, + { 0, 0x6fd, 0, "LSL_GRANULARITY_FINE" }, + {1, 0x700,11, " p VERR mw"}, + {0, 0x703,10, " p VERR rw"}, + {1, 0x706,16, " p VERW mw"}, + {0, 0x709,15, " p VERW rw"}, + { 0, 0x70c, 0, "LAR_LSL_VERRWM" }, + { 0, 0x70e, 0, "LAR_LSL_VERRWR" }, + { 0, 0x70f, 0, "LAR_LSL_VERRW " }, + { 0, 0x71a, 0, "LAR_VERRW_SUCCEEDED" }, //pla4 0????01011<30> 0????01100<30> 0????1011?<30><32> 0????10?0?<32> 0????10?1?<33> 0????1101?<30> 0????1?000<30> 0????1?01?<32> 0?????001?<30> 0?????010?<30> 0??????001<30> ?????1111?<32> ?????111??<30> 0000 10" }, + { 0, 0x71c, 0, "TASKGATE " }, + { 0, 0x71f, 0, "AVAIL_TSS " }, + { 0, 0x724, 0, "SAVE_TASK " }, + { 0, 0x72b, 0, "SAVE_TASK_16 " }, + { 0, 0x72e, 0, "SAVE_TASK_COMM" }, + { 0, 0x737, 0, "SAVE_TASK_LOOP" }, + { 0, 0x73f, 0, "CALL_SAVE_TASK" }, + { 0, 0x743, 0, "AVAIL_TSS_PR " }, + { 0, 0x749, 0, "SWITCH_TASK " }, + { 0, 0x750, 0, "LOAD_TASK " }, + { 0, 0x758, 0, "TR_BACKLINK_OK" }, + { 0, 0x75a, 0, "LOAD_TASK_32 " }, + { 0, 0x764, 0, "LOAD_TASK_16 " }, + { 0, 0x765, 0, "LOAD_TASK_16A " }, + { 0, 0x765, 0, "LOAD_TASK_COMM" }, // Common to both 16-bit and 32-bit LOAD_TASK + { 0, 0x773, 0, "LOAD_TASK_LOOP" }, + { 0, 0x787, 0, "LOAD_TASK_NOPG" }, + { 0, 0x78c, 0, "NOT_NESTED_TSK" }, + { 0, 0x792, 0, "SET_TSKSWTCHED" }, + { 0, 0x795, 0, "WRITE_BACK_CR0" }, + { 0, 0x798, 0, "TASK_FINAL_V86" }, + { 0, 0x798, 0, "TASK_FV86_LOOP" }, + { 0, 0x7ab, 0, "TASK_FINAL_PM " }, + { 0, 0x7d0, 0, "HANDLE_TS_BP " }, // Last phase of task switching - handle breakpoints + { 0, 0x7d4, 0, "ADJ_STACK_DONE" }, + { 0, 0x7d7, 0, "TSKF_NO_ERRCOD" }, + { 0, 0x7e3, 0, "ADJ_STACK_16 " }, + { 0, 0x7e5, 0, "NULL_SELECTOR2" }, + { 0, 0x7e8, 0, "AVAIL_TSS_NP " }, + { 0, 0x7eb, 0, "NO_DEBUG_BP " }, + { 0, 0x7ec, 0, "CLI_STI " }, + {0, 0x7ef, 2, " CLC/STC/CLD/STD/CMC"}, + {2, 0x7f2, 4, " p PUSHFd"}, + {0, 0x7f7, 3, " CLI/STI"}, // cycle count is 2 for STI? + {2, 0x7f9, 4, " r PUSHFd"}, + {3, 0x7fb, 5, " r POPFd"}, + {0, 0x7fd,37, " r INT ib"}, + {3, 0x7ff,22, " r IRETd"}, // cycle count is 22/38 + { 0, 0x801, 0, "OVERLONG_INST "}, //small pla 010100 01 ? 0011011" }, + {3, 0x803, 5, " p POPFd"}, + {0, 0x808,59, " p INT ib"}, // cycle count is 59/99/119/TS + { 0, 0x80a, 0, "IRET_REAL_MODE" }, + {0, 0x816,33, " INT 3"}, // cycle count is 33/59/99/119/TS + {1, 0x818,10, " BOUND rv,m2v"}, // cycle count in no-jump case + { 0, 0x822, 0, "#BR " }, //small pla ?????? 11 ? 0011010" }, bound range exceeded + { 0, 0x824, 0, "DIVIDE_ERROR " }, //small pla ?????? 11 ? 0011010" }, + {0, 0x827, 3, " INTO"}, // cycle count is 35/3/59/99/119/TS + { 0, 0x82a, 0, "NO_OVERFLOW " }, + { 0, 0x82b, 0, "#UD " }, // invalid opcode + { 0, 0x82d, 0, "HARDWARE_IRQ " }, //small pla 11010? 01 ? 0011011" }, + { 0, 0x836, 0, "NMI " }, //small pla ?0010? 01 ? 0011011" }, + { 0, 0x839, 0, "TRIPLE_FAULT " }, //small pla ?????1 00 ? 0000000" }, + { 0, 0x83a, 0, "TRIPLE_FT_WAIT" }, + { 0, 0x83f, 0, "#DF " }, //small pla ?????? 00 1 0100010" }, double fault + {0, 0x844, 0, "NO_PRIVILEGE " }, + {0, 0x849, 0, " unused?"}, + { 0, 0x857, 0, "ACCESS_VIOLATI" }, //small pla ?????? 00 ? 0010110" }, + { 0, 0x85b, 0, "#GP(0) " }, + { 0, 0x85d, 0, "#GP/#TS(I0,E0)" }, + { 0, 0x85e, 0, "#GP/#TS(SIGMA)" }, //pla4 ?????0011?<24> ?????01001<24> 0000 10" }, + { 0, 0x860, 0, "#GP(SIGMA) " }, + { 0, 0x862, 0, "#SS(0) " }, + { 0, 0x863, 0, "#SS(SIGMA) " }, + { 0, 0x865, 0, "#GP(I1,E0) " }, // #GP((TMP_TR & -4) | 2) general fault with EXT = 0, I = 1 => fault with gate descriptor in the IDT + { 0, 0x866, 0, "#GP(SIGMA | 2)" }, // I = 1 + { 0, 0x868, 0, "#TS(SIGMA) " }, // #TS(SIGMA) + { 0, 0x86a, 0, "#SS(I0,E0) " }, // #SS(TMP_TR & -4) + { 0, 0x86d, 0, "FAULT_SUPPRESS" }, + { 0, 0x86e, 0, "LAR_LSL_VERRW_NULL_SELECTOR" }, + { 0, 0x870, 0, "#NP(I0,E0) " }, // #NP(TMP_TR & -4) + { 0, 0x871, 0, "#NP(I1,E0) " }, // #NP((TMP_TR & -4)|2) + { 0, 0x873, 0, "NP_COMMON " }, // Common to both #NP with I=0 and I=1 + { 0, 0x874, 0, "FAULT_ERR_CODE" }, + { 0, 0x87b, 0, "EXT_BIT_DONE " }, + { 0, 0x882, 0, "STRING_CORRECT" }, + { 0, 0x889, 0, "STRCORR_DOWN " }, + { 0, 0x88a, 0, "STRCORR_LOOP " }, + { 0, 0x890, 0, "FAULT " }, + { 0, 0x893, 0, "FLAGS_OK " }, + { 0, 0x89a, 0, "RESUME_FLAG_OK" }, + { 0, 0x89e, 0, "INTERRUPT_X " }, + { 0, 0x89f, 0, "INTERRUPT " }, // Software or hardware interrupt (vector entries are 4 byte far pointers) + { 0, 0x8b0, 0, "INTERRUPT_PM " }, // Software or hardware interrupt in protected or v86 mode (vector entries are 8 byte gate descriptors) + { 0, 0x8ba, 0, "INTERRUPT_COMM" }, + { 0, 0x8bf, 0, "INTERRUPT_SW " }, + { 0, 0x8c2, 0, "INTGATE286 " }, + { 0, 0x8c3, 0, "TRAPGATE286 " }, + { 0, 0x8cb, 0, "INTGATE386 " }, + { 0, 0x8cc, 0, "TRAPGATE386 " }, + { 0, 0x8d5, 0, "TRAP_INT_GATE " }, // common to 286/386 trap/interrupt gates + { 0, 0x8d5, 0, "PUSH_INT_FRAME" }, // pushes flags, return address and error code + { 0, 0x8e3, 0, "TRAP_INT_DONE " }, // end of trap/interrupt gate code + { 0, 0x8e5, 0, "PUSH_ERRORCODE" }, // pushes the error code onto the stack for faults + { 0, 0x8e9, 0, "PAGE_FAULT " }, //small pla ?????? 00 0 1011010" }, + { 0, 0x8ea, 0, "PAGE_FAULTLOOP" }, + {0, 0x8f6, 0, " LOADALL386"}, // don't know cycle count + { 0, 0x902, 0, "LOADALL_LOOP1 " }, + { 0, 0x90b, 0, "LOADALL_LOOP2 " }, + { 0, 0x917, 0, "LOADALL_LOOP3 " }, + { 0, 0x91c, 0, "LOADALL_LOOP4 " }, + { 0, 0x932, 0, "LOADALL_FINAL " }, + { 0, 0x939, 0, "LOADALL_PAGING" }, + {0, 0x93c, 0, " ICEBP"}, // don't know cycle count + { 0, 0x93f, 0, "SINGLE_STEP " }, //small pla ???0?? 01 ? 0011011" }, single stepping via trap flag + { 0, 0x941, 0, "BREAKPOINT " }, //small pla ??11?? 01 ? 0011011" }, comes in via small pla when DR0-DR3 are hit? Also jumped to from microcode for task switch breakpoint + { 0, 0x943, 0, "BREAKPOINT_CMN" }, // Breakpoint code common to software breakpoints (ICEBP) and hardware/signal breakpoints (like debug register condition getting hit) + { 0, 0x94f, 0, "ICE_SINGLESTEP" }, // SINGLE_STEP handled by ICE + { 0, 0x953, 0, "ICE_PIN " }, //small pla ??011? 01 ? 0011011" }, Enter ICE mode via ICE# pin like SMI# pin? + { 0, 0x95a, 0, "ICE_PIN_LOOP " }, + { 0, 0x95e, 0, "STOREALL16 " }, + { 0, 0x961, 0, "STOREALL " }, + { 0, 0x95e, 0, "STOREALL_COMM " }, + { 0, 0x970, 0, "STOREALL_LOOP1" }, + { 0, 0x980, 0, "STOREALL_LOOP2" }, + { 0, 0x981, 0, "STOREALL_LOOPS" }, + { 0, 0x989, 0, "STOREALL_LOOP3" }, + { 0, 0x993, 0, "STOREALL_LOOP4" }, + { 0, 0x99a, 0, "STOREALL_L4_ST" }, + { 0, 0x9a6, 0, "BOOTUP " }, + { 0, 0x9a7, 0, "BOOTUP_LOOP1 " }, + { 0, 0x9ab, 0, "BOOTUP_LOOP2 " }, + { 0, 0x9af, 0, "BOOTUP_LOOP3 " }, + { 0, 0x9bc, 0, "BOOTUP_JUMP " }, // Jump to initial boot CS:IP (BASE=0xffff0000 LIMIT=0xffff):0x0000fff0 aka linear address 0xfffffff0 + diff --git a/80386/images/README.md b/80386/images/README.md new file mode 100644 index 0000000..e1633e5 --- /dev/null +++ b/80386/images/README.md @@ -0,0 +1 @@ +A die photos by Ken Shirriff. diff --git a/80386/images/decoder-addr-l-b.tif b/80386/images/decoder-addr-l-b.tif new file mode 100644 index 0000000..75adbfb Binary files /dev/null and b/80386/images/decoder-addr-l-b.tif differ diff --git a/80386/images/decoder-addr-rt-b.tif b/80386/images/decoder-addr-rt-b.tif new file mode 100644 index 0000000..917c288 Binary files /dev/null and b/80386/images/decoder-addr-rt-b.tif differ diff --git a/80386/images/decoder-l-b.tif b/80386/images/decoder-l-b.tif new file mode 100644 index 0000000..6912030 Binary files /dev/null and b/80386/images/decoder-l-b.tif differ diff --git a/80386/images/decoder-rt-b.tif b/80386/images/decoder-rt-b.tif new file mode 100644 index 0000000..d0e3c82 Binary files /dev/null and b/80386/images/decoder-rt-b.tif differ diff --git a/80386/images/microcode.jpg b/80386/images/microcode.jpg new file mode 100644 index 0000000..8442d89 Binary files /dev/null and b/80386/images/microcode.jpg differ diff --git a/80386/images/pla4.jpg b/80386/images/pla4.jpg new file mode 100644 index 0000000..546ffc3 Binary files /dev/null and b/80386/images/pla4.jpg differ diff --git a/80386/images/rom1.jpg b/80386/images/rom1.jpg new file mode 100644 index 0000000..587d333 Binary files /dev/null and b/80386/images/rom1.jpg differ diff --git a/80386/microcode_10.txt b/80386/microcode_10.txt new file mode 100644 index 0000000..12c9c49 --- /dev/null +++ b/80386/microcode_10.txt @@ -0,0 +1,2880 @@ +000 =====================================| +001 BC F OP S WXY 67 9 | LDTR BOOTUP LJUMP IND= +002 B D G I L QRST Z | 0 -> OPR_W 0x29 LDCNTR +------------------------------------------|---------------------------------------------------------------------------------------------- +003 STU W YZ012 | SRCREG PASS RNI 0 MOV r,r +004 G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +005 N TU W YZ012 | IMM PASS RNI 0 MOV r,i +006 G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +007 G L RS 012 | SEGREG -> DSTREG RNI 0 MOVZX rv,segreg +008 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +009 H M R TU W YZ0 234 6 9&| DSTREG DES_SR PASS RnI DLY SBRM 0 r MOV ES/SS/DS/FS/GS,rw +00A G LMN S | SIGMA -> SEGREG +------------------------------------------|---------------------------------------------------------------------------------------------- +00B AB F N P S W YZ 5 7 9 | PM_LD_SS LJMPP RD W 1 MOV SS,mw +00C A CDE H M VW 34 89 | DES_SR TST_DES_SS PTSAV7 DLY SPTR +00D H M O R TU W YZ0 23 6 9&| OPR_R DES_SR PASS RnI UNL SBRM +00E G LMN S | SIGMA -> SEGREG +------------------------------------------|---------------------------------------------------------------------------------------------- +00F AB D F N P S W YZ 5 7 9 | PM_LD_DSESFSGS LJMPP RD W 1 MOV ES/DS/FS/GS,mw +010 A CDEF H M VWXY 34 89 | DES_SR TST_DES_SIMPLE PTSAV1 DLY SPTR +011 H M O R TU W YZ0123 6 9&| OPR_R DES_SR PASS RNI UNL SBRM +012 G LMN S | SIGMA -> SEGREG +------------------------------------------|---------------------------------------------------------------------------------------------- +013 G I L S 012 5 78 &| SRCREG -> OPR_W RNI WR 1 MOV [i],A MOV m,r +014 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +015 G I L N 012 5 78 &| IMM -> OPR_W RNI WR 1 MOV m,i +016 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +017 G I L RS 012 5 789 | SEGREG -> OPR_W RNI WR W 1 MOV mw,segreg +018 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +019 5 7 &| RD 1 MOV A,[i] MOV r,m +01A 34 | DLY +01B 012 | RNI +01C G L O R 3 | OPR_R -> DSTREG UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +01D F R TUVWXYZ012 | DSTREG SRCREG +-&|^ RNI 0 ADD/OR/ADC/SBB/AND/SUB/XOR r,r +01E G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +01F F R TUVWX 012 | DSTREG SRCREG CMPTST RNI 0 CMP r,r TEST r,r +020 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +021 R TUVWXY 012 | DSTREG ++--~- RNI 0 INC/DEC/NOT/NEG r +022 G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +023 AB DE R TUVWXYZ012 | DSTREG IMM +-&|^ RNI 0 ADD/OR/ADC/SBB/AND/SUB/XOR r,i +024 G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +025 AB DE R TUVWX 012 | DSTREG IMM CMPTST RNI 0 CMP/TEST A,i +026 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +027 5 7 &| RD 1 ADD/OR/ADC/SBB/AND/SUB/XOR r,m +028 34 | DLY +029 GHI K O R 3 | OPR_R -> TMPB UNL +02A AB D R TUVWXYZ012 | DSTREG TMPB +-&|^ RNI +02B G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +02C 5 7 &| RD 1 CMP r,m +02D 34 | DLY +02E GHI K O R 3 | OPR_R -> TMPB UNL +02F AB D R TUVWX 012 | DSTREG TMPB CMPTST RNI +030 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +031 5 7 &| RD 1 CMP/TEST m,i +032 34 | DLY +033 AB DE O R TUVWX 0123 | OPR_R IMM CMPTST RNI UNL +034 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +035 5 7 &| RD 1 CMP/TEST m,r +036 34 | DLY +037 F O R TUVWX 0123 | OPR_R SRCREG CMPTST RNI UNL +038 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +039 GH JKLMNO QR T XYZ 5 7 &| EFLAGS -> FLAGSB FLGSBA RD 9 ADD/OR/ADC/SBB/AND/SUB/XOR m,i +03A 34 | DLY +03B AB D FGHI K O R U X Z 3 | OPR_R -> TMPB WRITE_RESULT JMP UNL +03C AB DE NO Q TUVWXYZ | TMPB IMM +-&|^ +------------------------------------------|---------------------------------------------------------------------------------------------- +03D ABCD UVWXY | SETCONDR_FALSE JNcond 0 SETcond rb +03E T VW YZ | BITS8 +03F CDEF TU W Y 012 | 1 PASS2 RNI +040 G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +041 G L QRS 012 | 0 -> DSTREG RNI 0 SETCONDR_FALSE +042 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +043 ABC EF UVWXY | SETCONDM_FALSE JNcond 1 SETcond mb +044 T VW YZ | BITS8 +045 CDEF TU W Y | 1 PASS2 +046 G I L N S 012 5 78 &| SIGMA -> OPR_W RNI WR 0 WRITE_RESULT +047 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +048 G I L QRS 012 5 78 &| 0 -> OPR_W RNI WR 0 SETCONDM_FALSE +049 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +04A GH JKLMNO QR T XYZ 5 7 &| EFLAGS -> FLAGSB FLGSBA RD 9 ADD/OR/ADC/SBB/AND/SUB/XOR m,r +04B 34 | DLY +04C DE GHI K O R U X Z 3 | OPR_R -> TMPB WRITE_RESULT JMP UNL +04D F NO Q TUVWXYZ | TMPB SRCREG +-&|^ +------------------------------------------|---------------------------------------------------------------------------------------------- +04E 5 7 &| RD 9 INC/DEC/NOT/NEG m +04F C F U X Z 34 | WRITE_RESULT JMP DLY +050 O R TUVWXY 3 | OPR_R ++--~- UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +051 G JK M PQR 34 | eCX -> COUNTR DLY 0 JeCXZ cb +052 AB DEF H KL NO QRSTUV YZ 67 &| EIP DESCOD IMM8 ADD IN=+ +053 A C E UVW Y | Jcond_DONE JCNTNZ +054 01 5 9&| RNi PREF +055 A CD H N S U X Z 34 | SIGMA -> eIP Jcond_DONE JMP DLY +056 01 | RNi +------------------------------------------|---------------------------------------------------------------------------------------------- +057 G JK M PQR 34 | eCX -> COUNTR DLY 0 LOOP cb +058 AB DEF H KL NO QRSTUV YZ 67 &| EIP DESCOD IMM8 ADD IN=+ +059 ABCD UV XYZ | LOOP_UNTAKEN JCNT1 +05A T 5 9&| DECNTR PREF +05B AB E H N S U X Z 34 | SIGMA -> eIP Jcond_DONE JMP DLY 0 LOOP_DONE +05C G JKL N P RS 01 | COUNTR -> eCX RNi +------------------------------------------|---------------------------------------------------------------------------------------------- +05D E H KL NO QRS U X Z 34 67 9 | EIP DESCOD LOOP_DONE JMP DLY IND= 0 LOOP_UNTAKEN +05E NO QRSTU W YZ 5 9&| EIP PASS PREF +------------------------------------------|---------------------------------------------------------------------------------------------- +05F G JK M PQR 34 | eCX -> COUNTR DLY 0 LOOPE/LOOPNE cb +060 AB DEF H KL NO QRSTUV YZ 67 &| EIP DESCOD IMM8 ADD IN=+ +061 D UVWX | LOOP_UNTAKEN LOOPnE +062 T 5 9&| DECNTR PREF +063 ABC E H N S U X Z 34 | SIGMA -> eIP Jcond_DONE JMP DLY +064 G JKL N P RS 01 | COUNTR -> eCX RNi +------------------------------------------|---------------------------------------------------------------------------------------------- +065 ABCD H KL NO QRS UVWXY 34 67 &| EIP DESCOD Jcond_DONE JNcond DLY IN=+ 0 Jcond cb/cv +066 AB DEF NO QRSTUV YZ01 5 9&| EIP IMM8 ADD RNi PREF +067 34 | DLY 0 JMP_PREFINAL +068 H N S 012 | SIGMA -> eIP RNI 0 JMP_FINAL +069 =====================================| 0 Jcond_DONE +06A AB DEF H KL NO QRSTUV YZ 34 67 &| EIP DESCOD IMM8 ADD DLY IN=+ 0 JMP c +06B EF U X Z 5 9&| JMP_FINAL JMP PREF 0 JMP_PREF +06C 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +06D DE H KL R U X Z 34 67 9 | DSTREG DESCOD JMP_PREFINAL JMP DLY IND= 0 JMP rv +06E R TU W YZ 5 9&| DSTREG PASS PREF +------------------------------------------|---------------------------------------------------------------------------------------------- +06F 5 7 &| RD 1 JMP mv +070 D F U X Z 34 | JMP_PREF JMP DLY +071 H KL O R TU W YZ 3 67 9 | OPR_R DESCOD PASS UNL IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +072 AB DE N STUV YZ 5 7 &| SIGMA IMM ADD RD 3 RET/RET iw +073 C H LMN S U X Z 34 | SIGMA -> eSP JMP_PREF JMP DLY +074 H KL O R TU W YZ 3 67 9 | OPR_R DESCOD PASS UNL IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +075 G I L NO QRS 5 78 &| EIP -> OPR_W WR 2 CALL cw +076 AB DEF H KL NO QRS 34 67 &| EIP DESCOD IMM8 DLY IN=+ +077 CDEF H LMN S U X Z 5 9&| SIGMA -> eSP JMP_FINAL JMP PREF +078 AB DEF NO QRSTUV YZ 34 | EIP IMM8 ADD DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +079 G I L NO QRS 5 78 &| EIP -> OPR_W WR 2 CALL rv +07A B EF H KL R U X Z 34 67 9 | DSTREG DESCOD JMP_PREFINAL JMP DLY IND= +07B E H LMN STU W Y 5 9&| SIGMA -> eSP DSTREG PASS2 PREF +------------------------------------------|---------------------------------------------------------------------------------------------- +07C 5 7 &| RD 1 CALL mv +07D D F H K MNOP RSTUV YZ 34 67 &| ESP DESSTK NEGWSZ ADD DLY IN=+ +07E G I L NO QRS 5 78 &| EIP -> OPR_W WR +07F B D H LMN S U X Z 34 | SIGMA -> eSP JMP_PREF JMP DLY +080 H KL O R TU W YZ 3 67 9 | OPR_R DESCOD PASS UNL IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +081 5 7 &| RD 1 PUSH mv +082 D F H K MNOP RSTUV YZ 34 67 &| ESP DESSTK NEGWSZ ADD DLY IN=+ +083 H LMN S 5 8 &| SIGMA -> eSP wr +084 01234 | RNI DLY +085 O R 3 | OPR_R UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +086 G I L R 012 5 78 &| DSTREG -> OPR_W RNI WR 2 PUSH rv +087 H LMN S 34 | SIGMA -> eSP DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +088 EF NOP RSTUV Z 34 | ESP BITS_V SUB DLY 0 PUSHAd +089 C EF H K MN STUV YZ 67 &| SIGMA DESSTK -1 ADD IN=+ +08A BC FG I L NOP T Z 5 78 &| EDI -> OPR_W 6 LDCNTR WR +08B DE 345 | WORDSZ DLY IN+= +08C G I L QR T 5 78 &| IRF -> OPR_W DECNTR WR +08D =====================================| 0 PUSHAd_LOOP +08E F UVW Y 345 9 | PUSHAd_LOOP JCNTNZ DLY IN+D +08F G I L QR T 012 5 78 &| IRF -> OPR_W DECNTR RNI WR +090 H LMN S 34 | SIGMA -> eSP DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +091 BC EF H LMN ST Z 5 7 &| SIGMA -> eSP 0x47 LDCNTR RD 3 POPA +092 DE H K MNOP RSTUV YZ 34 67 9 | ESP DESSTK WORDSZ ADD DLY IND= 0 POPAd_LOOP +093 FG KL O R UVW Z 3 5 7 &| OPR_R -> IRF POPAd_LOOP JCT4N1 UNL RD +094 H LMN ST | SIGMA -> eSP DECNTR +095 01234 | RNI DLY +096 G KL O R 3 | OPR_R -> IRF UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +097 B EF H LMN ST Z 5 7 &| SIGMA -> eSP 7 LDCNTR RD 3 POPAD +098 DE H K MNOP RSTUV YZ 34 67 9 | ESP DESSTK WORDSZ ADD DLY IND= +099 DEFG KL O R U X Z 3 5 7 &| OPR_R -> IRF POPAd_LOOP JMP UNL RD +09A H LMN ST | SIGMA -> eSP DECNTR +------------------------------------------|---------------------------------------------------------------------------------------------- +09B G I L RS 012 5 789 | SEGREG -> OPR_W RNI WR W 2 PUSH segreg +09C H LMN S 34 | SIGMA -> eSP DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +09D G I L N 012 5 78 &| IMM -> OPR_W RNI WR 2 PUSH i +09E H LMN S 34 | SIGMA -> eSP DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +09F H LMN S 5 7 &| SIGMA -> eSP RD 3 POP rv +0A0 01234 | RNI DLY +0A1 G L O R 3 | OPR_R -> DSTREG UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +0A2 H LMN S 5 7 9 | SIGMA -> eSP RD W 3 POP SS +0A3 AB F N P S W YZ | PM_LD_SS LJMPP +0A4 A CDE H M VW 34 89 | DES_SR TST_DES_SS PTSAV7 DLY SPTR +0A5 H M O R TU W YZ0 23 6 9&| OPR_R DES_SR PASS RnI UNL SBRM +0A6 G LMN S | SIGMA -> SEGREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0A7 H LMN S 5 7 9 | SIGMA -> eSP RD W 3 POP ES/DS/FS/GS +0A8 AB D F N P S W YZ | PM_LD_DSESFSGS LJMPP +0A9 A CDEF H M VWXY 34 89 | DES_SR TST_DES_SIMPLE PTSAV1 DLY SPTR +0AA H M O R TU W YZ0123 6 9&| OPR_R DES_SR PASS RNI UNL SBRM +0AB G LMN S | SIGMA -> SEGREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0AC H LMN S 5 7 &| SIGMA -> eSP RD 3 POP mv +0AD H L P S 34 67 &| EA DES_OS 0 DLY IN=+ +0AE 5 8 &| wr +0AF 01234 | RNI DLY +0B0 O R 3 | OPR_R UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +0B1 567 &| rd 9 XCHG m,r +0B2 34 | DLY +0B3 G I L S 5 78 &| SRCREG -> OPR_W WR +0B4 01234 | RNI DLY +0B5 G M O R 3 | OPR_R -> SRCREG UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +0B6 E G JK M STU W Y | SRCREG -> COUNTR DSTREG PASS2 0 XCHG eAX,rv XCHG r,r +0B7 G L N P RS 012 | COUNTR -> DSTREG RNI +0B8 G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0B9 G M O S 012 5 | IRF2 -> SRCREG 0 RNI IN+= 1 LEA rv,m +0BA =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +0BB BC E TU W Y 5 7 &| 3 PASS2 RD 1 LDS rv,m +0BC DE 345 | WORDSZ DLY IN+= +0BD A N P S W YZ 5 7 9 | PM_LDS LJMPP RD W +0BE GHI L O R 3 | OPR_R -> TMPD UNL +0BF 34 | DLY +0C0 AB E G IJK O R TU W Y 0123 6 9&| OPR_R -> DS TMPD PASS2 RNI UNL SBRM +0C1 G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0C2 TU W Y 5 7 &| 0 PASS2 RD 1 LES rv,m +0C3 DE 345 | WORDSZ DLY IN+= +0C4 A C E N P S W YZ 5 7 9 | PM_LES LJMPP RD W +0C5 GHI L O R 3 | OPR_R -> TMPD UNL +0C6 34 | DLY +0C7 AB E G IJKLM O R TU W Y 0123 6 9&| OPR_R -> ES TMPD PASS2 RNI UNL SBRM +0C8 G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0C9 CD F N TUV X Z 5 7 &| IMM 0x10 XOR RD 1 LSS rv,m +0CA DE G JK MN S 345 | SIGMA -> COUNTR WORDSZ DLY IN+= +0CB A D F N P S W YZ 5 7 9 | PM_LSS LJMPP RD W +0CC GHI L O R 3 | OPR_R -> TMPD UNL +0CD 34 | DLY +0CE AB E G KL O R TU W Y 0123 6 9&| OPR_R -> IRF TMPD PASS2 RNI UNL SBRM +0CF G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0D0 CD F N TUV X Z 5 7 &| IMM 0x10 XOR RD 1 LFS/LGS rv,m +0D1 DE G JK MN S 345 | SIGMA -> COUNTR WORDSZ DLY IN+= +0D2 BC EF N P S W YZ 5 7 9 | PM_LFS_LGS LJMPP RD W +0D3 GHI L O R 3 | OPR_R -> TMPD UNL +0D4 34 | DLY +0D5 AB E G KL O R TU W Y 0123 6 9&| OPR_R -> IRF TMPD PASS2 RNI UNL SBRM +0D6 G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0D7 A C F NO QR TUV XYZ012 | EFLAGS 0x37fd7 AND RNI 0 LAHF +0D8 H J LMN S | SIGMA -> AH +------------------------------------------|---------------------------------------------------------------------------------------------- +0D9 T VW YZ | BITS8 0 SAHF +0DA G KLM O Q S 012 | eDX_AH -> FLAGSL RNI +0DB =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +0DC ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 CLTS +0DD A DE TUV X Z | -1 8 XOR +0DE GHI K N S | SIGMA -> TMPB +0DF AB D NO Q STUV XYZ012 | CR0 TMPB AND RNI +0E0 GHI K MN S | SIGMA -> CR0 +------------------------------------------|---------------------------------------------------------------------------------------------- +0E1 ABCD F U Y | SALC_DONE JNC 0 SALC +0E2 H JKLM QRS 01 | 0 -> AL RNi +0E3 H JKLM 012 | -1 -> AL RNI +0E4 =====================================| 0 SALC_DONE +0E5 EFG K MN TU W Y | IMM -> COUNT5 BITS_V PASS2 0 RCL/RCR r,ib +0E6 CDEF N STUV YZ | SIGMA 1 ADD +0E7 ABC E GHI K N S U X Z | SIGMA -> TMPB RCLRCR_R_COMM JMP +0E8 AB D GHI LMN P RSTUV Z | COUNTR -> TMPC TMPB SUB +------------------------------------------|---------------------------------------------------------------------------------------------- +0E9 EFG K MNOPQR TU W Y | ECX -> COUNT5 BITS_V PASS2 0 RCL/RCR r,CL +0EA CDEF N STUV YZ | SIGMA 1 ADD +0EB GHI K N S | SIGMA -> TMPB +0EC AB D GHI LMN P RSTUV Z | COUNTR -> TMPC TMPB SUB +0ED AB EFGHI L R TUVWX Z | DSTREG -> TMPD TMPC <<>>? 0 RCLRCR_R_COMM +0EE ABCD FGHI MN S U WXY | SIGMA -> TMPE RCLRCR_R_LOOP JG +0EF AB E NO STU WX Z012 | TMPE TMPD >>< DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0F1 AB D NO RSTUV Z | TMPC TMPB SUB 0 RCLRCR_R_LOOP +0F2 AB D GHI LMN STUV Z | SIGMA -> TMPC TMPB SUB +0F3 EF TUVWX Z | -1 BITS_V <<>>? +0F4 AB E NO STU WXYZ | TMPE TMPD SHIFT +0F5 D GHI L NO S U WXY | TMPE -> TMPD RCLRCR_R_LOOP JG +0F6 AB EFGHI MN STUVWX Z | SIGMA -> TMPE TMPC <<>>? +0F7 AB E NO STU WX Z012 | TMPE TMPD >>< DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0F9 AB DE R TUVWX Z | DSTREG IMM <<>>? 0 ROL/ROR/SHL/SHR/SAR r,ib +0FA E N STU WX Z012 | SIGMA DSTREG >>< DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0FC AB DE R TUVWX Z | DSTREG IMM <<>>? 0 SHxD rv,rv,ib +0FD E STU WX Z012 | SRCREG DSTREG >>< DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +0FF ABCDE R TUVWX Z | DSTREG ECX <<>>? 0 ROL/ROR/SHL/SHR/SAR r,CL +100 E N STU WX Z012 | SIGMA DSTREG >>< DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +102 ABCDE R TUVWX Z | DSTREG ECX <<>>? 0 SHxD rv,rv,CL +103 E STU WX Z012 | SRCREG DSTREG >>< DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +105 CDEF R TUVWX Z | DSTREG 1 <<>>? 0 rot r,1 +106 E N STU WX Z012 | SIGMA DSTREG >>< DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +108 EFG K MN TU W Y 5 7 &| IMM -> COUNT5 BITS_V PASS2 RD 1 RCL/RCR m,ib +109 CDEF N STUV YZ | SIGMA 1 ADD +10A ABC E GHI K N S U X Z 34 | SIGMA -> TMPB RCLRCR_M_COMM JMP DLY +10B AB D GHI LMN P RSTUV Z | COUNTR -> TMPC TMPB SUB +------------------------------------------|---------------------------------------------------------------------------------------------- +10C EFG K MNOPQR TU W Y 5 7 &| ECX -> COUNT5 BITS_V PASS2 RD 1 RCL/RCR m,CL +10D CDEF N STUV YZ | SIGMA 1 ADD +10E GHI K N S 34 | SIGMA -> TMPB DLY +10F AB D GHI LMN P RSTUV Z | COUNTR -> TMPC TMPB SUB +110 AB EFGHI L O R TUVWX Z 3 56 8 &| OPR_R -> TMPD TMPC <<>>? UNL CW 0 RCLRCR_M_COMM +111 ABCD GHI MN S U WXY 34 | SIGMA -> TMPE RCLRCR_M_LOOP JG DLY +112 AB E NO STU WX Z | TMPE TMPD >>< OPR_W RNI WR +114 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +115 AB D NO RSTUV Z | TMPC TMPB SUB 0 RCLRCR_M_LOOP +116 AB D GHI LMN STUV Z | SIGMA -> TMPC TMPB SUB +117 EF TUVWX Z | -1 BITS_V <<>>? +118 AB E NO STU WXYZ | TMPE TMPD SHIFT +119 D GHI L NO S U WXY | TMPE -> TMPD RCLRCR_M_LOOP JG +11A AB EFGHI MN STUVWX Z | SIGMA -> TMPE TMPC <<>>? +11B AB E NO STU WX Z | TMPE TMPD >>< OPR_W RNI WR +11D 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +11E GHI LMN 5 7 &| IMM -> TMPC RD 1 ROL/ROR/SHL/SHR/SAR m,ib +11F GH JKLMNO QR T XYZ 34 | EFLAGS -> FLAGSB FLGSBA DLY +120 AB EFGHI K O R TUVWX Z 3 | OPR_R -> TMPB TMPC <<>>? UNL 0 ROSHSA_M_COMM +121 AB D N STU WX Z | SIGMA TMPB >>< OPR_W RNI WR +123 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +124 GHI LMN 5 7 &| IMM -> TMPC RD 1 SHxD mv,rv,ib +125 GH JKLMNO QR T XYZ 34 | EFLAGS -> FLAGSB FLGSBA DLY +126 AB EFGHI K O R TUVWX Z 3 | OPR_R -> TMPB TMPC <<>>? UNL 0 SHxD_M_COMM +127 AB D STU WX Z | SRCREG TMPB >>< OPR_W RNI WR +129 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +12A CDEF TU W Y 5 7 &| 1 PASS2 RD 1 rot m,1 +12B C EFGHI LMN S U X Z | SIGMA -> TMPC ROSHSA_M_COMM JMP +12C GH JKLMNO QR T XYZ 34 | EFLAGS -> FLAGSB FLGSBA DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +12D CD FGHI LMNOPQR U X Z 5 7 &| ECX -> TMPC ROSHSA_M_COMM JMP RD 1 ROL/ROR/SHL/SHR/SAR m,CL +12E GH JKLMNO QR T XYZ 34 | EFLAGS -> FLAGSB FLGSBA DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +12F C FGHI LMNOPQR U X Z 5 7 &| ECX -> TMPC SHxD_M_COMM JMP RD 1 SHxD mv,rv,CL +130 GH JKLMNO QR T XYZ 34 | EFLAGS -> FLAGSB FLGSBA DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +131 F XYZ | SRCREG LDBSRM 0 BT rv,rv +132 E R TU WXY 012 | DSTREG DSTREG BITTST RNI +133 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +134 STUV X | SRCREG SIGN 1 BT m,rv +135 BC E X Z | 3 LDBSRU +136 F N STU WXYZ | SIGMA SRCREG SHIFT +137 D F N STUV XYZ | SIGMA NEGWSZ AND +138 GHI K N S | SIGMA -> TMPB +139 AB D 345 | TMPB DLY IN+= +13A 5 7 &| RD +13B 34 | DLY +13C FGHI K O R XYZ 3 | OPR_R -> TMPB SRCREG LDBSRM UNL +13D AB D NO Q TU WXY 012 | TMPB TMPB BITTST RNI +13E =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +13F AB DE XYZ | IMM LDBSRM 0 BT rv,ib +140 E R TU WXY 012 | DSTREG DSTREG BITTST RNI +141 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +142 5 7 &| RD 1 BT m,ib +143 34 | DLY +144 AB DE GHI K O R XYZ 3 | OPR_R -> TMPB IMM LDBSRM UNL +145 AB D NO Q TU WXY 012 | TMPB TMPB BITTST RNI +146 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +147 F XYZ | SRCREG LDBSRM 0 BTS/BTR/BTC rv,rv +148 E R TU WXY | DSTREG DSTREG BITTST +149 CDEF N STUVW Y | SIGMA 1 SERECO +14A FGHI K N S XY | SIGMA -> TMPB SRCREG LDBSLM +14B AB D NO Q TU WXYZ012 | TMPB TMPB SHIFT RNI +14C G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +14D STUV X | SRCREG SIGN 9 BTS/BTR/BTC m,rv +14E BC E X Z | 3 LDBSRU +14F F N STU WXYZ | SIGMA SRCREG SHIFT +150 D F N STUV XYZ | SIGMA NEGWSZ AND +151 CDEFGHI K N STU W Y | SIGMA -> TMPB 1 PASS2 +152 AB D 345 | TMPB DLY IN+= +153 F XY 5 7 &| SRCREG LDBSLM RD +154 CDEF N STU WXYZ | SIGMA 1 SHIFT +155 FGHI K N S XYZ 34 | SIGMA -> TMPB SRCREG LDBSRM DLY +156 AB D GHI LM O R TUVW Y 3 | OPR_R -> TMPC TMPB SERECO UNL +157 G I L N S 5 78 &| SIGMA -> OPR_W WR +158 AB EF NO RSTU WXY 01234 | TMPC TMPC BITTST RNI DLY +159 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +15A AB DE XYZ | IMM LDBSRM 0 BTS/BTR/BTC rv,ib +15B E R TU WXY | DSTREG DSTREG BITTST +15C CDEF N STUVW Y | SIGMA 1 SERECO +15D AB DE GHI K N S XY | SIGMA -> TMPB IMM LDBSLM +15E AB D NO Q TU WXYZ012 | TMPB TMPB SHIFT RNI +15F G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +160 CDEF TU W Y 5 7 &| 1 PASS2 RD 9 BTS/BTR/BTC m,ib +161 AB DE XY | IMM LDBSLM +162 CDEF N STU WXYZ | SIGMA 1 SHIFT +163 AB DE GHI K N S XYZ 34 | SIGMA -> TMPB IMM LDBSRM DLY +164 AB D GHI LM O R TUVW Y 3 | OPR_R -> TMPC TMPB SERECO UNL +165 G I L N S 5 78 &| SIGMA -> OPR_W WR +166 AB EF NO RSTU WXY 01234 | TMPC TMPC BITTST RNI DLY +167 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +168 EFGHI K R T Z | DSTREG -> TMPB BITS_V LDCNTR 0 BSF rv,rv +169 AB D QRSTUV | 0 TMPB CMP 0 BSF_COMMON +16A GHI MN P RS X Z | COUNTR -> TMPE 0 LDBSRU +16B ABC E U Y | BSF_DONE JNC +16C AB D QRSTU WXY 01 | 0 TMPB BITTST RNi +16D CDEF X Z | 1 LDBSRU +16E ABCD U Y | BSF_LOOP JNC +16F AB D QRSTU WXY | 0 TMPB BITTST +170 G M QRST V XYZ012 | 0 -> SRCREG CLZF RNI +171 =====================================| 0 BSF_DONE +172 T | DECNTR 0 BSF_LOOP +173 FGHI K N S U Y | SIGMA -> TMPB BSF_LOOP JNC +174 AB D GHI LMN P RSTU WXY | COUNTR -> TMPC TMPB BITTST +175 AB EF NO STUV 012 | TMPE TMPC CMP RNI +176 G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +177 5 7 &| RD 1 BSF rv,mv +178 CDEF U X Z 34 | BSF_COMMON JMP DLY +179 EFGHI K O R T Z 3 | OPR_R -> TMPB BITS_V LDCNTR UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +17A EFGHI K R T Z | DSTREG -> TMPB BITS_V LDCNTR 0 BSR rv,rv +17B AB D QRSTUV | 0 TMPB CMP 0 BSR_COMMON +17C CDEF X | 1 LDBSLU +17D ABC E U Y | BSR_DONE JNC +17E QRSTUV 01 | 0 0 CMP RNi +17F AB D G MNO RSTU WX Z | TMPC -> SRCREG TMPB >>< TMPC BSR_LOOP JNC +181 GHI K N ST | SIGMA -> TMPB DECNTR +182 T V XYZ012 | CLZF RNI +183 =====================================| 0 BSR_DONE +184 5 7 &| RD 1 BSR rv,mv +185 C E U X Z 34 | BSR_COMMON JMP DLY +186 EFGHI K O R T Z 3 | OPR_R -> TMPB BITS_V LDCNTR UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +187 T VW YZ | BITS8 0 AAA/AAS +188 NOPQRSTU W YZ | EAX PASS +189 N STU W Z012 | SIGMA AAAAAS RNI +18A HIJKLMN S | SIGMA -> AX +------------------------------------------|---------------------------------------------------------------------------------------------- +18B T VW YZ | BITS8 0 DAA/DAS +18C NOPQRSTU W YZ | EAX PASS +18D N STU W 012 | SIGMA DAADAS RNI +18E H JKLMN S | SIGMA -> AL +------------------------------------------|---------------------------------------------------------------------------------------------- +18F T VW YZ | BITS8 0 AAM ib +190 B EFGH J LM O QRST Z | eAX_AL -> MDTMP4 7 LDCNTR +191 QRSTU W YZ | 0 PASS +192 GHI K N | IMM -> TMPB +193 AB D N STU 234 | SIGMA TMPB DIV7 RPT DLY +194 AB D N STU Y | SIGMA TMPB DIV5 +195 N STU W YZ | SIGMA PASS +196 H J LMN R | MDTMP -> AH +197 N STUV Y 012 | SIGMA 0 ADC RNI +198 H JKLMN S | SIGMA -> AL +------------------------------------------|---------------------------------------------------------------------------------------------- +199 T VW YZ | BITS8 0 AAD ib +19A B EFGH L N T Z | IMM -> MDTMP 7 LDCNTR +19B GHI K O Q STU W Y | eDX_AH -> TMPB 0 PASS2 +19C AB D N STU X 234 | SIGMA TMPB IMUL3 RPT DLY +19D N STU W YZ | SIGMA PASS +19E GHI L N P RS | COUNTR -> TMPD +19F AB E GHI LMN R XYZ | MDTMP -> TMPC TMPD LDBSRM +1A0 AB EFGHI L N STU WXYZ | SIGMA -> TMPD TMPC SHIFT +1A1 GHI K N S | SIGMA -> TMPB +1A2 AB D O QRSTUV Y | eAX_AL TMPB ADC +1A3 H J LM QRS 012 | 0 -> AH RNI +1A4 H JKLMN S | SIGMA -> AL +------------------------------------------|---------------------------------------------------------------------------------------------- +1A5 EFGH L R T Z | DSTREG -> MDTMP BITS_V LDCNTR 0 MUL/IMUL r +1A6 GHI K O QRSTU W Y | eAX_AL -> TMPB 0 PASS2 +1A7 AB D N STU X 234 | SIGMA TMPB IMUL3 RPT DLY 0 iMUL_COMMON +1A8 N STU W YZ | SIGMA PASS +1A9 GHI L N P RS | COUNTR -> TMPD +1AA AB E GHI LMN R XYZ | MDTMP -> TMPC TMPD LDBSRM +1AB AB EFGHI L N STU WXYZ | SIGMA -> TMPD TMPC SHIFT +1AC AB E G I KLMN STUVW | SIGMA -> eAX_AL TMPD SZ_EX2 +1AD AB E N STU WXYZ012 | SIGMA TMPD SHIFT RNI +1AE G I K MN S | SIGMA -> eDX_AH +------------------------------------------|---------------------------------------------------------------------------------------------- +1AF EFGHI K O QRST Z 5 7 &| eAX_AL -> TMPB BITS_V LDCNTR RD 1 MUL/IMUL m +1B0 34 | DLY +1B1 C E GH L O R U X Z 3 | OPR_R -> MDTMP iMUL_COMMON JMP UNL +1B2 TU W Y | 0 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +1B3 EFGH L R T Z | DSTREG -> MDTMP BITS_V LDCNTR 0 IMUL rv,rv +1B4 GHI K STU W Y | SRCREG -> TMPB 0 PASS2 +1B5 AB D N STU YZ 234 | SIGMA TMPB IMUL4 RPT DLY 0 IMUL2_COMMON +1B6 N STU W YZ | SIGMA PASS +1B7 GHI L N P RS | COUNTR -> TMPD +1B8 AB E GHI LMN R XYZ | MDTMP -> TMPC TMPD LDBSRM +1B9 AB EFGHI L N STU WXYZ | SIGMA -> TMPD TMPC SHIFT +1BA AB E G MN STUVW YZ | SIGMA -> SRCREG TMPD IMCS +1BB AB E N STU WXYZ012 | SIGMA TMPD SHIFT RNI +1BC =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +1BD EF T Z 5 7 &| BITS_V LDCNTR RD 1 IMUL rv,mv +1BE GHI K S 34 | SRCREG -> TMPB DLY +1BF C E GH L O R U X Z 3 | OPR_R -> MDTMP IMUL2_COMMON JMP UNL +1C0 TU W Y | 0 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +1C1 EFGH L N T Z 5 7 &| IMM -> MDTMP BITS_V LDCNTR RD 1 IMUL rv,mv,i +1C2 CD F U X Z 34 | IMUL2_COMMON JMP DLY +1C3 GHI K O R TU W Y 3 | OPR_R -> TMPB 0 PASS2 UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +1C4 EFGH L N T Z | IMM -> MDTMP BITS_V LDCNTR 0 IMUL rv,rv,i +1C5 B U X Z | IMUL2_COMMON JMP +1C6 GHI K R TU W Y | DSTREG -> TMPB 0 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +1C7 EFGH J LM O QRST Z | eAX_AL -> MDTMP4 BITS_V LDCNTR 0 DIV r +1C8 O Q STU W YZ | eDX_AH PASS +1C9 GHI K R | DSTREG -> TMPB +1CA AB D N STU 234 | SIGMA TMPB DIV7 RPT DLY 0 DIV_COMMON +1CB AB D N STU Y | SIGMA TMPB DIV5 +1CC N STU W YZ | SIGMA PASS +1CD G I KLMN R 012 | MDTMP -> eAX_AL RNI +1CE G I K MN S | SIGMA -> eDX_AH +------------------------------------------|---------------------------------------------------------------------------------------------- +1CF EFGH J LM O QRST Z 5 7 &| eAX_AL -> MDTMP4 BITS_V LDCNTR RD 1 DIV m +1D0 O Q STU W YZ | eDX_AH PASS +1D1 DEF U X Z 34 | DIV_COMMON JMP DLY +1D2 GHI K O R 3 | OPR_R -> TMPB UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +1D3 EF TUV YZ | -1 BITS_V ADD 0 IDIV r +1D4 G JK MN S | SIGMA -> COUNTR +1D5 O Q STU W YZ | eDX_AH PASS +1D6 GH J LM O QRS | eAX_AL -> MDTMP4 +1D7 GHI K R | DSTREG -> TMPB +1D8 AB D N STU XYZ | SIGMA TMPB PREDIV 0 IDIV_COMMON +1D9 AB D N STU 234 | SIGMA TMPB DIV7 RPT DLY +1DA AB D N STU Y | SIGMA TMPB DIV5 +1DB AB D N STU XY | SIGMA TMPB IDIV1 +1DC N STU W YZ | SIGMA PASS +1DD GHI K N S | SIGMA -> TMPB +1DE N R TU X Z | MDTMP IDIV2 +1DF G I K MNO Q 012 | TMPB -> eDX_AH RNI +1E0 G I KLMN S | SIGMA -> eAX_AL +------------------------------------------|---------------------------------------------------------------------------------------------- +1E1 EF TUV YZ 5 7 &| -1 BITS_V ADD RD 1 IDIV m +1E2 G JK MN S | SIGMA -> COUNTR +1E3 O Q STU W YZ | eDX_AH PASS +1E4 CD GH J LM O QRS U X Z 34 | eAX_AL -> MDTMP4 IDIV_COMMON JMP DLY +1E5 GHI K O R 3 | OPR_R -> TMPB UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +1E6 O QRSTUV X 012 | eAX_AL SIGN RNI 0 CWD / CDQ +1E7 G I K MN S | SIGMA -> eDX_AH +------------------------------------------|---------------------------------------------------------------------------------------------- +1E8 R TUVW Z | DSTREG SZ_EXT 0 CBW / CWDE MOVZX/MOVSX r,r (16-bit?) +1E9 T VW Y 012 | BITS16 RNI +1EA G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +1EB 5 7 &| RD 1 MOVZX/MOVSX r,m (16-bit?) +1EC 34 | DLY +1ED O R TUVW Z 3 | OPR_R SZ_EXT UNL +1EE T VW Y 012 | BITS16 RNI +1EF G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +1F0 R TUVW Z | DSTREG SZ_EXT 0 CBW / CWDE MOVZX/MOVSX r,r (32-bit?) +1F1 T VW 012 | BITS32 RNI +1F2 G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +1F3 5 7 &| RD 1 MOVZX/MOVSX r,m (32-bit?) +1F4 34 | DLY +1F5 O R TUVW Z 3 | OPR_R SZ_EXT UNL +1F6 T VW 012 | BITS32 RNI +1F7 G MN S | SIGMA -> SRCREG +------------------------------------------|---------------------------------------------------------------------------------------------- +1F8 G JK M PQR | eCX -> COUNTR 0 REP MOVS +1F9 T XY | SREPF +1FA ABCD F UVW Y | REP_MOVS_NOT0 JCNTNZ +1FB D H L NOP STUV YZ01234 67 9 | ESI DES_OS INCREM ADD RNI DLY IND= +1FC =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +1FD GHI K N ST 5 7 &| SIGMA -> TMPB DECNTR RD 0 REP_MOVS_NOT0 +1FE D IJKLMNOP TUV YZ 34 67 9 | EDI DES_ES INCREM ADD DLY IND= +1FF ABC E GHI LMN S UVW YZ 5 8 &| SIGMA -> TMPC REP_MOVS_DONE JCNTZ wr +200 D H L NO Q TUV YZ 34 67 9 | TMPB DES_OS INCREM ADD DLY IND= +201 GHI K N ST 5 7 &| SIGMA -> TMPB DECNTR RD 0 REP_MOVS_LOOP +202 D IJKLMNO RSTUV YZ 34 67 9 | TMPC DES_ES INCREM ADD DLY IND= +203 E GHI LMN S UVW 3 5 8 &| SIGMA -> TMPC REP_MOVS_LOOP JCNZNI UNL wr +204 D H L NO Q TUV YZ 34 67 9 | TMPB DES_OS INCREM ADD DLY IND= +205 ABCDE G JKL N P RS UVW Y | COUNTR -> eCX REP_MOVS_RPTI JCNTNZ 0 REP_MOVS_DONE +206 AB D G J NO RSTU W Y 0123 | TMPC -> eDI TMPB PASS2 RNI UNL +207 G J MN S | SIGMA -> eSI 0 REP_MOVS_RPTI +208 C F H KLMN P STU W Y 34 67 9 | TMPeIP DESCSW 0xffff PASS2 DLY IND= 0 RPTI +209 CDEF N STUV YZ | SIGMA 1 ADD +20A GHI K N S | SIGMA -> TMPB +20B AB D NO QR TUV XY | EFLAGS TMPB OR +20C GHI KL N S | SIGMA -> EFLAGS +20D GHI KLMN P S 5 9&| TMPeIP -> EIP PREF +20E 34 | DLY +20F 012 | RNI +210 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +211 D H L NOP STUV YZ 34 67 9 | ESI DES_OS INCREM ADD DLY IND= 0 MOVS +212 GHI K N S 5 7 &| SIGMA -> TMPB RD +213 D IJKLMNOP TUV YZ 34 67 9 | EDI DES_ES INCREM ADD DLY IND= +214 5 8 &| wr +215 34 | DLY +216 G J MNO Q 0123 | TMPB -> eSI RNI UNL +217 G J N S | SIGMA -> eDI +------------------------------------------|---------------------------------------------------------------------------------------------- +218 G JK M PQR | eCX -> COUNTR 0 REP CMPS +219 =====================================| +21A ABC E UVW Y | REP_CMPS_NOT0 JCNTNZ +21B D IJKLMNOP TUV YZ01234 67 9 | EDI DES_ES INCREM ADD RNI DLY IND= +21C =====================================| 0 REP_CMPS_DONE +21D G J MNO R T | TMPD -> eSI DECNTR 0 REP_CMPS_LOOP +21E E G JKL N P RS UVWX | COUNTR -> eCX REP_CMPS_DONE LOOPnE +21F D G J NO Q TUV YZ01 34 | TMPB -> eDI INCREM ADD RNi DLY +220 GHI K N S 5 7 &| SIGMA -> TMPB RD 0 REP_CMPS_NOT0 +221 D H L NOP STUV YZ 34 67 9 | ESI DES_OS INCREM ADD DLY IND= +222 GHI L N S 5 7 &| SIGMA -> TMPD RD +223 GHI LM O R 3 | OPR_R -> TMPC UNL +224 DEF IJKLMNO Q U 34 67 9 | TMPB DES_ES REP_CMPS_LOOP JNOINT DLY IND= +225 AB EF O R TUV 3 | OPR_R TMPC CMP UNL +226 G J MNO R T | TMPD -> eSI DECNTR +227 C EFG JKL N P RS UVWX | COUNTR -> eCX REP_CMPS_DONE LOOPnE +228 D G J NO Q TUV YZ01 345 | TMPB -> eDI INCREM ADD RNi DLY IN+= +229 AB DEF NO QRS WXY | RPTI LJUMP +22A =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +22B D IJKLMNOP TUV YZ 34 67 9 | EDI DES_ES INCREM ADD DLY IND= 0 CMPS +22C GHI K N S 5 7 &| SIGMA -> TMPB RD +22D D H L NOP STUV YZ 34 67 9 | ESI DES_OS INCREM ADD DLY IND= +22E 5 7 &| RD +22F GHI LM O R 3 | OPR_R -> TMPC UNL +230 34 | DLY +231 G J NO Q | TMPB -> eDI +232 G J MN S | SIGMA -> eSI +233 AB EF O R TUV 0123 | OPR_R TMPC CMP RNI UNL +234 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +235 G JK M PQR | eCX -> COUNTR 0 REP SCAS +236 =====================================| +237 ABC E UVW Y | REP_SCAS_NOT0 JCNTNZ +238 D IJKLMNOP TUV YZ01234 67 9 | EDI DES_ES INCREM ADD RNI DLY IND= +239 =====================================| 0 REP_SCAS_DONE +23A T | DECNTR 0 REP_SCAS_LOOP +23B E G JKL N P RS UVWX | COUNTR -> eCX REP_SCAS_DONE LOOPnE +23C D IJKLMNOP TUV YZ01 34 67 9 | EDI DES_ES INCREM ADD RNi DLY IND= +23D 5 7 &| RD 0 REP_SCAS_NOT0 +23E 34 | DLY +23F G J N S | SIGMA -> eDI +240 DE GHI LM O R U 3 | OPR_R -> TMPC REP_SCAS_LOOP JNOINT UNL +241 AB EF O QRSTUV | eAX_AL TMPC CMP +242 T | DECNTR +243 C E G JKL N P RS UVWX | COUNTR -> eCX REP_SCAS_DONE LOOPnE +244 01 | RNi +245 AB DEF NO QRS WXY | RPTI LJUMP +246 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +247 D IJKLMNOP TUV YZ 34 67 9 | EDI DES_ES INCREM ADD DLY IND= 0 SCAS +248 5 7 &| RD +249 34 | DLY +24A G J N S | SIGMA -> eDI +24B GHI K O R 3 | OPR_R -> TMPB UNL +24C AB D O QRSTUV 012 | eAX_AL TMPB CMP RNI +24D =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +24E ABCDE G JK M PQR U X Z | eCX -> COUNTR REP_LODS_LOOP JMP 0 REP LODS +24F =====================================| 0 REP_LODS_DONE +250 FG JKL N P RS UVW YZ | COUNTR -> eCX REP_LODS_DONE JCNTZ 0 REP_LODS_LOOP +251 D H L NOP STUV YZ01 34 67 9 | ESI DES_OS INCREM ADD RNi DLY IND= +252 T 5 7 &| DECNTR RD +253 34 | DLY +254 D G J MN S U | SIGMA -> eSI REP_LODS_LOOP JNOINT +255 G I KLM O R 3 | OPR_R -> eAX_AL UNL +256 DEFG JKL N P RS UVW YZ | COUNTR -> eCX REP_LODS_DONE JCNTZ +257 D H L NOP STUV YZ01 34 67 9 | ESI DES_OS INCREM ADD RNi DLY IND= +258 AB DEF NO QRS WXY | RPTI LJUMP +259 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +25A D H L NOP STUV YZ 34 67 9 | ESI DES_OS INCREM ADD DLY IND= 0 LODS +25B 5 7 &| RD +25C 34 | DLY +25D G J MN S 012 | SIGMA -> eSI RNI +25E G I KLM O R 3 | OPR_R -> eAX_AL UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +25F ABCD H L O QRS 34 67 &| eAX_AL DES_OS EBX DLY IN=+ 0 XLATB +260 5 7 &| RD +261 01234 | RNI DLY +262 G I KLM O R 3 | OPR_R -> eAX_AL UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +263 ABCDE G JK M PQR U X Z | eCX -> COUNTR REP_STOS_LOOP JMP 0 REP STOS +264 =====================================| 0 REP_STOS_DONE +265 FG JKL N P RS UVW YZ | COUNTR -> eCX REP_STOS_DONE JCNTZ 0 REP_STOS_LOOP +266 D IJKLMNOP TUV YZ01 34 67 9 | EDI DES_ES INCREM ADD RNi DLY IND= +267 G I L NOPQRST 5 78 &| EAX -> OPR_W DECNTR WR +268 EF U 34 | REP_STOS_LOOP JNOINT DLY +269 G J N S | SIGMA -> eDI +26A DE G JKL N P RS UVW YZ | COUNTR -> eCX REP_STOS_DONE JCNTZ +26B D IJKLMNOP TUV YZ01 34 67 9 | EDI DES_ES INCREM ADD RNi DLY IND= +26C AB DEF NO QRS WXY | RPTI LJUMP +26D =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +26E D IJKLMNOP TUV YZ 34 67 9 | EDI DES_ES INCREM ADD DLY IND= 0 STOS +26F G I L O QRS 5 78 &| eAX_AL -> OPR_W WR +270 01234 | RNI DLY +271 G J N S | SIGMA -> eDI +------------------------------------------|---------------------------------------------------------------------------------------------- +272 ABCD UV X | IN_IMM_NOCHK JIO_OK 0 p IN A,ib +273 I K N TU W YZ 34 67 9 | IMM DES_IO PASS DLY IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +274 ABCDE NO Q WXYZ | PORTIO_PROTCHK LCALL 0 r IN A,ib +275 I K N TU W YZ 34 67 9 | IMM DES_IO PASS DLY IND= +276 5 7 &| RD 0 IN_IMM_NOCHK +277 01234 | RNI DLY +278 G I KLM O R 3 | OPR_R -> eAX_AL UNL 0 IN_DONE +279 ABCD F UV X | IN_DX_NOCHK JIO_OK 0 p IN A,DX +27A C F NOPQ STUV XYZ | EDX 0xffff AND 0 r IN A,DX +27B ABCDE NO Q WXYZ | PORTIO_PROTCHK LCALL +27C I K N S 34 67 9 | SIGMA DES_IO DLY IND= 0 IN_DX_NOCHK +27D D F U X Z 5 7 &| IN_DONE JMP RD +27E 01 34 | RNi DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +27F ABC EF UV X | INS_NOCHK JIO_OK 0 p INS +280 IJKLMNOP 34 67 9 | EDI DES_ES DLY IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +281 ABCDE NO Q WXYZ | PORTIO_PROTCHK LCALL 0 r INS +282 C F NOPQ STUV XYZ | EDX 0xffff AND +283 IJKLMNOP 34 67 9 | EDI DES_ES DLY IND= +284 C F NOPQ STUV XYZ 56 8 &| EDX 0xffff AND CW 0 INS_NOCHK +285 I K N S 34 67 9 | SIGMA DES_IO DLY IND= +286 5 7 &| RD +287 D IJKLMNOP TUV YZ 34 67 9 | EDI DES_ES INCREM ADD DLY IND= +288 0123 5 8 &| RNI UNL wr +289 G J N S 34 | SIGMA -> eDI DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +28A ABCD F UV X | REP_INS_NOCHK JIO_OK 0 p REP INS +28B G JK M PQR | eCX -> COUNTR 0 r REP INS +28C ABCDE NO Q WXYZ | PORTIO_PROTCHK LCALL +28D C F NOPQ STUV XYZ | EDX 0xffff AND 0 REP_INS_NOCHK +28E ABC EFGHI LMN S UVW Y | SIGMA -> TMPC REP_INS_NOT0 JCNTNZ +28F D IJKLMNOP TUV YZ01234 67 9 | EDI DES_ES INCREM ADD RNI DLY IND= +290 G JKL N P RS | COUNTR -> eCX 0 REP_INS_DONE +291 FG J N S UVW YZ 3 5 8 &| SIGMA -> eDI REP_INS_DONE JCNTZ UNL wr 0 REP_INS_LOOP +292 D IJKLMNOP TUV YZ01 34 67 9 | EDI DES_ES INCREM ADD RNi DLY IND= +293 G JKL N P RST 56 8 &| COUNTR -> eCX DECNTR CW 0 REP_INS_NOT0 +294 I K NO RS 34 67 9 | TMPC DES_IO DLY IND= +295 D U 5 7 &| REP_INS_LOOP JNOINT RD +296 IJKLMNOP 34 67 9 | EDI DES_ES DLY IND= +297 DEFG J N S UVW YZ 3 5 8 &| SIGMA -> eDI REP_INS_DONE JCNTZ UNL wr +298 D IJKLMNOP TUV YZ01 34 67 9 | EDI DES_ES INCREM ADD RNi DLY IND= +299 AB DEF NO QRS WXY | RPTI LJUMP +29A G JKL N P RS | COUNTR -> eCX +------------------------------------------|---------------------------------------------------------------------------------------------- +29B ABCD UV X | OUT_IMM_NOCHK JIO_OK 0 p OUT ib,A +29C I K N TU W YZ 34 67 9 | IMM DES_IO PASS DLY IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +29D ABCDE NO Q WXYZ | PORTIO_PROTCHK LCALL 0 r OUT ib,A +29E I K N TU W YZ 34 67 9 | IMM DES_IO PASS DLY IND= +29F G I L O QRS 012 5 78 &| eAX_AL -> OPR_W RNI WR 0 OUT_IMM_NOCHK +2A0 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +2A1 ABCD F UV X | OUT_DX_NOCHK JIO_OK 0 p OUT DX,A +2A2 C F NOPQ STUV XYZ | EDX 0xffff AND 0 r OUT DX,A +2A3 ABCDE NO Q WXYZ | PORTIO_PROTCHK LCALL +2A4 I K N S 34 67 9 | SIGMA DES_IO DLY IND= 0 OUT_DX_NOCHK +2A5 G I L O QRS 012 5 78 &| eAX_AL -> OPR_W RNI WR +2A6 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +2A7 ABC EF UV X | OUTS_NOCHK JIO_OK 0 p OUTS +2A8 D H L NOP STUV YZ 34 67 9 | ESI DES_OS INCREM ADD DLY IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +2A9 ABCDE NO Q WXYZ | PORTIO_PROTCHK LCALL 0 r OUTS +2AA C F NOPQ STUV XYZ | EDX 0xffff AND +2AB D H L NOP STUV YZ 34 67 9 | ESI DES_OS INCREM ADD DLY IND= +2AC GHI K N S 5 7 &| SIGMA -> TMPB RD 0 OUTS_NOCHK +2AD C F NOPQ STUV XYZ | EDX 0xffff AND +2AE I K N S 34 67 9 | SIGMA DES_IO DLY IND= +2AF G J MNO Q 0123 5 8 &| TMPB -> eSI RNI UNL wr +2B0 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +2B1 ABCD F UV X | REP_OUTS_NOCHK JIO_OK 0 p REP OUTS +2B2 G JK M PQR | eCX -> COUNTR 0 r REP OUTS +2B3 ABCDE NO Q WXYZ | PORTIO_PROTCHK LCALL +2B4 C F NOPQ STUV XYZ | EDX 0xffff AND 0 REP_OUTS_NOCHK +2B5 ABC EFGHI LMN S UVW Y | SIGMA -> TMPC REP_OUTS_NOT0 JCNTNZ +2B6 D H L NOP STUV YZ01234 67 9 | ESI DES_OS INCREM ADD RNI DLY IND= +2B7 =====================================| 0 REP_OUTS_DONE +2B8 F H L NO Q UVW YZ 34 67 9 | TMPB DES_OS REP_OUTS_DONE JCNTZ DLY IND= 0 REP_OUTS_LOOP +2B9 D G J MNO Q TUV YZ01 3 | TMPB -> eSI INCREM ADD RNi UNL +2BA GHI K N ST 5 7 &| SIGMA -> TMPB DECNTR RD 0 REP_OUTS_NOT0 +2BB EF I K NO RS U 34 67 9 | TMPC DES_IO REP_OUTS_LOOP JNOINT DLY IND= +2BC G JKL N P RS 5 8 &| COUNTR -> eCX wr +2BD DE H L NO Q UVW YZ 34 67 9 | TMPB DES_OS REP_OUTS_DONE JCNTZ DLY IND= +2BE D G J MNO Q TUV YZ01 3 | TMPB -> eSI INCREM ADD RNi UNL +2BF AB DEF NO QRS WXY | RPTI LJUMP +2C0 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +2C1 ABC EF NO Q WX Z | IO_PERM_BITMAP LJMPNP 0 PORTIO_PROTCHK +2C2 D FGHI K N STU W Y | SIGMA -> TMPB NEGWSZ PASS2 +2C3 A CDEF U X Z | PORTIO_ALLOWED JMP +2C4 D F N STUV YZ | SIGMA NEGWSZ ADD 0 IO_PERM_BITMAP +2C5 BC FGHI L N STU W Y | SIGMA -> TMPD 6 PASS2 +2C6 B DEF I KL N ST VW 34 67 &| SIGMA DES_TR 0x60 BITS32 DLY IN=+ +2C7 BC E GH JK QRS X Z 5 7 9 | 0 -> SLCTR2 3 LDBSRU RD W +2C8 AB D GH J L QRSTU WXYZ | 0 -> PROTUN TMPB SHIFT +2C9 B D GHI LMN S V X 34 | SIGMA -> TMPC READ_RPL PTGEN DLY +2CA C F O R TUV XYZ 3 | OPR_R 0xffff AND UNL +2CB AB EF I KL N S 34 67 &| SIGMA DES_TR TMPC DLY IN=+ +2CC B EF NO Q TUV XYZ 5 7 9 | TMPB 7 AND RD W +2CD ABC E GHI LMN S UVWXYZ | SIGMA -> TMPC PORTIO_16BIT J16BIT +2CE AB E TUV X Z | -1 TMPD XOR +2CF AB EFGHI L N S X | SIGMA -> TMPD TMPC LDBSLU +2D0 AB E QRSTU WXYZ | 0 TMPD SHIFT +2D1 GHI L N ST V X Z 34 | SIGMA -> TMPD BITSDE DLY +2D2 AB E O R TUV XYZ 3 | OPR_R TMPD AND UNL +2D3 ABC EFGH J L N S V X Z | SIGMA -> PROTUN TST_PORTIO_BIT PTSELA 0 PORTIO_16BIT +2D4 YZ | RETURN 0 PORTIO_ALLOWED +2D5 I K NO Q TU W YZ 34 67 9 | TMPB DES_IO PASS DLY IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +2D6 BCDEF N P W YZ | CALL_FAR_PM LJMPP 2 CALL cp +2D7 AB DEFGH JK MN T Z | IMM -> TMPG IMM8 LDCNTR +2D8 AB DE G I L OPQR U X Z 5 78 &| CS -> OPR_W CALL_FAR_RM JMP WR +2D9 D F 345 | NEGWSZ DLY IN+= +------------------------------------------|---------------------------------------------------------------------------------------------- +2DA 5 7 &| RD 1 CALL mp +2DB DE 345 | WORDSZ DLY IN+= +2DC GH JK M O R 3 5 7 9 | OPR_R -> TMPG UNL RD W +2DD BCDEF N P W YZ 34 | CALL_FAR_PM LJMPP DLY +2DE G JK M O R 3 | OPR_R -> COUNTR UNL +2DF D F H K MNOP RSTUV YZ 34 67 &| ESP DESSTK NEGWSZ ADD DLY IN=+ +2E0 G I L OPQR 5 78 &| CS -> OPR_W WR +2E1 D F 345 | NEGWSZ DLY IN+= +2E2 D F N STUV YZ | SIGMA NEGWSZ ADD 0 CALL_FAR_RM +2E3 ABC G I L NO QRS U X Z 5 78 &| EIP -> OPR_W JMP_FAR_RM JMP WR +2E4 H LMN S 34 | SIGMA -> eSP DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +2E5 B EF N P S W YZ | JUMP_FAR_PM LJMPP 0 JMP cp +2E6 AB DEFGH JK MN T Z | IMM -> TMPG IMM8 LDCNTR +2E7 IJKL 34 7 9 | DES_CS DLY LAR +2E8 BC O STUV XYZ | IRF2 0xffff0000 AND +2E9 BCD N STUV XY | SIGMA 0x8200 OR +2EA IJKL N S 34 789 | SIGMA DES_CS DLY SAR +2EB IJKL 34 7 | DES_CS DLY LLIM 0 JMP_FAR_RM +2EC GHI K O S | IRF2 -> TMPB +2ED IJKL N P RSTU W YZ 6 9&| COUNTR DES_CS PASS SBRM 0 JMP_FAR_RM_1 +2EE IJKL NO Q 78 | TMPB DES_CS SLIM +2EF L 789&| PAGER5 SPCR +2F0 H KL N PQ S 34 67 9 | TMPG DESCOD DLY IND= 0 JMP_FAR_COMMON +2F1 H N PQ S 5 9&| TMPG -> eIP PREF 0 JMP_FAR_DONE +2F2 GH J L QRS 34 | 0 -> PROTUN DLY +2F3 G IJKL N S 012 | SIGMA -> CS RNI +2F4 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +2F5 5 7 &| RD 1 JMP mp +2F6 DE 345 | WORDSZ DLY IN+= +2F7 GH JK M O R 3 5 7 9 | OPR_R -> TMPG UNL RD W +2F8 B EF N P S W YZ 34 | JUMP_FAR_PM LJMPP DLY +2F9 G JK M O R 3 | OPR_R -> COUNTR UNL +2FA CD F IJKL U X Z 34 7 | DES_CS JMP_FAR_RM_1 JMP DLY LLIM +2FB GHI K O S | IRF2 -> TMPB +------------------------------------------|---------------------------------------------------------------------------------------------- +2FC DE N STUV YZ 5 7 &| SIGMA WORDSZ ADD RD 3 RETF/RETF iw +2FD DE 345 | WORDSZ DLY IN+= +2FE AB DE N STUV YZ 5 7 &| SIGMA IMM ADD RD +2FF GH JK M O R 3 | OPR_R -> TMPG UNL +300 N QR W YZ 34 | RETF_PM LJMPP DLY +301 G JK M O R 3 | OPR_R -> COUNTR UNL +302 B DEF H LMN S U X Z | SIGMA -> eSP JMP_FAR_RM JMP +303 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +304 AB EF NO RS WXYZ | ENTER_COMMON LCALL 2 ENTER (16-bit?) +305 AB DEF H LMN STU W Y | SIGMA -> eSP IMM8 PASS2 +306 NO RSTU W YZ01234 | TMPC PASS RNI DLY +307 HIJ L N S | SIGMA -> BP +------------------------------------------|---------------------------------------------------------------------------------------------- +308 AB EF NO RS WXYZ | ENTER_COMMON LCALL 2 ENTER (32-bit?) +309 AB DEF H LMN STU W Y | SIGMA -> eSP IMM8 PASS2 +30A NO RSTU W YZ01234 | TMPC PASS RNI DLY +30B GHIJ L N S | SIGMA -> EBP +------------------------------------------|---------------------------------------------------------------------------------------------- +30C G K MN S | SIGMA -> COUNT5 0 ENTER_COMMON +30D AB DE GHI LMNOP RSTUV Z | ESP -> TMPC IMM SUB +30E AB FG I L NOP R UVW YZ 5 78 &| EBP -> OPR_W ENTER_DONE JCNTZ WR +30F AB EF UV XYZ 34 | ENTER_LASTW JCNT1 DLY +310 D F N STUV YZ 5 | SIGMA NEGWSZ ADD IN+= +311 D F H K MNOP R TUV YZ 34 67 &| EBP DESSTK NEGWSZ ADD DLY IN=+ +312 GHI K N ST 5 7 &| SIGMA -> TMPB DECNTR RD +313 D F H K MNOP RSTUV YZ 34 67 &| ESP DESSTK NEGWSZ ADD DLY IN=+ +314 ABC E H LMN S UV XYZ 5 8 &| SIGMA -> eSP ENTER_LAST JCNT1 wr +315 D F H K MNO Q TUV YZ 34 67 &| TMPB DESSTK NEGWSZ ADD DLY IN=+ +316 GHI K N ST 5 7 &| SIGMA -> TMPB DECNTR RD 0 ENTER_LOOP +317 D F H K MNOP RSTUV YZ 34 67 &| ESP DESSTK NEGWSZ ADD DLY IN=+ +318 E H LMN S UV XY 3 5 8 &| SIGMA -> eSP ENTER_LOOP JCNTN1 UNL wr +319 D F H K MNO Q TUV YZ 34 67 &| TMPB DESSTK NEGWSZ ADD DLY IN=+ +31A D F H K MNOP RSTUV YZ 3 67 &| ESP DESSTK NEGWSZ ADD UNL IN=+ 0 ENTER_LAST +31B AB DE N STUV Z | SIGMA IMM SUB +31C G I L NO RS 5 78 &| TMPC -> OPR_W WR 0 ENTER_LASTW +31D H K MN S YZ 34 67 9 | SIGMA DESSTK RETURN DLY IND= 0 ENTER_DONE +31E H LMN S 56 8 &| SIGMA -> eSP CW +------------------------------------------|---------------------------------------------------------------------------------------------- +31F DE H K MNOP R TUV YZ 34 67 9 | EBP DESSTK WORDSZ ADD DLY IND= 0 LEAVE (16-bit?) +320 H LMN S 5 7 &| SIGMA -> eSP RD +321 01234 | RNI DLY +322 HIJ L O R 3 | OPR_R -> BP UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +323 DE H K MNOP R TUV YZ 34 67 9 | EBP DESSTK WORDSZ ADD DLY IND= 0 LEAVE (32-bit?) +324 H LMN S 5 7 &| SIGMA -> eSP RD +325 01234 | RNI DLY +326 GHIJ L O R 3 | OPR_R -> EBP UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +327 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 HLT +328 CDE I K M Y 67 9&| DESABS 2 ICESIG IN=2 +329 9&| HLTS 0 HLT_SHUTDOWN +32A 34 | DLY +32B 2 4 | RPT WIO +32C 012 | RNI +32D =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +32E ABC EF I KLM OPQR WX Z 89 | DESIDT NO_PRIVILEGE LJMPNP SPTR 1 LIDT mw +32F EF X | BITS_V LDBSLU +330 ABC E U X Z 5 7 9 | LIDTGDT_COMMON JMP RD W +331 CDE 345 | 2 DLY IN+= +------------------------------------------|---------------------------------------------------------------------------------------------- +332 ABC EF IJ OPQR WX Z 89 | DESGDT NO_PRIVILEGE LJMPNP SPTR 1 LGDT mw +333 EF X | BITS_V LDBSLU +334 5 7 9 | RD W +335 CDE 345 | 2 DLY IN+= +336 BCD F TU WXYZ 5 7 | -1 0x1ff SHIFT RD D 0 LIDTGDT_COMMON +337 GHI K N S | SIGMA -> TMPB +338 C F O R TUV XYZ 3 | OPR_R 0xffff AND UNL +339 HI L N S 34 78 | SIGMA DESPTR DLY SLIM +33A AB D O R TUV XYZ 3 | OPR_R TMPB AND UNL +33B HI L N S 012 78 &| SIGMA DESPTR RNI SBAS +33C =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +33D I KLM 34 7 &| DESIDT DLY LBAS 0 SIDT mw +33E ABC EFGHI LM O S U X Z | IRF2 -> TMPC SIDTGDT_COMMON JMP +33F I KLM 7 | DESIDT LLIM +------------------------------------------|---------------------------------------------------------------------------------------------- +340 IJ 34 7 &| DESGDT DLY LBAS 0 SGDT mw +341 GHI LM O S | IRF2 -> TMPC +342 IJ 7 | DESGDT LLIM +343 GHI K O S | IRF2 -> TMPB 0 SIDTGDT_COMMON +344 H L P S 34 67 &| EA DES_OS 0 DLY IN=+ +345 G I L NO Q 5 789 | TMPB -> OPR_W WR W +346 CDE 345 | 2 DLY IN+= +347 G I L NO RS 012 5 78 | TMPC -> OPR_W RNI WR D +348 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +349 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 1 LMSW mw +34A CDEF NO Q STUV XYZ | CR0 1 AND +34B GHI K N S 5 7 9 | SIGMA -> TMPB RD W +34C ABC EF U X Z 34 | LMSW_COMMON JMP DLY +34D AB D O R TUV XY 3 | OPR_R TMPB OR UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +34E ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 LMSW rw +34F CDEF NO Q STUV XYZ | CR0 1 AND +350 E N STUV XY | SIGMA DSTREG OR +351 B E N STUV XYZ | SIGMA 0x0f AND 0 LMSW_COMMON +352 GHI K N S | SIGMA -> TMPB +353 B E TUV X Z | -1 0x0f XOR +354 GHI LMN S | SIGMA -> TMPC +355 AB EF NO Q STUV XYZ | CR0 TMPC AND +356 AB D N STUV XY 012 | SIGMA TMPB OR RNI +357 GHI K MN S | SIGMA -> CR0 +------------------------------------------|---------------------------------------------------------------------------------------------- +358 G L NO Q S 012 | CR0 -> DSTREG RNI 0 SMSW rw +359 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +35A G I L NO Q S 012 5 789 | CR0 -> OPR_W RNI WR W 1 SMSW mw +35B 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +35C ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 MOV CR0,rd +35D T VW | BITS32 +35E CDEFGHI K S XY | SRCREG -> TMPB 1 LDBSLM +35F AB D NO Q TU WXYZ | TMPB TMPB SHIFT +360 BC E N STUV XYZ | SIGMA 3 AND +361 G JK MN S | SIGMA -> COUNTR +362 =====================================| +363 ABCD F UV XYZ | PAGING_RM JCNT1 +364 NO Q TU W YZ012 | TMPB PASS RNI +365 GHI K MN S | SIGMA -> CR0 +------------------------------------------|---------------------------------------------------------------------------------------------- +366 A E OPQR WXY | #GP/#TS(I0,E0) LJUMP 0 PAGING_RM +367 B GH JK QRS V X | 0 -> SLCTR2 SET_FAULT PTGEN +------------------------------------------|---------------------------------------------------------------------------------------------- +368 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 MOV CR2,rd +369 T VW | BITS32 +36A G I K S 012 | SRCREG -> CR2 RNI +36B =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +36C ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 MOV CR3,rd +36D T VW | BITS32 +36E I K M S 67 9 | SRCREG DESABS IND= +36F K 012 789&| PDBR RNI SPCR +370 K 34 | PDBR DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +371 ABCDE U X Z | STORE_CR JMP 0 MOV rd,CR0 +372 NO Q STU W YZ | CR0 PASS +------------------------------------------|---------------------------------------------------------------------------------------------- +373 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 STORE_CR +374 T VW | BITS32 +375 012 | RNI +376 G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +377 D U X Z | STORE_CR JMP 0 MOV rd,CR2 +378 O Q TU W YZ | CR2 PASS +------------------------------------------|---------------------------------------------------------------------------------------------- +379 DE K U X Z 7 9&| PDBR STORE_CR JMP LPCR 0 MOV rd,CR3 +37A K O STU W YZ 34 | IRF2 PDBR PASS DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +37B A DEF NO S WXYZ | GENERAL_DETECT LCALL 0 MOV DR4/6,rd +37C ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP +37D ABC E GH KLM S U X Z | SRCREG -> DR6 LD_DR4567_DONE JMP +37E =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +37F A DEF NO S WXYZ | GENERAL_DETECT LCALL 0 MOV DR5/7,rd +380 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP +381 GH KL S | SRCREG -> DR7 +382 =====================================| +383 012 | RNI 0 LD_DR4567_DONE +384 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +385 AB DE N TU WXYZ | IMM IMM SHIFT 0 SELECT_DR_TR +386 B EF N STUV XYZ | SIGMA 7 AND +387 BCDEF N STUV XY | SIGMA 0x70 OR +388 G JK MN S YZ | SIGMA -> COUNTR RETURN +389 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +38A A DEF NO S WXYZ | GENERAL_DETECT LCALL 0 MOV DR0-3,rd +38B ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP +38C ABC E NO S WXYZ | SELECT_DR_TR LCALL +38D BC E X Z | 3 LDBSRU +38E G KL S 34 78 &| SRCREG -> IRF DLY SBAS +38F I K M QRS 01234 67 9 | 0 DESABS RNI DLY IND= +390 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +391 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 MOV TRn,rd +392 T VW | BITS32 +393 ABC E NO S WXYZ | SELECT_DR_TR LCALL +394 BC E X Z | 3 LDBSRU +395 I K M S 34 67 9 | SRCREG DESABS DLY IND= +396 G KL 012 789&| -1 -> IRF RNI SPCR +397 G KL 34 | -1 -> IRF DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +398 T VW | BITS32 0 GENERAL_DETECT +399 A EFGHI K N QR X | DR7 -> TMPB 0x0d LDBSLU +39A CDEF QRSTU WXYZ | 0 1 SHIFT +39B AB D GHI LMN STUV XYZ | SIGMA -> TMPC TMPB AND +39C G JK MN S | SIGMA -> COUNTR +39D =====================================| +39E ABCD UVW Y | GD_HIT JCNTNZ +39F =====================================| +3A0 YZ | RETURN +3A1 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +3A2 GHI KLMN P ST V X | TMPeIP -> EIP ICEBRK 0 GD_HIT +3A3 AB EF N QRSTUV XY | DR6 TMPC OR +3A4 ABCD OP R WXY | BREAKPOINT_CMN LJUMP +3A5 GH KLMN ST VW | SIGMA -> DR6 BITS32 +------------------------------------------|---------------------------------------------------------------------------------------------- +3A6 A DEF NO S WXYZ | GENERAL_DETECT LCALL 0 MOV rd,DR4/6 +3A7 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP +3A8 N QRSTU W YZ012 | DR6 PASS RNI +3A9 G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +3AA A DEF NO S WXYZ | GENERAL_DETECT LCALL 0 MOV rd,DR5/7 +3AB ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP +3AC N QR TU W YZ012 | DR7 PASS RNI +3AD G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +3AE A DEF NO S WXYZ | GENERAL_DETECT LCALL 0 MOV rd,DR0-3 +3AF ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP +3B0 ABC E NO S WXYZ | SELECT_DR_TR LCALL +3B1 BC E X Z 34 | 3 LDBSRU DLY +3B2 G KL 7 &| -1 -> IRF LBAS +3B3 G L O S | IRF2 -> DSTREG +3B4 I K M QRS 01234 67 9 | 0 DESABS RNI DLY IND= +3B5 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +3B6 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 MOV rd,TRn +3B7 T VW | BITS32 +3B8 ABC E NO S WXYZ | SELECT_DR_TR LCALL +3B9 BC E X Z 34 | 3 LDBSRU DLY +3BA G KL 7 9&| -1 -> IRF LPCR +3BB G KL O STU W YZ01234 | IRF2 -> IRF PASS RNI DLY +3BC G L N S | SIGMA -> DSTREG +------------------------------------------|---------------------------------------------------------------------------------------------- +3BD C EFGH J L NO Q S V X | CR0 -> PROTUN FPU_WAIT PTGEN 0 WAIT +3BE AB DE UVWX Z | WAIT_DONE JFPUOK 0 WAIT_LOOP +3BF ABC E UV | WAIT_ERRT JFERR# +3C0 =====================================| +3C1 EF U | WAIT_LOOP JNOINT 0 WAIT_IRQT +3C2 =====================================| +3C3 AB DEF NO QRS WXY | RPTI LJUMP +3C4 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +3C5 ABC E UV Z | FPU_ERROR6 JNPERQ 0 WAIT_ERRT +3C6 =====================================| +3C7 DE U X Z | WAIT_IRQT JMP +3C8 =====================================| 0 WAIT_DONE +3C9 012 | RNI +3CA =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +3CB A CDEF OPQ S WXY | FAULT LJUMP 0 FPU_ERROR6 +3CC CD F TU W Y | 0x10 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +3CD DEFGH J L NO Q S V X | CR0 -> PROTUN FPU_OTHER PTGEN 0 FENI/FDISI/FCLEX/FINIT/FSETPM/FRSTPM r +3CE 2 | RPT +3CF A F I K 34 67 9&| DES_IO 0x800000f8 DLY IN=2 +3D0 G I L N T VW 5 789 | IMM -> OPR_W BITS32 WR W +3D1 Y 34 | ICESIG DLY 0 FPU_FLAG_LOOP +3D2 =====================================| +3D3 E U Z | FPU_FLAG_LOOP JICEWT +3D4 H KL NO QRS 67 9 | EIP DESCOD IND= +3D5 5 9&| PREF +3D6 34 | DLY +3D7 012 | RNI +3D8 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +3D9 T WX | SMISC1 0 FSTCW/FSTSW mw +3DA DEFGH J L NO Q S V X | CR0 -> PROTUN FPU_OTHER PTGEN 0 FSTSW AX/FNSTDW/FNSTSG r +3DB ABC F UV Z | FPU_MISC_CORE JNPERQ 0 FPU_MISC_WAIT +3DC =====================================| +3DD =====================================| +3DE EF U | FPU_MISC_WAIT JNOINT +3DF =====================================| +3E0 AB DEF NO QRS WXY | RPTI LJUMP +3E1 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +3E2 A F I K N TU W Y 34 67 9&| IMM DES_IO 0x800000f8 PASS2 DLY IN=2 0 FPU_MISC_CORE +3E3 G I L N 5 789 | IMM -> OPR_W WR W +3E4 ABCD I K N S U WX 34 67 9 | SIGMA DES_IO FPU_MISC_WRITE JMISC1 DLY IND= +3E5 5 7 9 | RD W +3E6 01234 | RNI DLY +3E7 HIJKLM O R 3 | OPR_R -> AX UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +3E8 H L P S 34 67 &| EA DES_OS 0 DLY IN=+ 0 FPU_MISC_WRITE +3E9 0123 5 89 | RNI UNL wr W +3EA 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +3EB A CDEF OPQ S WXY | FAULT LJUMP 0 FPU_ERROR5 +3EC CD F TU W Y | 0x10 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +3ED DEFGH J L NO Q S V X | CR0 -> PROTUN FPU_OTHER PTGEN 1 FSTENV m +3EE ABC EF U X Z 34 | FSAVE_WAIT JMP DLY +3EF A EFGH JK M O ST WX 5 | IRF2 -> TMPG 0x0d SMISC1 IN+= +------------------------------------------|---------------------------------------------------------------------------------------------- +3F0 DEFGH J L NO Q S V X | CR0 -> PROTUN FPU_OTHER PTGEN 1 FSAVE m +3F1 ABCDE U X Z 34 | FSAVE_WAIT JMP DLY +3F2 A E GH JK M O S 5 | IRF2 -> TMPG 0x5d IN+= +------------------------------------------|---------------------------------------------------------------------------------------------- +3F3 DE TU W Y | WORDSZ PASS2 0 FSAVE_WAIT +3F4 ABC E UV Z | FSAVE_CORE JNPERQ +3F5 BC E X | 3 LDBSLU +3F6 EF U | FSAVE_WAIT JNOINT +3F7 =====================================| +3F8 AB DEF NO QRS WXY | RPTI LJUMP +3F9 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +3FA CDE N STUV Z | SIGMA 2 SUB 0 FSAVE_CORE +3FB GHI LMN S | SIGMA -> TMPC +3FC AB EF QRSTU WXYZ | 0 TMPC SHIFT +3FD DE N STUV Z | SIGMA WORDSZ SUB +3FE GHI LMN ST VW | SIGMA -> TMPC BITS32 +3FF AB EF 345 | TMPC DLY IN+= +400 CD F X Z 56 89&| 0x10 LDBSRU CW B +401 H L N PQ S 34 67 9 | TMPG DES_OS DLY IND= +402 GHI LMN Q S 56 89&| CSOPCD -> TMPC CW B +403 A F I K 34 67 9&| DES_IO 0x800000f8 DLY IN=2 +404 G I L N 5 789 | IMM -> OPR_W WR W +405 AB EF QRSTU WXYZ | 0 TMPC SHIFT +406 GHI LMN ST V X Z | SIGMA -> TMPC BITSDE +407 UV Z | 407 JNPERQ +408 GH JKL N PQ S | TMPG -> TMPH +409 C F N PQRS WXYZ | FSAVE_REGFILE LCALL +40A BC E T Z | 3 LDCNTR +40B CD GHI K N PQR T Z | TMPH -> TMPB 4 LDCNTR +40C C F N PQRS WXYZ | FSAVE_REGFILE LCALL +40D T W Y | SMISC2 +40E B N PQRS W YZ | FSAVE_COR_WAIT LJMPP +40F H L NO Q 34 67 9 | TMPB DES_OS DLY IND= +410 C F N Q STUV XYZ | CSOPCD 0xffff AND +411 GHI K N ST VW | SIGMA -> TMPB BITS32 +412 CD X | 4 LDBSLU +413 AB D QRSTU WXYZ | 0 TMPB SHIFT +414 GHI K N S | SIGMA -> TMPB +415 AB D N Q TUV YZ | FSVeIP TMPB ADD +416 GHI K N S | SIGMA -> TMPB +417 AB EF QRSTU WXYZ | 0 TMPC SHIFT +418 GHI LMN S | SIGMA -> TMPC +419 AB EF N RSTUV YZ | OPROFF TMPC ADD +41A CD GH JK MN S X Z | SIGMA -> TMPG 4 LDBSRU +41B BC N PQ STUV XYZ | TMPG 0xffff0000 AND +41C GHI L N S | SIGMA -> TMPD +41D AB E QRSTU WXYZ | 0 TMPD SHIFT +41E GHI MN S | SIGMA -> TMPE +41F BC NO Q TUV XYZ | TMPB 0xffff0000 AND +420 GHI L N S | SIGMA -> TMPD +421 AB E QRSTU WXYZ | 0 TMPD SHIFT +422 GHI L N ST VW Y | SIGMA -> TMPD BITS16 +423 A DE GHI LMNO X | TMPF -> TMPC 8 LDBSLU +424 AB EF NO RSTU WXYZ | TMPC TMPC SHIFT +425 T V X Z | BITSDE +426 G I L NO Q 5 78 &| TMPB -> OPR_W WR +427 B DE N STUV XYZ | SIGMA 0x7ff AND +428 AB E N STUV XY | SIGMA TMPD OR +429 DE 345 | WORDSZ DLY IN+= +42A G I L N S 5 78 &| SIGMA -> OPR_W WR +42B FGH J L NO Q S V X 345 9 | CR0 -> PROTUN FPU_FSAVE PTGEN DLY IN+D +42C B D G I L N PQ ST Z 5 78 &| TMPG -> OPR_W 0x29 LDCNTR WR +42D CDEFGHI K N P RS X Z 345 9 | COUNTR -> TMPB 1 LDBSRU DLY IN+D +42E G I L NO S 5 78 &| TMPE -> OPR_W WR +42F G I L N Q 5 78 &| FSVeIP -> OPR_W WR 0 FSAVE_COR_WAIT +430 DE 345 | WORDSZ DLY IN+= +431 G I L N Q S 5 78 &| CSOPCD -> OPR_W WR +432 FGH J L NO Q S V X 345 9 | CR0 -> PROTUN FPU_FSAVE PTGEN DLY IN+D +433 B D G I L N RST Z 5 78 &| OPROFF -> OPR_W 0x29 LDCNTR WR +434 CDEFGHI K N P RS X Z 345 9 | COUNTR -> TMPB 1 LDBSRU DLY IN+D +435 G I L NO RS 5 78 &| TMPC -> OPR_W WR +436 A I K 34 67 9&| DES_IO 0x800000fc DLY IN=2 0 FSAVE_REGFILE +437 AB EF U W Y 1 4 | FSAVE_NOWRITE JMISC2 FIO WIO +438 T 5 7 &| DECNTR RD +439 DE H L N PQR TUV YZ 34 67 9 | TMPH DES_OS WORDSZ ADD DLY IND= +43A ABC GH JKL N S UVW YZ 5 8 &| SIGMA -> TMPH FSAVE_DONEFILE JCNTZ wr +43B 3 | UNL +43C A TU W Y 34 | 0x800000fc PASS2 DLY 0 FSAVE_LOOP +43D ABC F I K N S U W Y 1 4 67 9 | SIGMA DES_IO FSAVE_NOWRITE JMISC2 FIO WIO IND= +43E T 5 7 &| DECNTR RD +43F DE H L N PQR TUV YZ 34 67 9 | TMPH DES_OS WORDSZ ADD DLY IND= +440 D GH JKL N S UVW Y 5 8 &| SIGMA -> TMPH FSAVE_LOOP JCNTNZ wr +441 3 | UNL +442 YZ 34 | RETURN DLY 0 FSAVE_DONEFILE +443 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +444 34 | DLY 0 FSAVE_NOWRITE +445 C F UVW Y | FSAVE_LOOP JCNTNZ +446 DE N PQR TUV YZ 3 | TMPH WORDSZ ADD UNL +447 GH JKL N S YZ | SIGMA -> TMPH RETURN +448 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +449 AB E U WX | 457 JMISC1 0 FSAVE_387 +44A AB D QRSTU WXYZ | 0 TMPB SHIFT +44B G JK MN ST YZ 34 | SIGMA -> COUNTR CMISC2 DLY +44C DE O STUV YZ 5 | IRF2 WORDSZ ADD IN+= +44D C F N PQRS WXYZ | FSAVE_REGFILE LCALL +44E GH JKL N ST VW | SIGMA -> TMPH BITS32 +44F 012 | RNI +450 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +451 ABC E U WX | 457 JMISC1 0 FSAVE_287 +452 CDEF NO Q TUV Z | TMPB 1 SUB +453 G JK MN ST YZ 34 | SIGMA -> COUNTR CMISC2 DLY +454 DE O STUV YZ 5 | IRF2 WORDSZ ADD IN+= +455 C F N PQRS WXYZ | FSAVE_REGFILE LCALL +456 GH JKL N ST VW Y | SIGMA -> TMPH BITS16 +457 012 | RNI +458 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +459 DEFGH J L NO Q S V X | CR0 -> PROTUN FPU_OTHER PTGEN 1 FLDENV m +45A ABC F U X Z 34 | FRSTOR_WAIT JMP DLY +45B A EFGH JK M O ST WX 5 | IRF2 -> TMPG 0x0d SMISC1 IN+= +------------------------------------------|---------------------------------------------------------------------------------------------- +45C DEFGH J L NO Q S V X | CR0 -> PROTUN FPU_OTHER PTGEN 1 FRSTOR m +45D ABCD U X Z 34 | FRSTOR_WAIT JMP DLY +45E A E GH JK M O S 5 | IRF2 -> TMPG 0x5d IN+= +------------------------------------------|---------------------------------------------------------------------------------------------- +45F A CDEF OPQ S WXY | FAULT LJUMP 0 FPU_ERROR4 +460 CD F TU W Y | 0x10 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +461 DE TU W Y | WORDSZ PASS2 0 FRSTOR_WAIT +462 AB D UVWX Z | FRSTOR_CORE JFPUOK +463 BC E X | 3 LDBSLU +464 ABC E UV | FRSTOR_ERRT JFERR# +465 =====================================| +466 D F U | FRSTOR_WAIT JNOINT 0 FRSTOR_IRQT +467 =====================================| +468 AB DEF NO QRS WXY | RPTI LJUMP +469 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +46A C EF UV Z | FPU_ERROR4 JNPERQ 0 FRSTOR_ERRT +46B =====================================| +46C DE U X Z | FRSTOR_IRQT JMP +46D =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +46E CDE N STUV Z | SIGMA 2 SUB 0 FRSTOR_CORE +46F GHI LMN S | SIGMA -> TMPC +470 AB EF QRSTU WXYZ | 0 TMPC SHIFT +471 DE N STUV Z | SIGMA WORDSZ SUB +472 EFGHI LMN S X | SIGMA -> TMPC BITS_V LDBSLU +473 AB EF 345 | TMPC DLY IN+= +474 CDEF TU W Y 56 9&| 1 PASS2 CR B +475 H L N PQ S 34 67 9 | TMPG DES_OS DLY IND= +476 GHI LMN S 56 9&| SIGMA -> TMPC CR B +477 A F I K 34 67 9&| DES_IO 0x800000f8 DLY IN=2 +478 C EFG I L N TU W Y 5 789 | IMM -> OPR_W -1 PASS2 WR W +479 AB EF N STU WXYZ | SIGMA TMPC SHIFT +47A =====================================| +47B GHI LMN S UV Z | SIGMA -> TMPC FRSTOR_CORWAIT JNPERQ 0 FRSTOR_CORWAIT +47C BC E GH JKL N PQ ST Z | TMPG -> TMPH 3 LDCNTR +47D BC N PQ S WXYZ | FRSTOR_REGFILE LCALL +47E =====================================| +47F BC N PQ S WXYZ | FRSTOR_REGFILE LCALL +480 CD GHI K N PQR T Z | TMPH -> TMPB 4 LDCNTR +481 H L NO Q 34 67 9 | TMPB DES_OS DLY IND= +482 B D T Z 5 7 &| 0x29 LDCNTR RD +483 DE 345 | WORDSZ DLY IN+= +484 A D N PQ S W YZ 5 7 &| FRSTOR_PM LJMPP RD +485 C F O R TUV XYZ 3 | OPR_R 0xffff AND UNL +486 GHI K N S 345 9 | SIGMA -> TMPB DLY IN+D +487 AB EF O R TUV XYZ 3 5 7 &| OPR_R TMPC AND UNL RD +488 GHI L N S 345 9 | SIGMA -> TMPD DLY IN+D +489 A DE X 5 7 &| 8 LDBSLU RD +48A C F O R TUV XYZ 3 | OPR_R 0xffff AND UNL +48B GHI MN ST VW Y 34 | SIGMA -> TMPE BITS16 DLY +48C AB E NO R TU WXYZ | TMPD TMPD SHIFT +48D GHI N ST VW | SIGMA -> TMPF BITS32 +48E CD X | 4 LDBSLU +48F AB E GH K M QRSTU WXYZ | 0 -> CSOPCD TMPD SHIFT +490 BC N STUV XYZ | SIGMA 0xffff0000 AND +491 AB D N STUV XY | SIGMA TMPB OR +492 GH K N S | SIGMA -> FSVeIP +493 AB EF O R TUV XYZ 3 | OPR_R TMPC AND UNL +494 GHI L N S | SIGMA -> TMPD +495 AB E QRSTU WXYZ | 0 TMPD SHIFT +496 GHI K NO S | TMPE -> TMPB +497 GH J L NO Q S V X | CR0 -> PROTUN FPU_FRSTOR PTGEN +498 AB D N STUV YZ | SIGMA TMPB ADD +499 GH LMN S | SIGMA -> OPROFF +49A CDEFGHI K N P RS X Z | COUNTR -> TMPB 1 LDBSRU +49B AB EF O R TUV XYZ | OPR_R TMPC AND 0 FRSTOR_PM +49C GH K N S 345 9 | SIGMA -> FSVeIP DLY IN+D +49D C F O R TUV XYZ 3 5 7 &| OPR_R 0xffff AND UNL RD +49E GHI L N S 345 9 | SIGMA -> TMPD DLY IN+D +49F AB EF O R TUV XYZ 3 5 7 &| OPR_R TMPC AND UNL RD +4A0 GH LMN ST VW 34 | SIGMA -> OPROFF BITS32 DLY +4A1 CD FGHI K O R X 3 | OPR_R -> TMPB 0x10 LDBSLU UNL +4A2 AB D QRSTU WXYZ | 0 TMPB SHIFT +4A3 GH J L NO Q S V X | CR0 -> PROTUN FPU_FRSTOR PTGEN +4A4 AB E N STUV XY | SIGMA TMPD OR +4A5 GH K MN S | SIGMA -> CSOPCD +4A6 CDEFGHI K N P RS X Z | COUNTR -> TMPB 1 LDBSRU +4A7 H L N PQR 34 67 9 | TMPH DES_OS DLY IND= 0 FRSTOR_REGFILE +4A8 T 5 7 &| DECNTR RD +4A9 A I K 34 67 9&| DES_IO 0x800000fc DLY IN=2 +4AA DE N PQR TUV YZ | TMPH WORDSZ ADD +4AB ABC GH JKL N S UVW YZ 1 4 | SIGMA -> TMPH FRSTOR_DONEFIL JCNTZ FIO WIO +4AC 3 5 8 &| UNL wr +4AD H L N PQR 34 67 9 | TMPH DES_OS DLY IND= 0 FRSTOR_LOOP +4AE T 5 7 &| DECNTR RD +4AF A I K 34 67 9&| DES_IO 0x800000fc DLY IN=2 +4B0 DE N PQR TUV YZ 1 | TMPH WORDSZ ADD FIO +4B1 D GH JKL N S UVW Y 1 4 | SIGMA -> TMPH FRSTOR_LOOP JCNTNZ FIO WIO +4B2 3 5 8 &| UNL wr +4B3 YZ 34 | RETURN DLY 0 FRSTOR_DONEFIL +4B4 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +4B5 ABC EF U WX | FRSTOR_DONE JMISC1 0 FRSTOR_387 +4B6 AB D QRSTU WXYZ01 | 0 TMPB SHIFT RNi +4B7 BC N PQ S WXYZ | FRSTOR_REGFILE LCALL +4B8 G JK MN ST VW 34 | SIGMA -> COUNTR BITS32 DLY +4B9 012 | RNI +4BA =====================================| 0 FRSTOR_DONE +4BB F U WX | FRSTOR_DONE JMISC1 0 FRSTOR_287 +4BC CDEF NO Q TUV Z01 | TMPB 1 SUB RNi +4BD BC N PQ S WXYZ | FRSTOR_REGFILE LCALL +4BE G JK MN ST VW Y 34 | SIGMA -> COUNTR BITS16 DLY +4BF 012 | RNI +4C0 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +4C1 DEFGH J L NO Q S V X | CR0 -> PROTUN FPU_OTHER PTGEN 0 FP instructions that don't access memory +4C2 AB DE UVWX Z | FPU_REG_CORE JFPUOK 0 FPU_REG_WAIT +4C3 ABC E UV | FPU_REG_ERRT JFERR# +4C4 =====================================| +4C5 EF U | FPU_REG_WAIT JNOINT 0 FPU_REG_IRQT +4C6 =====================================| +4C7 AB DEF NO QRS WXY | RPTI LJUMP +4C8 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +4C9 ABC UV Z | FPU_ERROR3 JNPERQ 0 FPU_REG_ERRT +4CA =====================================| +4CB DE U X Z | FPU_REG_IRQT JMP +4CC A F I K N TU W YZ 34 67 9&| IMM DES_IO 0x800000f8 PASS DLY IN=2 0 FPU_REG_CORE +4CD G I L N 5 789 | IMM -> OPR_W WR W +4CE GH K N P S UV Z | TMPeIP -> FSVeIP FPU_REG_CORWAI JNPERQ 0 FPU_REG_CORWAI +4CF GH K M OPQR 012 | CS -> CSOPCD RNI +4D0 GHI N S 34 | SIGMA -> TMPF DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +4D1 A CDEF OPQ S WXY | FAULT LJUMP 0 FPU_ERROR3 +4D2 CD F TU W Y | 0x10 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +4D3 D GH J L NO Q S V X | CR0 -> PROTUN FPU_LOAD_80 PTGEN 1 FBLD/FLD mt +4D4 CDE GHI K Q TU W Y 34 | OPCODE -> TMPB 2 PASS2 DLY +4D5 B D FGH JK M O ST VW 5 | IRF2 -> TMPG 9 BITS32 IN+= +4D6 CD FG JK MN S X | SIGMA -> COUNTR 0x10 LDBSLU +4D7 DE GH J L NO Q S V X | CR0 -> PROTUN FPU_LOAD_3264 PTGEN 1 FADD/FMUL/FCOM/FCOMP/FSUB/FSUBR/FDIV/FDIVR/FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FLD/FILD md +4D8 CDEFGHI K Q TU W Y 34 | OPCODE -> TMPB 1 PASS2 DLY +4D9 BC E GH JK M O ST VW 5 | IRF2 -> TMPG 3 BITS32 IN+= +4DA CD FG JK MN S X | SIGMA -> COUNTR 0x10 LDBSLU +4DB DE GH J L NO Q S V X | CR0 -> PROTUN FPU_LOAD_3264 PTGEN 1 FLD/FILD/FADD/FMUL/FCOM/FCOMP/FSUBR/FSUB/FDIVR/FDIV mq +4DC CDE GHI K Q TU W Y 34 | OPCODE -> TMPB 2 PASS2 DLY +4DD B EFGH JK M O ST VW 5 | IRF2 -> TMPG 7 BITS32 IN+= +4DE CD FG JK MN S X | SIGMA -> COUNTR 0x10 LDBSLU +4DF T W Y 34 | SMISC2 DLY 1 FLDCW mw +4E0 DEFGH J L NO Q S V X | CR0 -> PROTUN FPU_OTHER PTGEN 1 FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FILD mw +4E1 CDEFGHI K Q TU W Y 34 | OPCODE -> TMPB 1 PASS2 DLY +4E2 CDEFGH JK M O ST VW 5 | IRF2 -> TMPG 1 BITS32 IN+= +4E3 CD FG JK MN S X | SIGMA -> COUNTR 0x10 LDBSLU +4E4 AB D QRSTU WXYZ | 0 TMPB SHIFT +4E5 AB D F U X Z | FPU_LOAD_WAIT JMP +4E6 T VW Y | BITS16 +------------------------------------------|---------------------------------------------------------------------------------------------- +4E7 T WX | SMISC1 0 FPU_LD80_287 +4E8 GHI LMN P RS | COUNTR -> TMPC 0 FPU_LD3264_287 +4E9 AB EF N P RSTUV YZ | COUNTR TMPC ADD +4EA G JK MN S | SIGMA -> COUNTR +4EB AB D QRSTU WXYZ | 0 TMPB SHIFT +4EC ABCD U X Z | FPU_LOAD_WAIT JMP +4ED T VW Y | BITS16 +------------------------------------------|---------------------------------------------------------------------------------------------- +4EE T WX | SMISC1 0 FPU_LD80_387 +4EF AB D QRSTU WXYZ | 0 TMPB SHIFT +4F0 AB D GHI K N S UVWX Z | SIGMA -> TMPB FPU_LOAD_CORE JFPUOK 0 FPU_LOAD_WAIT +4F1 AB D OPQR TUV XY | CS TMPB OR +4F2 ABC E UV | FPU_LOAD_ERRT JFERR# +4F3 =====================================| +4F4 D U | FPU_LOAD_WAIT JNOINT 0 FPU_LOAD_IRQT +4F5 =====================================| +4F6 AB DEF NO QRS WXY | RPTI LJUMP +4F7 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +4F8 A D UV Z | FPU_ERROR2 JNPERQ 0 FPU_LOAD_ERRT +4F9 =====================================| +4FA DE U X Z | FPU_LOAD_IRQT JMP +4FB =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +4FC GHI K N S 56 9&| SIGMA -> TMPB CR B 0 FPU_LOAD_CORE +4FD DE H L N PQ STUV YZ 34 67 9 | TMPG DES_OS WORDSZ ADD DLY IND= +4FE A FGH JKL N STU W Y 56 9&| SIGMA -> TMPH 0x800000f8 PASS2 CR B +4FF A C F I K N S U W Y 34 67 9 | SIGMA DES_IO FLDCW JMISC2 DLY IND= +500 G I L N TU W YZ 5 789 | IMM -> OPR_W PASS WR W +501 A H L N PQ STU W Y 34 67 9 | TMPG DES_OS 0x800000fc PASS2 DLY IND= +502 GH K MNO Q T 5 7 &| TMPB -> CSOPCD DECNTR RD +503 I K N S UV Z 34 67 9 | SIGMA DES_IO FPU_LOAD_CORWA JNPERQ DLY IND= 0 FPU_LOAD_CORWA +504 1 4 | FIO WIO +505 ABC FGH K N P S UVW YZ 3 5 8 &| TMPeIP -> FSVeIP FPU_LOAD_DONE JCNTZ UNL wr +506 H L N PQR 34 67 9 | TMPH DES_OS DLY IND= 0 FPU_LOAD_LOOP +507 GHI N T 5 7 &| IMM -> TMPF DECNTR RD +508 A I K 34 67 9&| DES_IO 0x800000fc DLY IN=2 +509 DE N PQR TUV YZ 1 | TMPH WORDSZ ADD FIO +50A D GH JKL N S UVW Y 1 4 | SIGMA -> TMPH FPU_LOAD_LOOP JCNTNZ FIO WIO +50B 3 5 8 &| UNL wr +50C ABCDE GH LMN PQ S U WX 34 | TMPG -> OPROFF FPU_LD80_DONE JMISC1 DLY 0 FPU_LOAD_DONE +50D H L N PQR 012 67 9 | TMPH DES_OS RNI IND= +50E 34 | DLY 0 FPU_LD80_DONE +50F 1 5 7 9 | FIO RD W +510 GHI N S 1 4 | SIGMA -> TMPF FIO WIO +511 A I K 34 67 9&| DES_IO 0x800000fc DLY IN=2 +512 0123 5 89 | RNI UNL wr W +513 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +514 A CDEF OPQ S WXY | FAULT LJUMP 0 FPU_ERROR2 +515 CD F TU W Y | 0x10 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +516 H L N PQ S 34 67 9 | TMPG DES_OS DLY IND= 0 FLDCW +517 5 7 9 | RD W +518 UV Z 34 | FLDCW_COR_WAIT JNPERQ DLY 0 FLDCW_COR_WAIT +519 A I K 1 4 67 9&| DES_IO 0x800000fc FIO WIO IN=2 +51A 0123 5 89 | RNI UNL wr W +51B 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +51C AB D QRSTU WXYZ | 0 TMPB SHIFT 0 FPU_LD3264_387 +51D A F I K 34 67 9&| DES_IO 0x800000f8 DLY IN=2 +51E G I L N 5 789 | IMM -> OPR_W WR W +51F AB D FGHI K N S UVWX Z | SIGMA -> TMPB FPU_LD3264_COR JFPUOK 0 FPU_LD3264_WAI +520 AB D OPQR TUV XY | CS TMPB OR +521 ABC E UV | FPU_LD3264_ERR JFERR# +522 =====================================| +523 D U | FPU_LD3264_WAI JNOINT 0 FPU_LD3264_IRQ +524 =====================================| +525 AB DEF NO QRS WXY | RPTI LJUMP +526 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +527 B EF UV Z | FPU_ERROR2 JNPERQ 0 FPU_LD3264_ERR +528 =====================================| +529 DE U X Z | FPU_LD3264_IRQ JMP +52A H L N PQ S 34 67 9 | TMPG DES_OS DLY IND= 0 FPU_LD3264_COR +52B ABC E GHI K N S UV XYZ 5 7 &| SIGMA -> TMPB FPU_LD32 JCNT1 RD +52C A I K 34 67 9&| DES_IO 0x800000fc DLY IN=2 +52D 5 8 &| wr +52E DE H L N PQ S 34 67 &| TMPG DES_OS WORDSZ DLY IN=+ +52F 3 5 7 &| UNL RD +530 A I K 34 67 9&| DES_IO 0x800000fc DLY IN=2 +531 GHI N 5 8 &| IMM -> TMPF wr 0 FPU_LD32 +532 GH K MNO Q | TMPB -> CSOPCD +533 GH K N P S UV Z 34 | TMPeIP -> FSVeIP FPU_LD32_WAIT JNPERQ DLY 0 FPU_LD32_WAIT +534 GH LMN PQ S 012 | TMPG -> OPROFF RNI +535 3 | UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +536 A CDEF OPQ S WXY | FAULT LJUMP 0 #NM +537 B EF TU W Y | 7 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +538 E GH J L NO Q S V X | CR0 -> PROTUN FPU_STORE_80 PTGEN 1 FBSTP/FSTP mt +539 CDE GHI K Q TU W Y 34 | OPCODE -> TMPB 2 PASS2 DLY +53A B D FGH JK M O ST VW 5 | IRF2 -> TMPG 9 BITS32 IN+= +53B CD FG JK MN S X | SIGMA -> COUNTR 0x10 LDBSLU +53C EFGH J L NO Q S V X | CR0 -> PROTUN FPU_STORE_3264 PTGEN 1 FST/FSTP/FIST/FISTP md +53D CDEFGHI K Q TU W Y 34 | OPCODE -> TMPB 1 PASS2 DLY +53E BC E GH JK M O ST VW 5 | IRF2 -> TMPG 3 BITS32 IN+= +53F CD FG JK MN S X | SIGMA -> COUNTR 0x10 LDBSLU +540 EFGH J L NO Q S V X | CR0 -> PROTUN FPU_STORE_3264 PTGEN 1 FST/FSTP/FISTP mq +541 CDE GHI K Q TU W Y 34 | OPCODE -> TMPB 2 PASS2 DLY +542 B EFGH JK M O ST VW 5 | IRF2 -> TMPG 7 BITS32 IN+= +543 CD FG JK MN S X | SIGMA -> COUNTR 0x10 LDBSLU +544 DEFGH J L NO Q S V X | CR0 -> PROTUN FPU_OTHER PTGEN 1 FIST/FISTP mw +545 CDEFGHI K Q TU W Y 34 | OPCODE -> TMPB 1 PASS2 DLY +546 CDEFGH JK M O ST VW 5 | IRF2 -> TMPG 1 BITS32 IN+= +547 CD FG JK MN S X | SIGMA -> COUNTR 0x10 LDBSLU +548 AB D QRSTU WXYZ | 0 TMPB SHIFT +549 AB EF U X Z | FPU_STORE_WAIT JMP +54A T VW Y | BITS16 +------------------------------------------|---------------------------------------------------------------------------------------------- +54B A CDEF OPQ S WXY | FAULT LJUMP 0 FPU_ERROR +54C CD F TU W Y | 0x10 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +54D T WX | SMISC1 0 FPU_ST80_287 +54E GHI LMN P RS | COUNTR -> TMPC 0 FPU_ST3264_287 +54F AB EF N P RSTUV YZ | COUNTR TMPC ADD +550 G JK MN S | SIGMA -> COUNTR +551 AB D QRSTU WXYZ | 0 TMPB SHIFT +552 ABCD U X Z | FPU_STORE_WAIT JMP +553 T VW Y | BITS16 +------------------------------------------|---------------------------------------------------------------------------------------------- +554 T WX | SMISC1 0 FPU_ST80_387 +555 AB D QRSTU WXYZ | 0 TMPB SHIFT 0 FPU_ST3264_387 +556 AB D GHI K N S UVWX Z | SIGMA -> TMPB FPU_STORE_CORE JFPUOK 0 FPU_STORE_WAIT +557 AB D OPQR TUV XY | CS TMPB OR +558 ABC E UV | FPU_STORE_ERRT JFERR# +559 =====================================| +55A D U | FPU_STORE_WAIT JNOINT 0 FPU_STORE_IRQT +55B =====================================| +55C AB DEF NO QRS WXY | RPTI LJUMP +55D =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +55E B EF UV Z | FPU_ERROR JNPERQ 0 FPU_STORE_ERRT +55F =====================================| +560 DE U X Z | FPU_STORE_IRQT JMP +561 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +562 GHI K N S 56 89&| SIGMA -> TMPB CW B 0 FPU_STORE_CORE +563 H L N PQ S 34 67 9 | TMPG DES_OS DLY IND= +564 56 89&| CW B +565 A F I K 34 67 9&| DES_IO 0x800000f8 DLY IN=2 +566 G I L N 5 789 | IMM -> OPR_W WR W +567 A I K 34 67 9&| DES_IO 0x800000fc DLY IN=2 +568 UV Z | FPU_STORE_CORW JNPERQ 0 FPU_STORE_CORW +569 =====================================| +56A A CD FGHI N UV Z 1 4 | IMM -> TMPF FPU_STORE_ABRT JNPERQ FIO WIO +56B GH K MNO Q | TMPB -> CSOPCD +56C GH JKL N PQ S 5 7 &| TMPG -> TMPH RD +56D ABC H L N PQR UV XYZ 34 67 9 | TMPH DES_OS FPU_STORE_DONE JCNT1 DLY IND= +56E GH K N P ST 5 8 &| TMPeIP -> FSVeIP DECNTR wr +56F DE N PQR TUV YZ 3 | TMPH WORDSZ ADD UNL 0 FPU_STORE_LOOP +570 GH JKL N S 34 | SIGMA -> TMPH DLY +571 A I K 1 4 67 9&| DES_IO 0x800000fc FIO WIO IN=2 +572 5 7 &| RD +573 D H L N PQR UV XY 34 67 9 | TMPH DES_OS FPU_STORE_LOOP JCNTN1 DLY IND= +574 T 5 8 &| DECNTR wr +575 ABCD FGH LMN PQ S U WX 34 | TMPG -> OPROFF FPU_STORE_287 JMISC1 DLY 0 FPU_STORE_DONE +576 A I K 0123 67 9&| DES_IO 0x800000fc RNI UNL IN=2 +577 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +578 1 4 | FIO WIO 0 FPU_STORE_287 +579 5 7 9 | RD W +57A DE H L N PQR 34 67 &| TMPH DES_OS WORDSZ DLY IN=+ +57B 0123 5 89 | RNI UNL wr W +57C 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +57D GH K N P S 34 | TMPeIP -> FSVeIP DLY 0 FPU_STORE_ABRT +57E GH LMN PQ S 012 | TMPG -> OPROFF RNI +57F =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +580 A CDEF H M VWXY 34 89 | DES_SR TST_DES_SIMPLE PTSAV1 DLY SPTR 0 p MOV ES/DS/FS/GS,rw +581 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +582 ABCDEFG J L R V Z 34 | DSTREG -> SLCTR TST_SEL_NONSS PTSELE DLY +583 AB EFG LMN PQ 012 6 | SLCTR2 -> SEGREG TMPC RNI SDEL +584 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +585 A CDE H M VW 34 89 | DES_SR TST_DES_SS PTSAV7 DLY SPTR 0 p MOV SS,rw +586 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +587 AB EFG J L R V Z 34 | DSTREG -> SLCTR TST_SEL_SS PTSELE DLY +588 AB EFG LMN PQ 0 2 6 | SLCTR2 -> SEGREG TMPC RnI SDEL +589 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +58A AB DE N P WXYZ 34 | LD_DESCRIPTOR LCALL DLY 0 PM_LD_DSESFSGS +58B ABCDEFG J L O R V Z 3 | OPR_R -> SLCTR TST_SEL_NONSS PTSELE UNL +58C AB EFG LMN PQ 012 6 | SLCTR2 -> SEGREG TMPC RNI SDEL +58D 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +58E AB DE N P WXYZ 34 | LD_DESCRIPTOR LCALL DLY 0 PM_LD_SS +58F AB EFG J L O R V Z 3 | OPR_R -> SLCTR TST_SEL_SS PTSELE UNL +590 AB EFG LMN PQ 0 2 6 | SLCTR2 -> SEGREG TMPC RnI SDEL +591 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +592 NO R TU W YZ 3 5 7 | TMPD PASS UNL RD D 0 NULL_SELECTOR +593 HI L QRS YZ 34 6 9 | 0 DESPTR 0 RETURN DLY SDEH +594 GHI LM QRS 3 6 &| 0 -> TMPC 0 UNL SDES +------------------------------------------|---------------------------------------------------------------------------------------------- +595 A CDEF IJKLM VWXY 34 89 | DES_ES TST_DES_SIMPLE PTSAV1 DLY SPTR 0 PM_LES +596 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +597 BC FG J L O R V Z 3 | OPR_R -> SLCTR TST_SEL_LES PTSELE UNL +598 AB EFG IJKLMN PQ 012 6 | SLCTR2 -> ES TMPC RNI SDEL +599 G MN S 34 | SIGMA -> SRCREG DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +59A A CDE IJK M VW 34 89 | DES_SS TST_DES_SS PTSAV7 DLY SPTR 0 PM_LSS +59B ABC EF N P WXYZ | LD_DES_SSFSGS LCALL +59C AB EFG J L O R V Z 3 | OPR_R -> SLCTR TST_SEL_SS PTSELE UNL +59D AB EFG IJK MN PQ 012 6 | SLCTR2 -> SS TMPC RNI SDEL +59E G MN S 34 | SIGMA -> SRCREG DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +59F A CDEF IJK VWXY 34 89 | DES_DS TST_DES_SIMPLE PTSAV1 DLY SPTR 0 PM_LDS +5A0 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +5A1 BC G J L O R V Z 3 | OPR_R -> SLCTR TST_SEL_LDS PTSELE UNL +5A2 AB EFG IJK N PQ 012 6 | SLCTR2 -> DS TMPC RNI SDEL +5A3 G MN S 34 | SIGMA -> SRCREG DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +5A4 A D F N STUV XY | SIGMA 0x40 OR 0 PM_LFS_LGS +5A5 G JK MN S | SIGMA -> COUNTR +5A6 =====================================| +5A7 A CDEFG KL VWXY 34 89 | -1 -> IRF TST_DES_SIMPLE PTSAV1 DLY SPTR +5A8 ABC EF N P WXYZ | LD_DES_SSFSGS LCALL +5A9 B DEFG J L O R V Z 3 | OPR_R -> SLCTR TST_SEL_LFSLGS PTSELE UNL +5AA AB EFG KL N PQ 012 6 | SLCTR2 -> IRF TMPC RNI SDEL +5AB G MN S 34 | SIGMA -> SRCREG DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +5AC A CD F IJKL VW 34 89 | DES_CS TST_DES_JMP PTSAV7 DLY SPTR 0 JUMP_FAR_PM +5AD AB DE N P WXYZ | LD_DESCRIPTOR LCALL +5AE ABCDE G J L N P RS V Z | COUNTR -> SLCTR TST_SEL_CS PTSELE +5AF B E GH J L N PQ V X | SLCTR2 -> PROTUN SET_RPL_TO_CPL PTGEN +5B0 AB EF 6 | TMPC SDEL +5B1 CDEF L NO Q WXY 789&| PAGER5 JMP_FAR_COMMON LJUMP SPCR +5B2 N P R TU W YZ | PROTUN PASS +------------------------------------------|---------------------------------------------------------------------------------------------- +5B3 A CD V XY | TST_DES_JGATE PTGATE 0 JUMP_FAR_PM_GATE +5B4 GH JKL N S 2 | SIGMA -> TMPH RPT +5B5 A C EF IJKL VW 34 89 | DES_CS TST_DES_JGDEST PTSAV7 DLY SPTR +5B6 A E OPQR WXY | #GP/#TS(I0,E0) LJUMP +5B7 B V X | SET_FAULT PTGEN +------------------------------------------|---------------------------------------------------------------------------------------------- +5B8 A C FG K MN P R V XY | PROTUN -> COUNT5 TST_DES_CGATE PTGATE 0 CALL_FAR_PM_GATE +5B9 GH JKL N ST WX Z 2 | SIGMA -> TMPH SINTHW RPT +5BA A C IJKL VW 34 89 | DES_CS TST_DES_CGDEST PTSAV7 DLY SPTR +5BB A E OPQR WXY | #GP/#TS(I0,E0) LJUMP 0 GENERAL_FAULTP +5BC B V X | SET_FAULT PTGEN +------------------------------------------|---------------------------------------------------------------------------------------------- +5BD T W Y | SMISC2 0 CALLGATE286 +5BE C F NO RSTUV XYZ | TMPC 0xffff AND 0 CALLGATE386 +5BF GHI LMN S | SIGMA -> TMPC +5C0 BC NO Q TUV XYZ | TMPB 0xffff0000 AND +5C1 AB EF N STUV XY | SIGMA TMPC OR +5C2 ABC FGH JK MN S U X Z | SIGMA -> TMPG LD_DESCRIPTOR JMP +5C3 ABCDE G J L N PQR V Z 34 | TMPH -> SLCTR TST_SEL_CS PTSELE DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +5C4 CD HI M P R 67 &| SLCTR DESSDT 4 IN=+ 0 LD_DES_SSFSGS +5C5 CD F N TUV X Z 567 | IMM 0x10 XOR rd D +5C6 C G JK MN S 345 | SIGMA -> COUNTR -4 DLY IN+= +5C7 ABC F U X Z 567 | LD_DESCRIPTOR2 JMP rd D +5C8 A CDEFGH J L O R V XYZ 3 | OPR_R -> PROTUN TST_DES_SIMPLE PTOVRR UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +5C9 CD HI M P R 67 &| SLCTR DESSDT 4 IN=+ 0 LD_DESCRIPTOR +5CA 567 | rd D +5CB C 345 | -4 DLY IN+= +5CC 567 | rd D +5CD A CDEFGH J L O R V XYZ 3 | OPR_R -> PROTUN TST_DES_SIMPLE PTOVRR UNL +5CE GHI K O R T VW | OPR_R -> TMPB BITS32 0 LD_DESCRIPTOR2 +5CF CD F X 34 | 0x10 LDBSLU DLY +5D0 AB D GHI LM O R TU WXYZ 3 | OPR_R -> TMPC TMPB SHIFT UNL +5D1 A E OPQR WXY | #GP/#TS(I0,E0) LJUMP +5D2 B V X | SET_FAULT PTGEN +------------------------------------------|---------------------------------------------------------------------------------------------- +5D3 ABC EFGHI LMN S U X Z | SIGMA -> TMPC PROT_TESTS_CMN JMP 0 PRESENT_TSS +5D4 HI L NO Q T V X Z 6 9 | TMPB DESPTR 0 BITSDE SDEH +------------------------------------------|---------------------------------------------------------------------------------------------- +5D5 CD GHI LMN S 345 | SIGMA -> TMPC 4 DLY IN+= 0 PROT_TESTS_PASSED +5D6 G I L N P R 5 789 | PROTUN -> OPR_W WR W +5D7 HI L NO Q T V X Z 34 6 9 | TMPB DESPTR 0 BITSDE DLY SDEH +5D8 AB EF YZ 6 &| TMPC RETURN SDES 0 PROT_TESTS_CMN +5D9 AB E GHI LM O R TU W Y | OPR_R -> TMPC TMPD PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +5DA CD GHI LMN S 345 | SIGMA -> TMPC 4 DLY IN+= 0 PROT_TESTS_PASSED2 +5DB G I L N P R 5 789 | PROTUN -> OPR_W WR W +5DC ABCD F HI L NO Q U W Y 34 6 9 | TMPB DESPTR PROT_TESTS_P16 JMISC2 DLY SDEH +5DD AB EF YZ 6 &| TMPC RETURN SDES +5DE GHI LM O R T VW | OPR_R -> TMPC BITS32 +------------------------------------------|---------------------------------------------------------------------------------------------- +5DF GHI LM O R T VW Y | OPR_R -> TMPC BITS16 0 PROT_TESTS_P16 +5E0 A C E IJKL VW 34 89 | DES_CS TST_DES_CALL PTSAV7 DLY SPTR 0 CALL_FAR_PM +5E1 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +5E2 ABCDE G J L N P RS V Z | COUNTR -> SLCTR TST_SEL_CS PTSELE +5E3 AB EFGH J L N PQ 6 | SLCTR2 -> PROTUN TMPC SDEL +5E4 B E L V X 789&| PAGER5 SET_RPL_TO_CPL PTGEN SPCR +5E5 D F H K MNOP RSTUV YZ 34 67 &| ESP DESSTK NEGWSZ ADD DLY IN=+ +5E6 G I L OPQR 5 78 &| CS -> OPR_W WR +5E7 GHI K N P R 345 9 | PROTUN -> TMPB DLY IN+D +5E8 G I L NO QRS 5 78 &| EIP -> OPR_W WR +5E9 D F N STUV YZ | SIGMA NEGWSZ ADD +5EA CDEF NO Q WXY 34 | JMP_FAR_COMMON LJUMP DLY +5EB AB D H LMN STU W Y | SIGMA -> eSP TMPB PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +5EC C E XYZ | -2 LDBSRM 0 MORE_PRIV16 +5ED N STU WXYZ | SIGMA 0 SHIFT +5EE A CD U X Z | FOUND_STACK JMP +5EF CDE I KL N ST VW Y 34 67 &| SIGMA DES_TR 2 BITS16 DLY IN=+ +------------------------------------------|---------------------------------------------------------------------------------------------- +5F0 A E OPQR WXY | #GP/#TS(I0,E0) LJUMP 0 GENERAL_FAUL2P +5F1 B GH JK N PQR V X | TMPH -> SLCTR2 SET_FAULT PTGEN +------------------------------------------|---------------------------------------------------------------------------------------------- +5F2 BC E N PQR TUV XYZ | TMPH 3 AND 0 PUSH_V86_SREGS +5F3 G I L OP R 5 789 | GS -> OPR_W WR W +5F4 G JK MN S 345 9 | SIGMA -> COUNTR DLY IN+D +5F5 G I L OP RS 5 789 | FS -> OPR_W WR W +5F6 DE UVW Y 345 9 | GENERAL_FAUL2P JCNTNZ DLY IN+D +5F7 G I L OPQ 5 789 | DS -> OPR_W WR W +5F8 345 9 | DLY IN+D +5F9 A CDE G I L OPQRS U X Z 5 789 | ES -> OPR_W MORE_PRIV2 JMP WR W +5FA 345 9 | DLY IN+D +------------------------------------------|---------------------------------------------------------------------------------------------- +5FB CD GHI MNO Q T VW 345 | TMPB -> TMPE 4 BITS32 DLY IN+= 0 MORE_PRIVILEGE +5FC A E G I L N P R XYZ 5 789 | PROTUN -> OPR_W 0x5d LDBSRM WR W +5FD B EFGH J L N PQ V X | SLCTR2 -> PROTUN WRITE_RPL PTGEN +5FE B E GH J LMNO RS UVWXYZ 2 | TMPC -> MDTMP4 MORE_PRIV16 J16BIT RPT +5FF BC E GH JKL N P R TUV XYZ | PROTUN -> TMPH 3 AND +600 N STU WXYZ | SIGMA 0 SHIFT +601 DE I KL N S 34 67 &| SIGMA DES_TR WORDSZ DLY IN=+ +602 GH JK O QR T WXYZ 5 7 &| TR -> SLCTR2 STSSAF RD 0 FOUND_STACK +603 345 9 | DLY IN+D +604 GHI L O R 3 5 7 9 | OPR_R -> TMPD UNL RD W +605 A EF IJKL VWX 34 89 | DES_CS TST_DES_MOREPR PTSAV3 DLY SPTR +606 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +607 AB DE G J L O R V X Z 3 | OPR_R -> SLCTR TST_SEL_MOREPR PTSELA UNL +608 AB EF T X Z 6 | TMPC CTSSAF SDEL +609 CD F N P WX | PUSH_V86_SREGS LJMPVM +60A D F H KLMNO R 34 67 &| TMPD DESCSW NEGWSZ DLY IN=+ +60B AB DE G I L OPQ S U WX 5 789 | SS -> OPR_W MORE_PRIV_INT JMISC1 WR W 0 MORE_PRIV2 +60C ABC EFGHI L N P RSTUV YZ 345 9 | COUNTR -> TMPD ESP ADD DLY IN+D +60D A C E G I L NOP RS UVW YZ 5 78 &| ESP -> OPR_W COPY_PRMS_SKIP JCNTZ WR +60E 345 9 | DLY IN+D +60F ABCD U W Y | MORE_PRIV3 JMISC2 +610 AB E N STUV YZ | SIGMA TMPD ADD +611 AB E N STUV YZ | SIGMA TMPD ADD +612 AB E N STUV YZ | SIGMA TMPD ADD +613 ABC E H LMN S U X Z | SIGMA -> eSP COPY_PARAMS JMP 0 MORE_PRIV3 +614 GHI L O S 5 | IRF2 -> TMPD 0 IN+= +------------------------------------------|---------------------------------------------------------------------------------------------- +615 G I L NOP RS 5 78 &| ESP -> OPR_W WR 0 MORE_PRIV_INT +616 A C F N PQRSTUV XYZ 345 9 | FLAGSB 0x37fd7 AND DLY IN+D +617 AB D G I L N S U X Z 5 78 &| SIGMA -> OPR_W COPY_PRMS_SKIP JMP WR +618 T V 345 9 | CLT DLY IN+D +------------------------------------------|---------------------------------------------------------------------------------------------- +619 D F H K MNOP RSTUV YZ 34 67 &| ESP DESSTK NEGWSZ ADD DLY IN=+ 0 COPY_PARAMS +61A H LMN ST 5 7 &| SIGMA -> eSP DECNTR RD +61B H KLMNO R TUV YZ 34 67 9 | TMPD DESCSW 0 ADD DLY IND= +61C ABC E GHI L N S UVW YZ 5 8 &| SIGMA -> TMPD COPY_PRMS_DONE JCNTZ wr +61D D F H K MNOP RSTUV YZ 34 67 &| ESP DESSTK NEGWSZ ADD DLY IN=+ +61E H LMN ST 5 7 &| SIGMA -> eSP DECNTR RD 0 COPY_PRMS_LOOP +61F D F H KLMNO R TUV YZ 34 67 &| TMPD DESCSW NEGWSZ ADD DLY IN=+ +620 E GHI L N S UVW Y 3 5 8 &| SIGMA -> TMPD COPY_PRMS_LOOP JCNTNZ UNL wr +621 D F H K MNOP RSTUV YZ 34 67 &| ESP DESSTK NEGWSZ ADD DLY IN=+ +622 D F H KLMNO R 3 67 &| TMPD DESCSW NEGWSZ UNL IN=+ 0 COPY_PRMS_DONE +623 G I L OPQR 5 789 | CS -> OPR_W WR W 0 COPY_PRMS_SKIP +624 D F 345 | NEGWSZ DLY IN+= +625 AB D G I L NO QRST Z 5 78 &| EIP -> OPR_W TMPB LDCNTR WR +626 ABC EF H N PQ S U W Z 34 | TMPG -> eIP NO_ERROR_CODE JNERRC DLY +627 GH J L NO ST VW | TMPE -> PROTUN BITS32 +628 CD FGHI L NO X Z | TMPF -> TMPD 0x10 LDBSRU +629 AB E QRSTU WXYZ 345 9 | 0 TMPD SHIFT DLY IN+D +62A G I L N S 5 789 | SIGMA -> OPR_W WR W +62B B FGHI L N R V X 34 | MDTMP -> TMPD COPY_STACK_DPL PTGEN DLY 0 NO_ERROR_CODE +62C CD FGH JK M O S X Z 5 9 | IRF2 -> TMPG 0x10 LDBSRU IN+D +62D AB E IJKL NO STU WXYZ 6 9 | TMPE DES_CS TMPD SHIFT SDEH +62E GHI K N S | SIGMA -> TMPB +62F AB D 6 &| TMPB SDES +630 AB E GHI K N PQ S 6 | TMPG -> TMPB TMPD SDEL +631 D L N QRS WX 789&| PAGER5 ZERO_V86_SREGS LJMPVM SPCR +632 C F NO QR TUV XYZ 34 | EFLAGS 0xffff AND DLY +633 GHI KL N S | SIGMA -> EFLAGS 0 MORE_PRIV_DONE +634 H KL NO QRS 34 67 9 | EIP DESCOD DLY IND= +635 AB EF N P RSTU WXYZ 5 9&| COUNTR TMPC SHIFT PREF +636 GHI L N S 34 | SIGMA -> TMPD DLY +637 AB D IJK MN P RSTU W Y 6 9 | COUNTR DES_SS TMPB PASS2 SDEH +638 AB E G IJK MN PQ 6 &| SLCTR2 -> SS TMPD SDES +639 AB EFG IJKL N PQR 012 6 | TMPH -> CS TMPC RNI SDEL +63A H LMN S | SIGMA -> eSP +------------------------------------------|---------------------------------------------------------------------------------------------- +63B G IJK QRS 34 789 | 0 -> DS DLY SAR 0 ZERO_V86_SREGS +63C G IJKLM QRS 789 | 0 -> ES SAR +63D C E G IJ LM QRS U X Z 789 | 0 -> FS MORE_PRIV_DONE JMP SAR +63E G IJ L QRS 789 | 0 -> GS SAR +------------------------------------------|---------------------------------------------------------------------------------------------- +63F H K MN S 34 67 9 | SIGMA DESSTK DLY IND= 0 IRETd_V86 +640 C F TU W Y 5 7 | 0xffff PASS2 RD D +641 CD GH J LMN S 345 | SIGMA -> MDTMP4 4 DLY IN+= +642 A EFGHIJ LM O R X 3 5 7 | OPR_R -> ESP 0x0d LDBSLU UNL RD D +643 BC E QRSTU WXYZ 345 9 | 0 3 SHIFT DLY IN+D +644 GHI K O R 3 5 7 | OPR_R -> TMPB UNL RD D +645 BCD N STUV XY 345 9 | SIGMA 0x8200 OR DLY IN+D +646 GHI L O R 3 5 7 | OPR_R -> TMPD UNL RD D +647 GHI LMN S 345 9 | SIGMA -> TMPC DLY IN+D +648 GHI M O R 3 5 7 | OPR_R -> TMPE UNL RD D +649 HI KLMN PQ S 345 9 | TMPG -> IP DLY IN+D +64A GH JK O R 3 5 7 | OPR_R -> SLCTR2 UNL RD D +64B B FGH J L V 34 | -1 -> PROTUN COPY_STACK_DPL PTF DLY +64C IJKL NO RS 789 | TMPC DES_CS SAR +64D IJKL N P RS 6 9&| COUNTR DES_CS SBRM +64E IJKL N R 78 | MDTMP DES_CS SLIM +64F L 789&| PAGER5 SPCR +650 IJKL NO QRS 34 67 9 | EIP DES_CS DLY IND= +651 N P RSTU W YZ 5 9&| COUNTR PASS PREF +652 B FG IJ LMN PQ T Z 34 6 9&| SLCTR2 -> FS 0x65 LDCNTR DLY SBRM +653 G IJK NO S 6 9&| TMPE -> DS SBRM +654 G IJK MNO Q 6 9&| TMPB -> SS SBRM +655 G IJKLMNO R 6 9&| TMPD -> ES SBRM +656 G IJ L O R 3 6 9&| OPR_R -> GS UNL SBRM +657 IJKLMNO RS 789 | TMPC DES_ES SAR 0 IRETd_V86_LOOP +658 FG KL NO RS UVW Z 789 | TMPC -> IRF IRETd_V86_LOOP JCT4N1 SAR +659 G KL N R T 78 | MDTMP -> IRF DECNTR SLIM +65A IJKLMN R 012 78 | MDTMP DES_ES RNI SLIM +65B G IJKL N S | SIGMA -> CS +------------------------------------------|---------------------------------------------------------------------------------------------- +65C A E GHI L N ST Z | SIGMA -> TMPD 0x5d LDCNTR 0 TASK_RETURN +65D A C TUV X Z | -1 0x4000 XOR +65E GHI K N ST XYZ | SIGMA -> TMPB FLGSBA +65F AB D GH JKLMNO QR TUV XYZ | EFLAGS -> FLAGSB TMPB AND +660 GHI KL N S | SIGMA -> EFLAGS +661 BC EF N RS WXYZ | SAVE_TASK LCALL +662 CDEF N P RSTUV Z | COUNTR 1 SUB +663 I KL T X 34 67 9&| DES_TR 0 CTSKS DLY IN=2 +664 T WXYZ 5 7 9 | STSSAF RD W +665 A F I KL VWXY 34 89 | DES_TR TST_DES_TSSTSR PTSAV1 DLY SPTR +666 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +667 ABC FG J L O R V X Z 3 | OPR_R -> SLCTR TST_SEL_GDT PTSELA UNL +668 AB EFGH JK MN PQ T VW 6 | SLCTR2 -> TMPG TMPC BITS32 SDEL +669 CD FGHI LM O QR X | TR -> TMPC 0x10 LDBSLU +66A AB EF QRSTU WXYZ | 0 TMPC SHIFT +66B GHI LMN S | SIGMA -> TMPC +66C C F N PQ STUV XYZ | TMPG 0xffff AND +66D ABCD UVWXYZ | LOAD_TASK_16B J16BIT +66E AB EF I K MN S 34 67 &| SIGMA DESABS TMPC DLY IN=+ +66F A D F N R WXY 89&| LOAD_TASK_32 LJUMP TSDB +670 B DEF I KL 34 67 9&| DES_TR 0x60 DLY IN=2 +------------------------------------------|---------------------------------------------------------------------------------------------- +671 BC E N R WXY 89&| LOAD_TASK_16A LJUMP TSDB 0 LOAD_TASK_16B +672 B D T Z | 0x29 LDCNTR +------------------------------------------|---------------------------------------------------------------------------------------------- +673 B DEF U X | TASK_RETURN JNT 3 p IRETd +674 T VWX | CLRNMI +675 DE N STUV YZ 5 7 &| SIGMA WORDSZ ADD RD +676 DE 345 | WORDSZ DLY IN+= +677 DE N STUV YZ 5 7 &| SIGMA WORDSZ ADD RD +678 GH JK M O R 3 | OPR_R -> TMPG UNL +679 GH JKLMNO QR T XYZ 345 9 | EFLAGS -> FLAGSB FLGSBA DLY IN+D +67A G JK M O R 3 5 7 &| OPR_R -> COUNTR UNL RD +67B 34 | DLY +67C HI KL O R 3 | OPR_R -> FLAGS UNL +67D 34 | DLY +67E N QRS WX | IRETd_V86 LJMPVM +67F A DEF IJKL VWX 34 89 | DES_CS TST_DES_RETF PTSAV3 DLY SPTR 0 RETF_PM +680 H LMN S | SIGMA -> eSP +681 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +682 ABCD FG J L N P RS V Z 34 | COUNTR -> SLCTR TST_SEL_RET PTSELE DLY +683 AB EF N P RSTU W YZ 6 | COUNTR TMPC PASS SDEL +684 CDE L NO Q WXY 789&| PAGER5 JMP_FAR_DONE LJUMP SPCR +685 H KL N PQ S 34 67 9 | TMPG DESCOD DLY IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +686 AB F N P WXYZ 567 | LD_DESCRIPTOR2 LCALL rd D 0 RETF_OUTER_LEV +687 A CDEFGH J L O R V XYZ 3 | OPR_R -> PROTUN TST_DES_SIMPLE PTOVRR UNL +688 AB EFGHI K N P RS 6 | COUNTR -> TMPB TMPC SDEL +689 A EF L X 789&| PAGER5 0x0d LDBSLU SPCR +68A H K MNOP RS 34 67 9 | ESP DESSTK DLY IND= +68B AB D QRSTU WXYZ 5 7 &| 0 TMPB SHIFT RD +68C DE GH JKL N P RS 345 | COUNTR -> TMPH WORDSZ DLY IN+= +68D B FGH J L N S V X 5 7 &| SIGMA -> PROTUN COPY_STACK_DPL PTGEN RD +68E AB DE O R TUV YZ 3 | OPR_R IMM ADD UNL +68F H KL N PQ S 34 67 9 | TMPG DESCOD DLY IND= +690 B GHI L N ST Z 5 9&| SIGMA -> TMPD 0x1f LDCNTR PREF +691 A DE IJK M VWX 34 89 | DES_SS TST_DES_RTOLSS PTSAV3 DLY SPTR +692 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +693 ABCD G J L O R V X Z 3 | OPR_R -> SLCTR TST_SEL_RET_OL PTSELA UNL +694 AB EFG IJK MN PQ 6 | SLCTR2 -> SS TMPC SDEL +695 CDEF IJKLMN P RSTUV YZ 34 7 9 | COUNTR DES_ES 1 ADD DLY LAR +696 BC E GH J L O S V | IRF2 -> PROTUN TST_DES_RTOLOS PTF +697 A DE N Q S WXYZ | RETF_OL_ES LCALL +698 G JK MN S | SIGMA -> COUNTR +699 BC E IJK N P RSTUV YZ 7 9 | COUNTR DES_DS 3 ADD LAR 0 RETF_OL_ES +69A BC E GH J L O S V | IRF2 -> PROTUN TST_DES_RTOLOS PTF +69B A E N Q S WXYZ | RETF_OL_DS LCALL +69C G JK MN S | SIGMA -> COUNTR +69D CDEF IJ LMN P RSTUV YZ 7 9 | COUNTR DES_FS 1 ADD LAR 0 RETF_OL_DS +69E BC E GH J L O S V | IRF2 -> PROTUN TST_DES_RTOLOS PTF +69F BCDE N Q S WXYZ | RETF_OL_FS LCALL +6A0 G JK MN S | SIGMA -> COUNTR +6A1 CDEF IJ L N P RSTUV YZ 7 9 | COUNTR DES_GS 1 ADD LAR 0 RETF_OL_FS +6A2 BC E GH J L O S V | IRF2 -> PROTUN TST_DES_RTOLOS PTF +6A3 BC E N Q S WXYZ | RETF_OL_GS LCALL +6A4 G JK MN S | SIGMA -> COUNTR +6A5 AB E G IJKL N PQR TU W Y | TMPH -> CS TMPD PASS2 0 RETF_OL_GS +6A6 H N PQ S 012 | TMPG -> eIP RNI +6A7 H LMN S | SIGMA -> eSP +------------------------------------------|---------------------------------------------------------------------------------------------- +6A8 YZ | RETURN 0 ZERO_SLCTR_AR +6A9 G KL QRS 6 9 | 0 -> IRF 0 SDEH +------------------------------------------|---------------------------------------------------------------------------------------------- +6AA B D GH J L S V X Z 5 7 9 | SRCREG -> PROTUN READ_RPL PTSELA RD W 1 p ARPL mw,rw +6AB 2 | RPT +6AC 34 | DLY +6AD ABC E GH J L O R V X Z 3 | OPR_R -> PROTUN TST_SEL_ARPL PTSELA UNL +6AE 2 | RPT +6AF =====================================| +6B0 G I L N P R T V XY 5 789 | PROTUN -> OPR_W SEZF WR W +6B1 012 | RNI +6B2 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +6B3 T V XYZ | CLZF 0 ARPL_FAILED +6B4 012 | RNI +6B5 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +6B6 B D GH J L S V X Z | SRCREG -> PROTUN READ_RPL PTSELA 0 p ARPL rw,rw +6B7 2 | RPT +6B8 =====================================| +6B9 ABC E GH J L R V X Z | DSTREG -> PROTUN TST_SEL_ARPL PTSELA +6BA 2 | RPT +6BB =====================================| +6BC G L N P R T V XY 012 | PROTUN -> DSTREG SEZF RNI +6BD =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +6BE ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 1 p LTR mw +6BF =====================================| +6C0 5 7 9 | RD W +6C1 ABCD U X Z 34 | LTR_COMMON JMP DLY +6C2 G J L O R 3 | OPR_R -> SLCTR UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +6C3 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 p LTR rw +6C4 G J L R | DSTREG -> SLCTR +6C5 A I KL VWXY 34 89 | DES_TR TST_DES_TSSLTR PTSAV1 DLY SPTR 0 LTR_COMMON +6C6 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +6C7 ABC F N PQ V X Z | SLCTR2 TST_SEL_GDT PTSELA +6C8 AB EFG I KL N PQ 34 6 | SLCTR2 -> TR TMPC DLY SDEL +6C9 CD HI M P R 67 &| SLCTR DESSDT 4 IN=+ +6CA BCD N P R TUV XY | PROTUN 0x8200 OR +6CB G I L N S 012 5 789 | SIGMA -> OPR_W RNI WR W +6CC 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +6CD G I L O QR 012 5 789 | TR -> OPR_W RNI WR W 1 p STR mw +6CE 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +6CF G L O QR 012 | TR -> DSTREG RNI 0 p STR rw +6D0 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +6D1 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 1 p LLDT mw +6D2 =====================================| +6D3 5 7 9 | RD W +6D4 ABCD U X Z 34 | 6D8 JMP DLY +6D5 G J L O R 3 | OPR_R -> SLCTR UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +6D6 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 p LLDT rw +6D7 G J L R | DSTREG -> SLCTR +6D8 A D IJ M VWXY 34 89 | DESLDT TST_DES_LDT PTSAV1 DLY SPTR +6D9 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +6DA ABC N P R V X Z | PROTUN TST_SEL_LLDT PTSELA +6DB AB EFG IJ MN PQ 012 6 | SLCTR2 -> LDTR TMPC RNI SDEL +6DC =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +6DD G IJ MN PQ 3 5 7 | SLCTR2 -> LDTR UNL RD D 0 LLDT_TEST_PASS +6DE IJ M QRS 01234 6 9 | 0 DESLDT 0 RNI DLY SDEH +6DF 3 | UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +6E0 G I L OP S 012 5 789 | LDTR -> OPR_W RNI WR W 1 p SLDT mw +6E1 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +6E2 G L OP S 012 | LDTR -> DSTREG RNI 0 p SLDT rw +6E3 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +6E4 AB EF N RS WXYZ 5 7 9 | LAR_LSL_VERRWM LCALL RD W 1 p LAR rv,mv +6E5 CDEF VWXY 34 89 | TST_DES_LAR PTSAV1 DLY SPTR +6E6 G MN S | SIGMA -> SRCREG +6E7 AB F N RS WXYZ | LAR_LSL_VERRWR LCALL 0 p LAR rv,rv +6E8 CDEF VWXY 34 89 | TST_DES_LAR PTSAV1 DLY SPTR +6E9 G MN S | SIGMA -> SRCREG +6EA AB EF N RS WXYZ 5 7 9 | LAR_LSL_VERRWM LCALL RD W 1 p LSL rv,mv +6EB CDE VWXY 34 89 | TST_DES_LSL PTSAV1 DLY SPTR +6EC AB F N RS WXYZ | LAR_LSL_VERRWR LCALL 0 p LSL rv,rv +6ED CDE VWXY 34 89 | TST_DES_LSL PTSAV1 DLY SPTR +6EE T VW 34 | BITS32 DLY 0 LSL_HELPER +6EF A DE GHI K N PQ X Z 3 | SLCTR2 -> TMPB 8 LDBSRU UNL +6F0 AB D QRSTU WXYZ | 0 TMPB SHIFT +6F1 BCDEFGH J L N S V | SIGMA -> PROTUN TST_DES_GRANUL PTF +6F2 C F N PQ STUV XYZ | TMPG 0xffff AND +6F3 GHI K N S | SIGMA -> TMPB +6F4 A D N PQ TUV XYZ | SLCTR2 0xf0000 AND +6F5 AB D N STUV XY | SIGMA TMPB OR 0 LSL_GRANULARITY_COARSE +6F6 CDEF N STUV YZ | SIGMA 1 ADD +6F7 A EFGHI LMN STU W Y | SIGMA -> TMPC 0x0d PASS2 +6F8 C EF N STUV YZ | SIGMA -1 ADD +6F9 GHI L N S | SIGMA -> TMPD +6FA AB E GHI K QRS X | 0 -> TMPB TMPD LDBSLU +6FB AB EF QRSTU WXYZ | 0 TMPC SHIFT +6FC C EF N STUV YZ | SIGMA -1 ADD +6FD T V X Z | BITSDE 0 LSL_GRANULARITY_FINE +6FE AB D N STUV XY 012 | SIGMA TMPB OR RNI +6FF G MN ST V XY | SIGMA -> SRCREG SEZF +------------------------------------------|---------------------------------------------------------------------------------------------- +700 AB EF N RS WXYZ 5 7 9 | LAR_LSL_VERRWM LCALL RD W 1 p VERR mw +701 CD F VWXY 34 89 | TST_DES_VERR PTSAV1 DLY SPTR +702 =====================================| +703 AB F N RS WXYZ | LAR_LSL_VERRWR LCALL 0 p VERR rw +704 CD F VWXY 34 89 | TST_DES_VERR PTSAV1 DLY SPTR +705 =====================================| +706 AB EF N RS WXYZ 5 7 9 | LAR_LSL_VERRWM LCALL RD W 1 p VERW mw +707 CD VWXY 34 89 | TST_DES_VERW PTSAV1 DLY SPTR +708 =====================================| +709 AB F N RS WXYZ | LAR_LSL_VERRWR LCALL 0 p VERW rw +70A CD VWXY 34 89 | TST_DES_VERW PTSAV1 DLY SPTR +70B =====================================| +70C ABCD F U X Z 34 | LAR_LSL_VERRW JMP DLY 0 LAR_LSL_VERRWM +70D AB DEFG J L O R V X Z 3 | OPR_R -> SLCTR TST_SEL_LLVV PTSELA UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +70E AB DEFG J L R V X Z 34 | DSTREG -> SLCTR TST_SEL_LLVV PTSELA DLY 0 LAR_LSL_VERRWR +70F CD HI M P R T W 67 &| SLCTR DESSDT 4 SNOFLT IN=+ 0 LAR_LSL_VERRW +710 T VW 2 | BITS32 RPT +711 A DE GHI MN PQ X Z 567 | SLCTR2 -> TMPE 8 LDBSRU rd D +712 C 345 | -4 DLY IN+= +713 BC QRSTU WXYZ 567 | 0 0xffff0000 SHIFT rd D +714 CDEFG J L O R V XYZ 3 | OPR_R -> SLCTR TST_DES_LAR PTOVRR UNL +715 GHI K N ST V X Z 34 | SIGMA -> TMPB BITSDE DLY +716 AB D N PQ TUV XYZ 5 7 9 | SLCTR2 TMPB AND RD W +717 GH JK M O R 3 | OPR_R -> TMPG UNL +718 T V XYZ01234 | CLZF RNI DLY +719 O R 3 | OPR_R UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +71A YZ 34 | RETURN DLY 0 LAR_VERRW_SUCCEEDED +71B O R T V XY 0123 | OPR_R SEZF RNI UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +71C A E I KL VWXY 34 89 | DES_TR TST_DES_TSSTSG PTSAV1 DLY SPTR 0 TASKGATE +71D AB DE N P WXY | LD_DESCRIPTOR LJUMP +71E AB D FG J L N S V X Z 34 | SIGMA -> SLCTR TST_SEL_TASKGT PTSELA DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +71F GH JK MN S | SIGMA -> TMPG 0 AVAIL_TSS +720 BCD N P R TUV XY | PROTUN 0x8200 OR +721 GH J L N S | SIGMA -> PROTUN +722 AB DE N R WXY | SWITCH_TASK LJUMP +723 N PQ STU W YZ | TMPG PASS +------------------------------------------|---------------------------------------------------------------------------------------------- +724 ABC FGH JK O QR UVWXYZ | TR -> SLCTR2 SAVE_TASK_16 J16BIT 0 SAVE_TASK +725 T VW Y | BITS16 +726 I KL N ST W YZ 34 67 9 | SIGMA DES_TR STSKS DLY IND= +727 G I L OP R T VW 5 789 | GS -> OPR_W BITS32 WR W +728 D F T WXYZ 345 | NEGWSZ STSSAF DLY IN+= +729 ABC EFG I L OP RS U X Z 5 789 | FS -> OPR_W SAVE_TASK_COMM JMP WR W +72A 345 9 | DLY IN+D +------------------------------------------|---------------------------------------------------------------------------------------------- +72B B D T Z | 0x29 LDCNTR 0 SAVE_TASK_16 +72C C EF N P RSTUV YZ | COUNTR -1 ADD +72D I KL N ST W YZ 34 67 9 | SIGMA DES_TR STSKS DLY IND= +72E G I L OPQ T WXYZ 5 789 | DS -> OPR_W STSSAF WR W 0 SAVE_TASK_COMM +72F D F 345 | NEGWSZ DLY IN+= +730 G I L OPQ S 5 789 | SS -> OPR_W WR W +731 345 9 | DLY IN+D +732 B EFG I L OPQR T Z 5 789 | CS -> OPR_W 7 LDCNTR WR W +733 345 9 | DLY IN+D +734 G I L OPQRS 5 789 | ES -> OPR_W WR W +735 345 9 | DLY IN+D +736 G I L QR T 5 78 &| IRF -> OPR_W DECNTR WR +737 345 9 | DLY IN+D 0 SAVE_TASK_LOOP +738 F UVW Y | SAVE_TASK_LOOP JCNTNZ +739 G I L QR T 5 78 &| IRF -> OPR_W DECNTR WR +73A A C F NO QR TUV XYZ 345 9 | EFLAGS 0x37fd7 AND DLY IN+D +73B G I L N S 5 78 &| SIGMA -> OPR_W WR +73C A E T Z 345 9 | 0x5d LDCNTR DLY IN+D +73D G I L NO QRS YZ 5 78 &| EIP -> OPR_W RETURN WR +73E T V 345 9 | CLT DLY IN+D +------------------------------------------|---------------------------------------------------------------------------------------------- +73F BC EF N RS WXYZ | SAVE_TASK LCALL 0 CALL_SAVE_TASK +740 CDEF N P RSTUV Z | COUNTR 1 SUB +741 AB F I KL NO Q U X Z 34 6 9 | TMPB DES_TR LOAD_TASK JMP DLY SDEH +742 AB E GH JK N PQ S 6 &| TMPG -> SLCTR2 TMPD SDES +------------------------------------------|---------------------------------------------------------------------------------------------- +743 GH JK MN S | SIGMA -> TMPG 0 AVAIL_TSS_PR +744 BCD N P R TUV XY | PROTUN 0x8200 OR +745 AB D FGH J L N PQ V X Z | SLCTR2 -> PROTUN TST_SEL_TASKGT PTSELA +746 2 | RPT +747 ABCDE GH J L N S U X Z | SIGMA -> PROTUN SWITCH_TASK JMP +748 N PQ STU W YZ | TMPG PASS +------------------------------------------|---------------------------------------------------------------------------------------------- +749 A E GHI L N ST Z | SIGMA -> TMPD 0x5d LDCNTR 0 SWITCH_TASK +74A C F N PQ TUV XYZ 34 | SLCTR2 0xffff AND DLY +74B CD HI M P R T WXYZ 67 &| SLCTR DESSDT 4 STSSAF IN=+ +74C CD FG I L N P R U W YZ 5 789 | PROTUN -> OPR_W CALL_SAVE_TASK JNTSKS WR W +74D GH JK MN S | SIGMA -> TMPG +74E I KL NO Q 34 6 9 | TMPB DES_TR 0 DLY SDEH +74F AB E GH JK N PQ S 6 &| TMPG -> SLCTR2 TMPD SDES +750 AB EF T VW 6 | TMPC BITS32 SDEL 0 LOAD_TASK +751 CD FGHI LM O QR X | TR -> TMPC 0x10 LDBSLU +752 AB EF QRSTU WXYZ | 0 TMPC SHIFT +753 GHI LMN S | SIGMA -> TMPC +754 AB EF I K MN PQ S 34 67 &| TMPG DESABS TMPC DLY IN=+ +755 ABCD F UV Y 89&| TR_BACKLINK_OK JSTSKL TSDB +756 I KL 34 67 9&| DES_TR 0 DLY IN=2 +757 G I L O QR 5 789 | TR -> OPR_W WR W +758 AB D GHI M QRS UVWXYZ | 0 -> TMPE LOAD_TASK_16 J16BIT 0 TR_BACKLINK_OK +759 B DEF I KL T VW 34 67 9&| DES_TR 0x60 BITS32 DLY IN=2 +75A C EF TU W Y 5 7 9 | -1 PASS2 RD W 0 LOAD_TASK_32 +75B C GHI L N S 345 | SIGMA -> TMPD -4 DLY IN+= +75C G IJ M O R 3 5 7 9 | OPR_R -> LDTR UNL RD W +75D 345 9 | DLY IN+D +75E G IJ L O R 3 5 7 9 | OPR_R -> GS UNL RD W +75F 345 9 | DLY IN+D +760 G IJ LM O R 3 5 7 9 | OPR_R -> FS UNL RD W +761 345 9 | DLY IN+D +762 AB D FG IJK O R U X Z 3 5 7 9 | OPR_R -> DS 76D JMP UNL RD W +763 345 9 | DLY IN+D +------------------------------------------|---------------------------------------------------------------------------------------------- +764 B D T Z | 0x29 LDCNTR 0 LOAD_TASK_16 +765 CDEF I KL N P RST VW Y 34 67 &| COUNTR DES_TR 1 BITS16 DLY IN=+ 0 LOAD_TASK_16A +766 C F TU W Y 5 7 9 | 0xffff PASS2 RD W +767 C E GHI L N S 345 | SIGMA -> TMPD -2 DLY IN+= +768 G IJ M O R 3 5 7 9 | OPR_R -> LDTR UNL RD W +769 345 9 | DLY IN+D +76A G IJK O R 3 | OPR_R -> DS UNL +76B G IJ LM QRS 5 7 9 | 0 -> FS RD W +76C G IJ L QRS 345 9 | 0 -> GS DLY IN+D +76D B EFG IJK M O R T Z 3 5 7 9 | OPR_R -> SS 7 LDCNTR UNL RD W +76E AB E TUV Z 345 9 | -1 TMPD SUB DLY IN+D +76F G IJKL O R 3 5 7 9 | OPR_R -> CS UNL RD W +770 D FGHI LMN S 345 | SIGMA -> TMPC NEGWSZ DLY IN+= +771 G IJKLM O R 3 5 7 &| OPR_R -> ES UNL RD +772 GHI M QRS 345 9 | 0 -> TMPE DLY IN+D +773 AB EF O R TUV XY 3 5 7 &| OPR_R TMPC OR UNL RD 0 LOAD_TASK_LOOP +774 FG KL N S UVW Y 345 9 | SIGMA -> IRF LOAD_TASK_LOOP JCNTNZ DLY IN+D +775 T | DECNTR +776 B D GH J L OPQR V | CS -> PROTUN READ_RPL PTF +777 AB E O R TUV XYZ 3 5 7 &| OPR_R TMPD AND UNL RD +778 GHI KL N ST Z 345 9 | SIGMA -> EFLAGS 0 LDCNTR DLY IN+D +779 AB D H O R UVWXYZ 3 | OPR_R -> eIP 785 J16BIT UNL +77A NO Q STUV X | CR0 SIGN +77B GHI K N S 5 7 | SIGMA -> TMPB RD D +77C 34 | DLY +77D K 7 9&| PDBR LPCR +77E GHI L O S 34 | IRF2 -> TMPD DLY +77F AB E GHI LM O R TUV Z 3 | OPR_R -> TMPC TMPD SUB UNL +780 B F I KL 34 67 &| -1 DES_TR 0x65 DLY IN=+ +781 AB D N STUV XYZ 5 7 9 | SIGMA TMPB AND RD W +782 G JK MN S 34 | SIGMA -> COUNTR DLY +783 CDEF O R TUV XYZ 3 | OPR_R 1 AND UNL +784 GHI MN S | SIGMA -> TMPE +785 GH J NOP RS | ESP -> TMPeSP +786 GH J MNO QRST XYZ | EIP -> TMPeIP FLGSBA +787 ABC EFGH JK O QR UV Y | TR -> SLCTR2 NOT_NESTED_TSK JSTSKL 0 LOAD_TASK_NOPG +788 A C GH JKLMNO QR TUV XY | EFLAGS -> FLAGSB 0x4000 OR +789 GH JKLMN S | SIGMA -> FLAGSB +78A ABC GHI KL N S U X Z | SIGMA -> EFLAGS SET_TSKSWTCHED JMP +78B G I KL N PQ ST X | TMPG -> TR CTSKS +------------------------------------------|---------------------------------------------------------------------------------------------- +78C N PQ 34 | SLCTR2 DLY 0 NOT_NESTED_TSK +78D CD HI M P R 67 &| SLCTR DESSDT 4 IN=+ +78E G I KL N PQ S 567 9 | TMPG -> TR rd W +78F 34 | DLY +790 A DEF O R TUV XYZ 3 | OPR_R ~0x200 AND UNL +791 G I L N ST X 5 789 | SIGMA -> OPR_W CTSKS WR W +792 ABCD F I K MNO RS UVW YZ 34 67 9 | TMPC DESABS WRITE_BACK_CR0 JCNTZ DLY IND= 0 SET_TSKSWTCHED +793 A DE NO Q STUV XY | CR0 8 OR +794 K 789&| PDBR SPCR +795 B FGHI K MN ST Z | SIGMA -> CR0 0x65 LDCNTR 0 WRITE_BACK_CR0 +796 A C EFGHI LM OPQR U X Z | CS -> TMPC TASK_FINAL_PM JMP +797 A DEF N S WX | TASK_FINAL_V86 LJMPVM +------------------------------------------|---------------------------------------------------------------------------------------------- +798 B FGH J L V | -1 -> PROTUN COPY_STACK_DPL PTF 0 TASK_FINAL_V86 +799 IJ LM OP RS 6 9&| FS DES_FS SBRM +79A IJK OPQ 6 9&| DS DES_DS SBRM +79B IJK M OPQ S 6 9&| SS DES_SS SBRM +79C IJKL OPQR 6 9&| CS DES_CS SBRM +79D C F IJ L OP R TU W Y 6 9&| GS DES_GS 0xffff PASS2 SBRM +79E A EFGH JK MN S X 34 | SIGMA -> TMPG 0x0d LDBSLU DLY +79F BC E QRSTU WXYZ | 0 3 SHIFT +7A0 BCD N STUV XY | SIGMA 0x8200 OR +7A1 IJKLM OPQRS 6 9&| ES DES_ES SBRM +7A2 FG KL N S UVW Z 789 | SIGMA -> IRF 7A1 JCT4N1 SAR +7A3 G KL N PQ ST 78 | TMPG -> IRF DECNTR SLIM +7A4 IJKLMN S 789 | SIGMA DES_ES SAR +7A5 IJKLMN PQ S 78 | TMPG DES_ES SLIM +7A6 A D IJ M VWXY 34 89 | DESLDT TST_DES_LDT PTSAV1 DLY SPTR +7A7 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +7A8 AB E G J L OP S V X Z 34 | LDTR -> SLCTR TST_SEL_TR_TSF PTSELA DLY +7A9 A CDEF N WXY | HANDLE_TS_BP LJUMP +7AA AB EFG JK MNO ST VW 6 | TMPE -> COUNTR TMPC BITS32 SDEL +------------------------------------------|---------------------------------------------------------------------------------------------- +7AB A EF X 34 | 0x0d LDBSLU DLY 0 TASK_FINAL_PM +7AC AB EF IJ M QRSTU WXYZ 789 | 0 DESLDT TMPC SHIFT SAR +7AD B FGH J L N S V | SIGMA -> PROTUN COPY_STACK_DPL PTF +7AE IJ L QRS 789 | 0 DES_GS SAR +7AF IJ LM QRS 789 | 0 DES_FS SAR +7B0 IJK QRS 789 | 0 DES_DS SAR +7B1 IJK M QRS 789 | 0 DES_SS SAR +7B2 IJKLM QRS 789 | 0 DES_ES SAR +7B3 A D F IJ M VWXY 34 89 | DESLDT TST_DES_LDTTSK PTSAV1 DLY SPTR +7B4 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +7B5 AB E G J L OP S V X Z 34 | LDTR -> SLCTR TST_SEL_TR_TSF PTSELA DLY +7B6 AB EF 6 | TMPC SDEL +7B7 A CDE IJK M VW 34 89 | DES_SS TST_DES_SS PTSAV7 DLY SPTR +7B8 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +7B9 AB DE G J L OPQ S V X Z 34 | SS -> SLCTR TST_SEL_MOREPR PTSELA DLY +7BA AB EF 6 | TMPC SDEL +7BB A C EF IJKL VW 34 89 | DES_CS TST_DES_JGDEST PTSAV7 DLY SPTR +7BC AB DE N P WXYZ | LD_DESCRIPTOR LCALL +7BD ABCDE G J L OPQR V Z 34 | CS -> SLCTR TST_SEL_CS PTSELE DLY +7BE AB EF 6 | TMPC SDEL +7BF L 789&| PAGER5 SPCR +7C0 A CDEF IJK VWXY 34 89 | DES_DS TST_DES_SIMPLE PTSAV1 DLY SPTR +7C1 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +7C2 AB D G J L OPQ V X Z 34 | DS -> SLCTR TST_SEL_TASKFI PTSELA DLY +7C3 AB EF 6 | TMPC SDEL +7C4 A CDEF IJKLM VWXY 34 89 | DES_ES TST_DES_SIMPLE PTSAV1 DLY SPTR +7C5 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +7C6 AB D G J L OPQRS V X Z 34 | ES -> SLCTR TST_SEL_TASKFI PTSELA DLY +7C7 AB EF 6 | TMPC SDEL +7C8 A CDEF IJ LM VWXY 34 89 | DES_FS TST_DES_SIMPLE PTSAV1 DLY SPTR +7C9 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +7CA AB D G J L OP RS V X Z 34 | FS -> SLCTR TST_SEL_TASKFI PTSELA DLY +7CB AB EF 6 | TMPC SDEL +7CC A CDEF IJ L VWXY 34 89 | DES_GS TST_DES_SIMPLE PTSAV1 DLY SPTR +7CD AB DE N P WXYZ | LD_DESCRIPTOR LCALL +7CE AB D G J L OP R V X Z 34 | GS -> SLCTR TST_SEL_TASKFI PTSELA DLY +7CF AB EFG JK MNO ST VW 6 | TMPE -> COUNTR TMPC BITS32 SDEL +7D0 ABC F H KL NO QRS U W Z 34 67 9 | EIP DESCOD TSKF_NO_ERRCOD JNERRC DLY IND= 0 HANDLE_TS_BP +7D1 GHI K NO 5 9&| TMPF -> TMPB PREF +7D2 A CDEF UVWXYZ | ADJ_STACK_16 J16BIT +7D3 C H K MNOP RSTUV YZ 34 67 &| ESP DESSTK -4 ADD DLY IN=+ +7D4 CD F H LMN S X Z | SIGMA -> eSP 0x10 LDBSRU 0 ADJ_STACK_DONE +7D5 AB D QRSTU WXYZ | 0 TMPB SHIFT +7D6 G I L N S 5 789 | SIGMA -> OPR_W WR W +7D7 B FGHI K N QR TU W Y 34 | DR7 -> TMPB 0x65 PASS2 DLY 0 TSKF_NO_ERRCOD +7D8 CD F N STUV Z | SIGMA 0x10 SUB +7D9 C EF N STUV X Z | SIGMA -1 XOR +7DA CDE GHI LMN S X | SIGMA -> TMPC 2 LDBSLU +7DB AB EF QRSTU WXYZ | 0 TMPC SHIFT +7DC CDE N STUV XY | SIGMA 2 OR +7DD AB D N STUV XYZ | SIGMA TMPB AND +7DE GH KL N S | SIGMA -> DR7 +7DF AB D GH J MNO QRS UVW Z | EIP -> TMPeIP NO_DEBUG_BP JCT4N1 +7E0 BCD N QRSTUV XY 01 | DR6 0x8200 OR RNi +7E1 ABCDE OP R WXY | BREAKPOINT LJUMP +7E2 GH KLMN S | SIGMA -> DR6 +------------------------------------------|---------------------------------------------------------------------------------------------- +7E3 CDEF U X Z | ADJ_STACK_DONE JMP 0 ADJ_STACK_16 +7E4 C E H K MNOP RSTUV YZ 34 67 &| ESP DESSTK -2 ADD DLY IN=+ +------------------------------------------|---------------------------------------------------------------------------------------------- +7E5 CD 345 | 4 DLY IN+= 0 NULL_SELECTOR2 +7E6 YZ 3 5 89 | RETURN UNL wr W +7E7 HI L QRS 34 6 9 | 0 DESPTR 0 DLY SDEH +------------------------------------------|---------------------------------------------------------------------------------------------- +7E8 AB D FGH J L N PQ V X Z | SLCTR2 -> PROTUN TST_SEL_TASKGT PTSELA 0 AVAIL_TSS_NP +7E9 =====================================| +7EA CDEF OPQR WXY | #NP(I0,E0) LJUMP +7EB =====================================| 0 NO_DEBUG_BP +7EC H KL NO QRS 67 9 | EIP DESCOD IND= 0 CLI_STI +7ED 5 9&| PREF +7EE 34 | DLY +7EF TU WX | FLGOPS 0 CLC/STC/CLD/STD/CMC +7F0 012 | RNI +7F1 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +7F2 H LMN S | SIGMA -> eSP 2 p PUSHFd +7F3 C F NO QR TUV XYZ | EFLAGS 0xffff AND +7F4 A C F N STUV XYZ | SIGMA 0x37fd7 AND +7F5 G I L N S 012 5 78 &| SIGMA -> OPR_W RNI WR +7F6 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +7F7 C EF UV X | CLI_STI JIO_OK 0 CLI/STI +7F8 T VW | BITS32 +------------------------------------------|---------------------------------------------------------------------------------------------- +7F9 DEF UV X | p PUSHFd JIO_OK 2 r PUSHFd +7FA =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +7FB ABC UV X | p POPFd JIO_OK 3 r POPFd +7FC =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +7FD AB D F UV X | p INT ib JIO_OK 0 r INT ib +7FE =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +7FF AB D F UV X | IRET_REAL_MODE JIO_OK 3 r IRETd +800 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +801 A E OPQR WXY | #GP/#TS(I0,E0) LJUMP 0 OVERLONG_INST +802 B GH JK QRS V X | 0 -> SLCTR2 SET_FAULT PTGEN +------------------------------------------|---------------------------------------------------------------------------------------------- +803 H LMN S 5 7 &| SIGMA -> eSP RD 3 p POPFd +804 T VW Y 34 | BITS16 DLY +805 O R TU W YZ 3 | OPR_R PASS UNL +806 HI KL N S 012 | SIGMA -> FLAGS RNI +807 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +808 A OPQ S WXY | INTERRUPT LJUMP 0 p INT ib +809 N TU W YZ | IMM PASS +------------------------------------------|---------------------------------------------------------------------------------------------- +80A DE N STUV YZ 5 7 &| SIGMA WORDSZ ADD RD 0 IRET_REAL_MODE +80B DE GH JKLMNO QR T XYZ 345 | EFLAGS -> FLAGSB WORDSZ FLGSBA DLY IN+= +80C DE N STUV YZ 5 7 &| SIGMA WORDSZ ADD RD +80D GH JK M O R T VWX 3 | OPR_R -> TMPG CLRNMI UNL +80E DE H LMN S 345 | SIGMA -> eSP WORDSZ DLY IN+= +80F C FG JK M O R TU W Y 3 5 7 &| OPR_R -> COUNTR 0xffff PASS2 UNL RD +810 C F N STUV YZ | SIGMA 0xffff ADD +811 C F N STUV XY 34 | SIGMA 0xffff OR DLY +812 GHI K N S | SIGMA -> TMPB +813 AB D O R TUV XYZ 3 | OPR_R TMPB AND UNL +814 B D NO Q WXY 34 | JMP_FAR_RM LJUMP DLY +815 HI KL N S | SIGMA -> FLAGS +------------------------------------------|---------------------------------------------------------------------------------------------- +816 A OPQ S WXY | INTERRUPT LJUMP 0 INT 3 +817 BC E TU W Y | 3 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +818 B EF TU W Y 5 7 &| 7 PASS2 RD 1 BOUND rv,m2v +819 DE GHI K N S 345 | SIGMA -> TMPB WORDSZ DLY IN+= +81A F O R TUV Z 3 5 7 &| OPR_R SRCREG SUB UNL RD +81B 34 | DLY +81C ABC E GHI LM O R U WXY 3 | OPR_R -> TMPC #BR JG UNL +81D AB EF STUV Z | SRCREG TMPC SUB +81E =====================================| +81F ABCD F U WXY | #BR JG +820 012 | RNI +821 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +822 A CDEF OPQ S WXY | FAULT LJUMP 0 #BR +823 C E NO Q TUV YZ | TMPB -2 ADD +------------------------------------------|---------------------------------------------------------------------------------------------- +824 T V YZ | SCNTFF 0 DIVIDE_ERROR +825 A CDEF OPQ S WXY | FAULT LJUMP +826 TU W Y | 0 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +827 ABCD F U YZ | NO_OVERFLOW JNO 0 INTO +828 CD TU W Y 01 | 4 PASS2 RNi +829 A OPQ S WXY | INTERRUPT LJUMP +82A =====================================| 0 NO_OVERFLOW +82B A CDEF OPQ S WXY | FAULT LJUMP 0 #UD +82C BC F TU W Y | 6 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +82D GH J NOP RS Y | ESP -> TMPeSP ICESIG 0 HARDWARE_IRQ +82E CD I K M T VW 34 67 9&| DESABS 4 BITS32 DLY IN=2 +82F A DE GH J MNO QRS X Z 6 89&| EIP -> TMPeIP 8 LDBSRU IACK +830 I K M T V Y 34 67 9&| DESABS 0 CINTLA DLY IN=2 +831 C F QRSTU WXYZ 3 | 0 0xffff SHIFT UNL +832 2 | RPT +833 GHI K N S 6 89&| SIGMA -> TMPB IACK +834 A F OPQ S WXY 34 | INTERRUPT_X LJUMP DLY +835 AB D O R TUV XYZ 3 | OPR_R TMPB AND UNL +------------------------------------------|---------------------------------------------------------------------------------------------- +836 GH J NOP RST VW Z | ESP -> TMPeSP SETNMI 0 NMI +837 A F OPQ S WXY | INTERRUPT_X LJUMP +838 CDE GH J MNO QRSTU W Y | EIP -> TMPeIP 2 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +839 Y | ICESIG 0 TRIPLE_FAULT +83A U Z | TRIPLE_FT_WAIT JICEWT 0 TRIPLE_FT_WAIT +83B =====================================| +83C O R T V YZ | OPR_R SCNTFF +83D B DE NO RS WXY | HLT_SHUTDOWN LJUMP +83E I K M QRS 34 67 9 | 0 DESABS DLY IND= +------------------------------------------|---------------------------------------------------------------------------------------------- +83F C F NO TUV XYZ 34 | TMPF 0xffff AND DLY 0 #DF +840 GHI N ST W Z | SIGMA -> TMPF SERRCF +841 A DE TU W Y | 8 PASS2 +842 A CDEF OPQ S WXY | FAULT LJUMP +843 T V YZ | SCNTFF +------------------------------------------|---------------------------------------------------------------------------------------------- +844 T V YZ | SCNTFF 0 NO_PRIVILEGE +845 T W Z | SERRCF +846 C F NO TUV XYZ | TMPF 0xffff AND +847 A CDEF OPQ S WXY | FAULT LJUMP +848 A EFGHI N STU W Y | SIGMA -> TMPF 0x0d PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +849 B V X | SET_FAULT PTGEN 0 unused? +84A C F NO TUV XYZ | TMPF 0xffff AND +84B T VW | BITS32 +84C =====================================| +84D CD FGHI K N S X | SIGMA -> TMPB 0x10 LDBSLU +84E B EF QRSTU WXYZ | 0 7 SHIFT +84F GHI LMN S 34 | SIGMA -> TMPC DLY +850 K M T W Z 7 9&| PFERRC SERRCF LPCR +851 AB EF O STUV XYZ 34 | IRF2 TMPC AND DLY +852 AB D KL N STUV XY 7 9&| SIGMA PGUNUS TMPB OR LPCR +853 G I K O ST V YZ 34 | IRF2 -> CR2 SCNTFF DLY +854 A EFGHI N STU W Y | SIGMA -> TMPF 0x0d PASS2 +855 A CDEF OPQ S WXY | FAULT LJUMP +856 CDEF N STUV YZ | SIGMA 1 ADD +------------------------------------------|---------------------------------------------------------------------------------------------- +857 I LM 7 9 | DESERR LAR 0 ACCESS_VIOLATI +858 BC EFGH J L V X 7 9 | -1 -> PROTUN TST_ACCESS_VIO PTGEN LAR +859 C N PQ TUV XYZ 2 | SLCTR2 -4 AND RPT +85A T V YZ | SCNTFF +85B C EF OPQR WXY | FAULT_ERR_CODE LJUMP 0 #GP(0) +85C CD GHI M QRSTU W Y | 0 -> TMPE 4 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +85D C N PQ TUV XYZ | SLCTR2 -4 AND 0 #GP/#TS(I0,E0) +85E AB DE U WXYZ | #TS(SIGMA) JTSSAF 0 #GP/#TS(SIGMA) +85F =====================================| +860 C EF OPQR WXY | FAULT_ERR_CODE LJUMP 0 #GP(SIGMA) +861 CD GHI MN STU W Y | SIGMA -> TMPE 4 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +862 TU W Y | 0 PASS2 0 #SS(0) +863 C EF OPQR WXY | FAULT_ERR_CODE LJUMP 0 #SS(SIGMA) +864 BC E GHI MN STU W Y | SIGMA -> TMPE 3 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +865 C N PQ TUV XYZ | SLCTR2 -4 AND 0 #GP(I1,E0) +866 DE U X Z | #GP(SIGMA) JMP 0 #GP(SIGMA | 2) +867 CDE N STUV XY | SIGMA 2 OR +------------------------------------------|---------------------------------------------------------------------------------------------- +868 C EF OPQR WXY | FAULT_ERR_CODE LJUMP 0 #TS(SIGMA) +869 CDEFGHI MN STU W Y | SIGMA -> TMPE 1 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +86A C N PQ TUV XYZ | SLCTR2 -4 AND 0 #SS(I0,E0) +86B AB DEF U X Z 34 | FAULT_ERR_CODE JMP DLY +86C BC E GHI MN STU W Y | SIGMA -> TMPE 3 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +86D U Z | FAULT_SUPPRESS JICEWT 0 FAULT_SUPPRESS +86E T V XYZ012 | CLZF RNI 0 LAR_LSL_VERRW_NULL_SELECTOR +86F O R | OPR_R +------------------------------------------|---------------------------------------------------------------------------------------------- +870 ABCD F U X Z | NP_COMMON JMP 0 #NP(I0,E0) +871 C N PQ TUV XYZ | SLCTR2 -4 AND 0 #NP(I1,E0) +872 CDE N STUV XY | SIGMA 2 OR +873 CDE GHI MN STU W Y 34 | SIGMA -> TMPE 2 PASS2 DLY 0 NP_COMMON +874 DEF U W | FAULT_SUPPRESS JNOFLT 0 FAULT_ERR_CODE +875 B D F N STUV YZ | SIGMA 9 ADD +876 T V YZ | SCNTFF +877 GHI LMN ST VW | SIGMA -> TMPC BITS32 +878 ABCD F UV YZ | EXT_BIT_DONE JEXTFT +879 CDEF NO STUV XY | TMPE 1 OR +87A C E NO STUV XYZ | TMPE -2 AND +87B CD FGHI K N S X | SIGMA -> TMPB 0x10 LDBSLU 0 EXT_BIT_DONE +87C AB D QRSTU WXYZ | 0 TMPB SHIFT +87D GHI K N ST W Z | SIGMA -> TMPB SERRCF +87E C F NO TUV XYZ | TMPF 0xffff AND +87F AB D N STUV XY | SIGMA TMPB OR +880 AB GHI N S U X Z | SIGMA -> TMPF FAULT JMP +881 NO RSTU W YZ | TMPC PASS +------------------------------------------|---------------------------------------------------------------------------------------------- +882 CDEF N P RSTUV YZ | COUNTR 1 ADD 0 STRING_CORRECT +883 DE GHI K N STU W Y | SIGMA -> TMPB WORDSZ PASS2 +884 D G JK MN STUV Z | SIGMA -> COUNTR INCREM SUB +885 GHI LM PQR T Y | eCX -> TMPC CREPF +886 ABCD FG JKL NO Q U WXY | TMPB -> eCX STRCORR_DOWN JG +887 AB EF NO Q TUV Z | TMPB TMPC SUB +888 AB D NO RSTUV Z | TMPC TMPB SUB +889 ABC FGHI LMN STUV YZ | SIGMA -> TMPC ESI ADD 0 STRCORR_DOWN +88A G J MN ST | SIGMA -> eSI DECNTR 0 STRCORR_LOOP +88B ABC NO RSTUV YZ | TMPC EDI ADD +88C E G J N S UVW Y | SIGMA -> eDI STRCORR_LOOP JCNTNZ +88D ABC F NO RSTUV YZ | TMPC ESI ADD +88E AB U X Z | INTERRUPT_X JMP +88F NO R TU W YZ | TMPD PASS +------------------------------------------|---------------------------------------------------------------------------------------------- +890 ABCD F IJK M U XYZ 34 7 9 | DES_SS FLAGS_OK JNFLGB DLY LAR 0 FAULT +891 B FGH J L O S V X | IRF2 -> PROTUN COPY_STACK_DPL PTGEN +892 GHI KL N PQRS | FLAGSB -> EFLAGS +893 ABC FGHI L N S U WXYZ | SIGMA -> TMPD RESUME_FLAG_OK JTSSAF 0 FLAGS_OK +894 GHI KLMN P S Y | TMPeIP -> EIP ICESIG +895 C F TU W Y | 0xffff PASS2 +896 CDEF N STUV YZ | SIGMA 1 ADD +897 GHI K N S | SIGMA -> TMPB +898 AB D NO QR TUV XY | EFLAGS TMPB OR +899 AB E GHI KL N STU W Y | SIGMA -> EFLAGS TMPD PASS2 +89A GHIJ LMN P U Z | TMPeSP -> ESP RESUME_FLAG_OK JICEWT 0 RESUME_FLAG_OK +89B O R T X Z | OPR_R CTSSAF +89C BC E U XY | STRING_CORRECT JREP +89D GHI L N ST V X Z | SIGMA -> TMPD BITSDE +89E T WX Z | SINTHW 0 INTERRUPT_X +89F Y | ICESIG 0 INTERRUPT +8A0 CDEF OPQ S W YZ | INTERRUPT_PM LJMPP +8A1 T VW | BITS32 +8A2 CDEF OPQ S WX | INTERRUPT_PM LJMPVM +8A3 CDE GHI K N S X | SIGMA -> TMPB 2 LDBSLU +8A4 AB D QRSTU WXYZ | 0 TMPB SHIFT +8A5 I KLMN S 34 67 9 | SIGMA DESIDT DLY IND= +8A6 GH JKLMNO QR T XYZ 5 7 | EFLAGS -> FLAGSB FLGSBA RD D +8A7 IJKL T V Z 34 7 | DES_CS CLI DLY LLIM +8A8 GHI LM O S | IRF2 -> TMPC +8A9 CD FGHI K O R XYZ 3 | OPR_R -> TMPB 0x10 LDBSRM UNL +8AA AB D QRSTU WXYZ | 0 TMPB SHIFT +8AB GH J L N S | SIGMA -> PROTUN +8AC IJKL N P R 6 9&| PROTUN DES_CS SBRM +8AD IJKL NO RST VW Y 78 | TMPC DES_CS BITS16 SLIM +8AE A C E L OPQ WXY 789&| PAGER5 TRAP_INT_GATE LJUMP SPCR +8AF GH JK MNO Q | TMPB -> TMPG +------------------------------------------|---------------------------------------------------------------------------------------------- +8B0 BC E GHI K N S X | SIGMA -> TMPB 3 LDBSLU 0 INTERRUPT_PM +8B1 AB D QRSTU WXYZ | 0 TMPB SHIFT +8B2 CD I KLMN ST WX 34 67 &| SIGMA DESIDT 4 SMISC1 DLY IN=+ +8B3 CD FGH JK N S X Z 567 | SIGMA -> SLCTR2 0x10 LDBSRU rd D +8B4 C GH JKLMNO QR T XYZ 345 | EFLAGS -> FLAGSB -4 FLGSBA DLY IN+= +8B5 BC GH J L O R TUV XYZ 3 567 | OPR_R -> PROTUN 0xffff0000 AND UNL rd D +8B6 AB DEFGHI K N S U WX Z 34 | SIGMA -> TMPB INTERRUPT_SW JINTSW DLY +8B7 C FGHI L O R TUV XYZ 3 | OPR_R -> TMPD 0xffff AND UNL +8B8 AB D N STUV XY | SIGMA TMPB OR +8B9 BCD FGH JK MN S V | SIGMA -> TMPG TST_DES_INT_HW PTF +8BA AB E QRSTU WXYZ | 0 TMPD SHIFT 0 INTERRUPT_COMM +8BB GH JKL N S | SIGMA -> TMPH +8BC A C IJKL VW 34 89 | DES_CS TST_DES_CGDEST PTSAV7 DLY SPTR +8BD BC E OPQR WXY | #GP(I1,E0) LJUMP +8BE B D F V X | JMP_GFAULT_INT PTGEN +------------------------------------------|---------------------------------------------------------------------------------------------- +8BF AB D N STUV XY | SIGMA TMPB OR 0 INTERRUPT_SW +8C0 DE U X Z | INTERRUPT_COMM JMP +8C1 BCDE GH JK MN S V | SIGMA -> TMPG TST_DES_INT_SW PTF +------------------------------------------|---------------------------------------------------------------------------------------------- +8C2 T V Z | CLI 0 INTGATE286 +8C3 A C TUV X Z | -1 0x4000 XOR 0 TRAPGATE286 +8C4 GHI K N ST W Y | SIGMA -> TMPB SMISC2 +8C5 AB D NO QR TUV XYZ | EFLAGS TMPB AND +8C6 GHI KL N S | SIGMA -> EFLAGS +8C7 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +8C8 ABCDE G J L N PQR V Z 34 | TMPH -> SLCTR TST_SEL_CS PTSELE DLY +8C9 AB DE U X Z | 8D3 JMP +8CA AB EFGH J L N PQR T VW Y 34 6 | TMPH -> PROTUN TMPC BITS16 DLY SDEL +------------------------------------------|---------------------------------------------------------------------------------------------- +8CB T V Z | CLI 0 INTGATE386 +8CC A C TUV X Z | -1 0x4000 XOR 0 TRAPGATE386 +8CD GHI K N ST YZ | SIGMA -> TMPB CMISC2 +8CE AB D NO QR TUV XYZ | EFLAGS TMPB AND +8CF GHI KL N S | SIGMA -> EFLAGS +8D0 AB DE N P WXYZ | LD_DESCRIPTOR LCALL +8D1 ABCDE G J L N PQR V Z 34 | TMPH -> SLCTR TST_SEL_CS PTSELE DLY +8D2 AB EFGH J L N PQR T VW 34 6 | TMPH -> PROTUN TMPC BITS32 DLY SDEL +8D3 B E L V X 789&| PAGER5 SET_RPL_TO_CPL PTGEN SPCR +8D4 D N P S WX | GENERAL_FAULTP LJMPVM +8D5 C F NO QR TUV XYZ | EFLAGS 0xffff AND 0 TRAP_INT_GATE +8D6 GHI KL N S | SIGMA -> EFLAGS +8D7 H KL N PQ S 67 9 | TMPG DESCOD IND= +8D8 A C F N PQRSTUV XYZ 5 9&| FLAGSB 0x37fd7 AND PREF +8D9 D F H K MNOP RS 34 67 &| ESP DESSTK NEGWSZ DLY IN=+ +8DA G I L N S 5 78 &| SIGMA -> OPR_W WR +8DB 345 9 | DLY IN+D +8DC G I L OPQR 5 789 | CS -> OPR_W WR W +8DD GHI K NO T V 345 9 | TMPF -> TMPB CLT DLY IN+D +8DE G I L NO QRS 5 78 &| EIP -> OPR_W WR +8DF ABCD H N PQ S U W Z 34 | TMPG -> eIP TRAP_INT_DONE JNERRC DLY +8E0 H LM O ST VW 5 9 | IRF2 -> eSP BITS32 IN+D +8E1 BC E OPQ W YZ | PUSH_ERRORCODE LJMPP +8E2 CD F X Z | 0x10 LDBSRU +8E3 G IJKL N P R 012 | PROTUN -> CS RNI 0 TRAP_INT_DONE +8E4 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +8E5 H LM O S 5 | IRF2 -> eSP 0 IN+= 0 PUSH_ERRORCODE +8E6 AB D QRSTU WXYZ | 0 TMPB SHIFT +8E7 D G I L N S U X Z 5 789 | SIGMA -> OPR_W TRAP_INT_DONE JMP WR W +8E8 34 | DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +8E9 Y | ICESIG 0 PAGE_FAULT +8EA U Z | PAGE_FAULTLOOP JICEWT 0 PAGE_FAULTLOOP +8EB C F NO TUV XYZ | TMPF 0xffff AND +8EC T VW | BITS32 +8ED GHI LMN S Z 34 | SIGMA -> TMPC PAGEFT DLY +8EE K M O R T V YZ 7 9&| OPR_R PFERRC SCNTFF LPCR +8EF CD FGHI K O S X 34 | IRF2 -> TMPB 0x10 LDBSLU DLY +8F0 AB D KLM QRSTU WXYZ 7 9&| 0 LATTTF TMPB SHIFT LPCR +8F1 G I K O ST W Z | IRF2 -> CR2 SERRCF +8F2 AB EF N STUV XY | SIGMA TMPC OR +8F3 A EFGHI N STU W Y | SIGMA -> TMPF 0x0d PASS2 +8F4 A CDEF OPQ S WXY | FAULT LJUMP +8F5 CDEF N STUV YZ | SIGMA 1 ADD +------------------------------------------|---------------------------------------------------------------------------------------------- +8F6 ABC EF OPQR WX Z | NO_PRIVILEGE LJMPNP 0 LOADALL386 +8F7 Y | ICESIG +8F8 A TU W Y | 0x800000fc PASS2 +8F9 B DE N STUV XYZ | SIGMA 0x7ff AND +8FA ABC IJKLMN ST VW 34 67 &| SIGMA DES_ES EDI BITS32 DLY IN=+ +8FB CD 345 | 4 DLY IN+= +8FC B E TU W Y 5 7 | 0x0f PASS2 RD D +8FD CD N STUV YZ | SIGMA 4 ADD +8FE A EFG JK MN STU W Y 34 | SIGMA -> COUNTR 0x0d PASS2 DLY +8FF GH J L O R 3 | OPR_R -> PROTUN UNL +900 CDE N STUV Z | SIGMA 2 SUB +901 GHIJKLMN S 345 9 | SIGMA -> EAX DLY IN+D +902 ABCDEF N P RSTUV Z 5 7 | COUNTR EAX SUB RD D 0 LOADALL_LOOP1 +903 345 9 | DLY IN+D +904 E G KL O R U WXY 3 | OPR_R -> IRF LOADALL_LOOP1 JG UNL +905 T | DECNTR +906 C IJKLMNOP 34 67 &| EDI DES_ES -4 DLY IN=+ +907 CD 345 | 4 DLY IN+= +908 5 7 | RD D +909 B D F T Z 345 9 | 9 LDCNTR DLY IN+D +90A GH J LM O R 3 5 7 | OPR_R -> MDTMP4 UNL RD D +90B 345 9 | DLY IN+D 0 LOADALL_LOOP2 +90C FG KL O R UV XY 3 5 7 | OPR_R -> IRF LOADALL_LOOP2 JCNTN1 UNL RD D +90D T | DECNTR +90E 345 9 | DLY IN+D +90F B D GHIJKLM O R TU W Y 3 5 7 | OPR_R -> EAX 0x29 PASS2 UNL RD D +910 BC E N STUV Z | SIGMA 3 SUB +911 G JK MN S 345 9 | SIGMA -> COUNTR DLY IN+D +912 GH KLM O R 3 5 7 | OPR_R -> DR6 UNL RD D +913 A E TU W Y 345 9 | 0x5d PASS2 DLY IN+D +914 GH KL O R 3 5 7 9 | OPR_R -> DR7 UNL RD W +915 GHI K N S 345 9 | SIGMA -> TMPB DLY IN+D +916 G I KL O R 3 5 7 9 | OPR_R -> TR UNL RD W +917 A EF NO Q TUV YZ 345 9 | TMPB 0x0d ADD DLY IN+D 0 LOADALL_LOOP3 +918 FG KL O R UVW Z 3 5 7 9 | OPR_R -> IRF LOADALL_LOOP3 JCT4N1 UNL RD W +919 T | DECNTR +91A G JK MN S 345 9 | SIGMA -> COUNTR DLY IN+D +91B G IJKLM O R 3 | OPR_R -> ES UNL +91C C EFGH J L N P RSTUV YZ 5 7 | COUNTR -> PROTUN -1 ADD RD D 0 LOADALL_LOOP4 +91D G JK MN S 345 9 | SIGMA -> COUNTR DLY IN+D +91E GHI K O R 3 5 7 | OPR_R -> TMPB UNL RD D +91F 34 | DLY +920 CD O STUV YZ 5 9 | IRF2 4 ADD IN+D +921 GHI LM O R 3 5 7 | OPR_R -> TMPC UNL RD D +922 G KL NO Q 34 789 | TMPB -> IRF DLY SAR +923 G KL NO RS 78 &| TMPC -> IRF SBAS +924 G KL O R 3 78 | OPR_R -> IRF UNL SLIM +925 CD IJKLMN S 67 &| SIGMA DES_ES 4 IN=+ +926 G JK MN P R | PROTUN -> COUNTR +927 =====================================| +928 CD UVW Z | LOADALL_LOOP4 JCT4N1 +929 T | DECNTR +92A BC IJK MNO Q STUV XYZ 34 7 9 | CR0 DES_SS 0xffff0000 AND DLY LAR +92B B FGH J L O S V X | IRF2 -> PROTUN COPY_STACK_DPL PTGEN +92C A N STUV XYZ | SIGMA 0x800000fc AND +92D G JK MN S | SIGMA -> COUNTR +92E GHI K MN R | MDTMP -> CR0 +92F AB DE GH J MNO QRS UVW Y | EIP -> TMPeIP LOADALL_PAGING JCNTNZ +930 IJKL W Z 7 | DES_CS ICEEXT LLIM +931 O STU W YZ | IRF2 PASS +932 IJKL N ST VWX 34 67 9 | SIGMA DES_CS CLRNMI DLY IND= 0 LOADALL_FINAL +933 L N QRSTU W YZ 789&| DR6 PAGER5 PASS SPCR +934 H KL NO QRST V X 67 9 | EIP DESCOD ICEBRK IND= +935 GH KLMN S 5 9&| SIGMA -> DR6 PREF +936 GH J NOP RS 34 | ESP -> TMPeSP DLY +937 012 | RNI +938 =====================================| +------------------------------------------|---------------------------------------------------------------------------------------------- +939 K O STU W YZ 7 9&| IRF2 PDBR PASS LPCR 0 LOADALL_PAGING +93A C I K M O S U X Z 67 9 | IRF2 DESABS LOADALL_FINAL JMP IND= +93B K 789&| PDBR SPCR +------------------------------------------|---------------------------------------------------------------------------------------------- +93C T VW | BITS32 0 ICEBP +93D ABC E U X Z | BREAKPOINT_CMN JMP +93E T V X | ICEBRK +------------------------------------------|---------------------------------------------------------------------------------------------- +93F A C N QRSTUV XY | DR6 0x4000 OR 0 SINGLE_STEP +940 GH KLMN S | SIGMA -> DR6 +941 GH J MNO QRST V X | EIP -> TMPeIP ICEBRK 0 BREAKPOINT +942 GH J NOP RST VW | ESP -> TMPeSP BITS32 +943 CDE X Z | 2 LDBSRU 0 BREAKPOINT_CMN +944 A C QRSTU WXYZ | 0 0x4000 SHIFT +945 GHI K N S Y | SIGMA -> TMPB ICESIG +946 AB D N QR TUV XYZ | DR7 TMPB AND +947 A EFG JK MN S X | SIGMA -> COUNTR 0x0d LDBSLU +948 CDEF QRSTU WXYZ | 0 1 SHIFT +949 ABC E GHI K N P S UVW Y | TMPeIP -> TMPB ICE_SINGLESTEP JCNTNZ +94A C EF N STUV X Z | SIGMA -1 XOR +94B GHI K N S | SIGMA -> TMPB +94C AB D N QR TUV XYZ | DR7 TMPB AND +94D A F OPQ S WXY | INTERRUPT_X LJUMP +94E CDEFGH KL N STU W Y | SIGMA -> DR7 1 PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +94F U Z | ICE_SINGLESTEP JICEWT 0 ICE_SINGLESTEP +950 =====================================| +951 BCDE OP R WXY | STOREALL LJUMP +952 W Y | ICEENT +------------------------------------------|---------------------------------------------------------------------------------------------- +953 T V X | ICEBRK 0 ICE_PIN +954 GHI K N QR T VW | DR7 -> TMPB BITS32 +955 CDE X Z | 2 LDBSRU +956 A C QRSTU WXYZ | 0 0x4000 SHIFT +957 AB D GHI LMN STUV XY | SIGMA -> TMPC TMPB OR +958 GH KL N S 34 | SIGMA -> DR7 DLY +959 GHI K N P S Y | TMPeIP -> TMPB ICESIG +95A U Z | ICE_PIN_LOOP JICEWT 0 ICE_PIN_LOOP +95B AB EF N QRSTUV XY | DR6 TMPC OR +95C BCDE OP R WXY | STOREALL LJUMP +95D GH KLMN S W Y | SIGMA -> DR6 ICEENT +------------------------------------------|---------------------------------------------------------------------------------------------- +95E BCD GH J M O ST Z | IRF2 -> TMPeIP 0x8200 LDCNTR 0 STOREALL16 +95F ABC FGH J LMN P RS U X Z | COUNTR -> MDTMP4 966 JMP +960 I KL 7 | DES_TR LLIM +------------------------------------------|---------------------------------------------------------------------------------------------- +961 CD F I KL X 34 7 9 | DES_TR 0x10 LDBSLU DLY LAR 0 STOREALL +962 D GH J LM UVWXYZ | -1 -> MDTMP4 STOREALL16 J16BIT +963 BC F I KL QRSTU WXYZ 7 &| 0 DES_TR 6 SHIFT LBAS +964 GH J M O S | IRF2 -> TMPeIP +965 I KL 7 | DES_TR LLIM +966 GH J O S | IRF2 -> TMPeSP +967 BCD G JK MN STU W Y | SIGMA -> COUNTR 0x8200 PASS2 +968 A I KL N STU W Y 789 | SIGMA DES_TR 0x800000fc PASS2 SAR +969 B DE N STUV XYZ | SIGMA 0x7ff AND +96A I KL N P RS 78 &| COUNTR DES_TR SBAS +96B I KL 34 78 | -1 DES_TR DLY SLIM +96C CD I KL N S 67 &| SIGMA DES_TR 4 IN=+ +96D B E G I L N P R TU W Y 5 78 | PROTUN -> OPR_W 0x0f PASS2 WR D +96E CD N STUV YZ | SIGMA 4 ADD +96F G JK MN S | SIGMA -> COUNTR +970 A EF N P RSTUV Z 345 9 | COUNTR 0x0d SUB DLY IN+D 0 STOREALL_LOOP1 +971 G I L QR 5 78 | IRF -> OPR_W WR D +972 E G KL QRS U WXY | 0 -> IRF STOREALL_LOOP1 JG +973 T | DECNTR +974 345 9 | DLY IN+D +975 G I L NO RS 5 78 | TMPC -> OPR_W WR D +976 345 9 | DLY IN+D +977 C G I L NO Q TU W Y 5 78 | TMPB -> OPR_W -4 PASS2 WR D +978 34 | DLY +979 K 7 9&| PDBR LPCR +97A I K M O S 67 9 | IRF2 DESABS IND= +97B K 789&| PDBR SPCR +97C CD I KL N STU W Y 34 67 &| SIGMA DES_TR 4 PASS2 DLY IN=+ +97D BC F N STUV YZ | SIGMA 6 ADD +97E ABCD FG JK MN S U X Z | SIGMA -> COUNTR STOREALL_LOOPS JMP +97F B FGH J L QRS V X | 0 -> PROTUN COPY_STACK_DPL PTGEN +------------------------------------------|---------------------------------------------------------------------------------------------- +980 GHI K QRS 345 9 | 0 -> TMPB DLY IN+D 0 STOREALL_LOOP2 +981 FG I L QR UVW Y 5 78 | IRF -> OPR_W STOREALL_LOOP2 JCNTNZ WR D 0 STOREALL_LOOPS +982 G KL QRST | 0 -> IRF DECNTR +983 B D T Z 345 9 | 0x29 LDCNTR DLY IN+D +984 G I L N QRS 5 78 | DR6 -> OPR_W WR D +985 BC E N P RSTUV Z 345 9 | COUNTR 3 SUB DLY IN+D +986 G I L N QR 5 78 | DR7 -> OPR_W WR D +987 G JK MN S 345 9 | SIGMA -> COUNTR DLY IN+D +988 G I L O QR 5 789 | TR -> OPR_W WR W +989 G I KL QRS 345 9 | 0 -> TR DLY IN+D 0 STOREALL_LOOP3 +98A FG I L QR UVW Z 5 789 | IRF -> OPR_W STOREALL_LOOP3 JCT4N1 WR W +98B G KL QRST | 0 -> IRF DECNTR +98C 34 | DLY +98D CD O STUV YZ 5 9 | IRF2 4 ADD IN+D +98E G I L OPQRS 5 789 | ES -> OPR_W WR W +98F BCDEFGHI MN STU W Y | SIGMA -> TMPE 0x70 PASS2 +990 B EF N STUV Z | SIGMA 7 SUB +991 AB DEFG JK MN S U X Z | SIGMA -> COUNTR STOREALL_L4_ST JMP +992 C EFG IJKLM QRSTUV Z 34 | 0 -> ES -1 SUB DLY +------------------------------------------|---------------------------------------------------------------------------------------------- +993 B G KL N P RSTUV XYZ 7 &| COUNTR -> IRF 0x1f AND LBAS 0 STOREALL_LOOP4 +994 GH J M O S | IRF2 -> TMPeIP +995 G KL N STUV Z 7 | SIGMA -> IRF 0 SUB LLIM +996 GH J O S | IRF2 -> TMPeSP +997 C FG KL QRSTU W Y 78 &| 0 -> IRF 0xffff PASS2 SBAS +998 BCD G KL N STU W Y 78 | SIGMA -> IRF 0x8200 PASS2 SLIM +999 G KL N S 789 | SIGMA -> IRF SAR +99A CD I KL NO S 67 &| TMPE DES_TR 4 IN=+ 0 STOREALL_L4_ST +99B G I L N R 5 78 | MDTMP -> OPR_W WR D +99C GH KL QRS 345 9 | 0 -> DR7 DLY IN+D +99D G I L N P ST 5 78 | TMPeIP -> OPR_W DECNTR WR D +99E 34 | DLY +99F CD O STUV YZ 5 9 | IRF2 4 ADD IN+D +9A0 GHI MN S | SIGMA -> TMPE +9A1 G I L N P 5 78 | TMPeSP -> OPR_W WR D +9A2 CDEFG KL U WXY 34 7 9 | -1 -> IRF STOREALL_LOOP4 JG DLY LAR +9A3 GH J LM O S | IRF2 -> MDTMP4 +9A4 EF OP S WXY | BOOTUP_JUMP LJUMP +9A5 I KL QRST V 78 &| 0 DES_TR CLT SBAS +------------------------------------------|---------------------------------------------------------------------------------------------- +9A6 A D F N P RSTUV XY | COUNTR 0x40 OR 0 BOOTUP +9A7 GHI LMN S UVW Y | SIGMA -> TMPC BOOTUP_LOOP1 JCNTNZ 0 BOOTUP_LOOP1 +9A8 G KL QRST | 0 -> IRF DECNTR +9A9 BCDE I K M QRST Z 34 78 &| 0 DESABS 0x73 LDCNTR DLY SBAS +9AA K 789&| PDBR SPCR +9AB GH KL QRS UVW Z | 0 -> DR7 BOOTUP_LOOP2 JCT4N1 0 BOOTUP_LOOP2 +9AC G KL QRST 78 &| 0 -> IRF DECNTR SBAS +9AD C FG I K QRSTU W Y | 0 -> CR2 0xffff PASS2 +9AE AB EFGHI K N ST Z | SIGMA -> TMPB TMPC LDCNTR +9AF BCD GH KLM QRSTU W Y | 0 -> DR6 0x8200 PASS2 0 BOOTUP_LOOP3 +9B0 FG KL N S UVW Z 789 | SIGMA -> IRF BOOTUP_LOOP3 JCT4N1 SAR +9B1 G KL NO Q T 78 | TMPB -> IRF DECNTR SLIM +9B2 IJKLMN ST V YZ 789 | SIGMA DES_ES SCNTFF SAR +9B3 IJKLMNO Q T VW 78 | TMPB DES_ES BITS32 SLIM +9B4 GH KLM QRS | 0 -> DR6 +9B5 A C E GHI L O TU W Y | BIST1 -> TMPD 0x0303 PASS2 +9B6 GHIJK MN S | SIGMA -> EDX +9B7 AB E GHI M PQRSTUV X Z | BIST2 -> TMPE TMPD XOR +9B8 A C EF N STUV X Z | SIGMA 0x3ddc0c2c XOR +9B9 ABCD FGHIJKLMN S UVWX Z | SIGMA -> EAX BOOTUP_JUMP JFPUOK +9BA CD FGHI K M QRSTU W Y | 0 -> CR0 0x10 PASS2 +9BB GHI K MN S | SIGMA -> CR0 +9BC CD GH J L QRS X Z | 0 -> PROTUN 4 LDBSRU 0 BOOTUP_JUMP +9BD A D QRSTU WXYZ | 0 0xf0000 SHIFT +9BE BC GHI K N STU W Y | SIGMA -> TMPB 0xffff0000 PASS2 +9BF C F H KL N STU W Y 78 &| SIGMA DESCOD 0xffff PASS2 SBAS +9C0 H KL N S 78 | SIGMA DESCOD SLIM +9C1 B E L N STUV Z 789&| SIGMA PAGER5 0x0f SUB SPCR +9C2 CDEF NO Q WXY | JMP_FAR_COMMON LJUMP +9C3 AB D GH JK MN STU W Y | SIGMA -> TMPG TMPB PASS2 +------------------------------------------|---------------------------------------------------------------------------------------------- +9C4 =====================================| +9C5 =====================================| +9C6 =====================================| +9C7 =====================================| +9C8 =====================================| +9C9 =====================================| +9CA =====================================| +9CB =====================================| +9CC =====================================| +9CD =====================================| +9CE =====================================| +9CF =====================================| +9D0 =====================================| +9D1 =====================================| +9D2 =====================================| +9D3 =====================================| +9D4 =====================================| +9D5 =====================================| +9D6 =====================================| +9D7 =====================================| +9D8 =====================================| +9D9 =====================================| +9DA =====================================| +9DB =====================================| +9DC =====================================| +9DD =====================================| +9DE =====================================| +9DF =====================================| +9E0 =====================================| +9E1 =====================================| +9E2 =====================================| +9E3 =====================================| +9E4 =====================================| +9E5 =====================================| +9E6 =====================================| +9E7 =====================================| +9E8 =====================================| +9E9 =====================================| +9EA =====================================| +9EB =====================================| +9EC =====================================| +9ED =====================================| +9EE =====================================| +9EF =====================================| +9F0 =====================================| +9F1 =====================================| +9F2 =====================================| +9F3 =====================================| +9F4 =====================================| +9F5 =====================================| +9F6 =====================================| +9F7 =====================================| +9F8 =====================================| +9F9 =====================================| +9FA =====================================| +9FB =====================================| +9FC =====================================| +9FD =====================================| +9FE =====================================| +9FF =====================================| diff --git a/80386/microcode_notes.txt b/80386/microcode_notes.txt new file mode 100644 index 0000000..dd75e15 --- /dev/null +++ b/80386/microcode_notes.txt @@ -0,0 +1,2904 @@ +000 // RESET - Probably CPU starts here after reset and there is 1 empty uop for random logic things to settle +001 IND = LDTR; goto BOOTUP // TODO: What is IND actually set to here? This is an LJUMP so this stomps alu2. Is this value actually used? Yes, to initialise CR3 +002 COUNTR = 0x29; OPR_W = 0; // TODO: Why set OPR_W here? Are we going to do a bus access? (386EX doesn't do any before first instruction fetch) +------------------------------------------|---------------------------------------------------------------------------------------------- +003 SIGMA = SRCREG; RNI; // 0 MOV r,r +004 DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +005 SIGMA = IMM; RNI; // 0 MOV r,i +006 DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +007 DSTREG = SEGREG; RNI; // 0 MOV(ZX) rw,segreg +008 +------------------------------------------|---------------------------------------------------------------------------------------------- +009 SIGMA = DSTREG; DES_SR.BASE = DSTREG << 4; RnI; DLY; // 0 r MOV ES/SS/DS/FS/GS,rw Use of RnI here suppresses interrupts for the next instruction? DES_SR == DES_ES, DES_SS, DES_DS, DES_FS or DES_GS depending on the operand? +00A SEGREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +00B if (PM) goto PM_LD_SS; RD_W; // 1 MOV SS,mw RD_W triggers a 16-bit read from the bus +00C PTR = &DES_SR; PTSAV7 TST_DES_SS; DLY; // TST_DES_SS goes to PROT_TESTS_PASSED (KN) (RETURNs) or #SS(I0,E0) or continues. Must continue in !PROTECTED_MODE case, so the other cases only happen in PM_LD_SS +00D DES_SR.BASE = OPR_R << 4; SIGMA = OPR_R; RnI; UNL; +00E SEGREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +00F if (PM) goto PM_LD_DSESFSGS; RD_W; // 1 MOV ES/DS/FS/GS,mw +010 PTR = &DES_SR; PTSAV1 TST_DES_SIMPLE; DLY; // TST_DES_SIMPLE goes to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continues +011 DES_SR.BASE = OPR_R << 4; SIGMA_OPR_R; UNL; RNI; +012 SEGREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +013 OPR_W = SRCREG; WR; RNI; // 1 MOV [i],A MOV m,r +014 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +015 OPR_W = IMM; WR; RNI; // 1 MOV m,i +016 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +017 OPR_W = SEGREG; WR_W; RNI; // 1 MOV mw,segreg +018 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +019 RD; // 1 MOV A,[i] MOV r,m +01A DLY; +01B RNI; +01C DSTREG = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +01D SIGMA = DSTREG +-&|^ SRCREG; RNI; // 0 ADD/OR/ADC/SBB/AND/SUB/XOR r,r +01E DSTREG = SIGMA: +------------------------------------------|---------------------------------------------------------------------------------------------- +01F SIGMA = DSTREG CMPTST SRCREG; RNI; // 0 CMP r,r TEST r,r +020 +------------------------------------------|---------------------------------------------------------------------------------------------- +021 SIGMA = ++--~- DSTREG; RNI; // 0 INC/DEC/NOT/NEG r +022 DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +023 SIGMA = DSTREG +-&|^ IMM; RNI; // 0 ADD/OR/ADC/SBB/AND/SUB/XOR r,i +024 DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +025 SIGMA = DSTREG CMPTST IMM; RNI; // 0 CMP/TEST A,i +026 +------------------------------------------|---------------------------------------------------------------------------------------------- +027 RD; // 1 ADD/OR/ADC/SBB/AND/SUB/XOR r,m +028 DLY; +029 TMPB = OPR_R; UNL; +02A SIGMA = DSTREG +-&|^ TMPB; RNI; +02B DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +02C RD; // 1 CMP r,m +02D DLY; +02E TMPB = OPR_R; UNL; +02F SIGMA = DSTREG CMPTST TMPB; RNI; +030 +------------------------------------------|---------------------------------------------------------------------------------------------- +031 RD; // 1 CMP/TEST m,i +032 DLY; +033 SIGMA = OPR_R CMPTST IMM; RNI; UNL; +034 +------------------------------------------|---------------------------------------------------------------------------------------------- +035 RD; // 1 CMP/TEST m,r +036 DLY; +037 SIGMA = OPR_R CMPTST SRCREG; RNI; UNL; +038 +------------------------------------------|---------------------------------------------------------------------------------------------- +039 RD; FLAGSB = EFLAGS; RD; // 9 ADD/OR/ADC/SBB/AND/SUB/XOR m,i +03A DLY; +03B TMPB = OPR_R; UNL; goto WRITE_RESULT; +03C SIGMA = TMPB +-&|^ IMM; +------------------------------------------|---------------------------------------------------------------------------------------------- +03D if (!cond) goto SETCONDR_FALSE; // 0 SETcond rb +03E BITS8; +03F SIGMA = 1; RNI; +040 DSTREG = 1; +------------------------------------------|---------------------------------------------------------------------------------------------- +041 SETCONDR_FALSE: DSTREG = 0; RNI; +042 +------------------------------------------|---------------------------------------------------------------------------------------------- +043 if (!cond) goto SETCONDM_FALSE; // 1 SETcond mb +044 BITS8; +045 SIGMA = 1; +046 WRITE_RESULT: OPR_W = SIGMA; WR; RNI; +047 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +048 SETCONDM_FALSE: OPR_W = 0; WR; RNI; +049 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +04A FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; RD; // 9 ADD/OR/ADC/SBB/AND/SUB/XOR m,r +04B DLY; +04C TMPB = OPR_R; UNL; goto WRITE_RESULT; +04D SIGMA = TMPB +-&|^ SRCREG; +------------------------------------------|---------------------------------------------------------------------------------------------- +04E RD; // 9 INC/DEC/NOT/NEG m +04F DLY; goto WRITE_RESULT; +050 SIGMA = ++--~- OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +051 COUNTR = eCX; DLY; // 0 JeCXZ cb +052 DESCOD; SIGMA = EIP + IMM8; IND_DELTA = IMM8; IND = EIP + IND_DELTA; +053 if (COUNTR != 0) goto Jcond_DONE; // COUNTR == 0 case goes to 054 (no RNI), 055, 056 (delay slot - RNI), 069 - RNi is RNI but only if it's executed in the delay slot +054 RNi; PREF; // COUNTR != 0 case goes to 054 (delay slot - RNI), 069 PREF starts prefetch at IND? Only if not in delay slot? Is PREF just an optimisation hint? +055 eIP = SIGMA; DLY; goto Jcond_DONE; +056 RNi; +------------------------------------------|---------------------------------------------------------------------------------------------- +057 COUNTR = eCX; DLY; // 0 LOOP cb +058 DESCOD; SIGMA = EIP + IMM8; IND_DELTA = IMM8; IND = EIP + IND_DELTA; +059 if (COUNTR == 1) goto LOOP_UNTAKEN; // COUNTR != 1 case goes to 05A (PREF at EIP + IMM8, COUNTR = -1), 05B (sets EIP = EIP + IMM8), 05C (ECX = -1, delay slot = RNI), 069 +05A --COUNTR; PREF; // COUNTR == 1 case goes to 05A (PREF at EIP + IMM8, --COUNTR), 05D (IND = EIP), 05E (delay slot, SIGMA = EIP, PREF at EIP), 05B (sets EIP = EIP), 05C (RNi), 069 +05B LOOP_DONE: eIP = SIGMA; DLY; goto Jcond_DONE; +05C eCX = COUNTR; RNi; +------------------------------------------|---------------------------------------------------------------------------------------------- +05D LOOP_UNTAKEN: DESCOD; IND = EIP; DLY; goto LOOP_DONE; +05E SIGMA = EIP; PREF; // If PREF is suppressed in delay slot, then it never has an effect here +------------------------------------------|---------------------------------------------------------------------------------------------- +05F COUNTR = eCX; DLY; // 0 LOOPE/LOOPNE cb +060 DESCOD; SIGMA = EIP + IMM8; IND_DELTA = IMM8; IND = EIP + IND_DELTA; +061 if (LOOPnE) goto LOOP_UNTAKEN; // This instruction is the same as LOOP apart from using LOOPnE instead of JCNTZ +062 --COUNTR; PREF; +063 eIP = SIGMA; DLY; goto Jcond_DONE; +064 eCX = COUNTR; RNi; +------------------------------------------|---------------------------------------------------------------------------------------------- +065 DESCOD; DLY; IND_DELTA = IMM8?; IND = EIP + IND_DELTA; if (!cond) goto Jcond_DONE; // 0 Jcond cb/cv From other routines, we'd think that IND = EIP + EBX here. Not sure what's going on +066 SIGMA = EIP + IMM8; RNi; PREF; // If PREF actually runs in the non-taken case, then perhaps it stops prefetching and writes to EIP (or RNI) restart it. +067 JMP_PREFINAL: DLY; // in that case, why modify IND at all? It might be dead code - they might have previously started prefetching at IND but there were too many bugs so they said "screw it, we'll just start prefetching at the new EIP when it's written to - that's guaranteed to work". +068 JMP_FINAL: eIP = SIGMA; RNI; +069 Jcond_DONE: +------------------------------------------|---------------------------------------------------------------------------------------------- +06A DESCOD; IND_DELTA = IMM8; IND = EIP + IND_DELTA; SIGMA = ESP + IMM8; DLY; // 0 JMP c +06B JMP_PREF: PREF; JMP JMP_FINAL; +06C DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +06D DESCOD; IND = DSTREG; DLY; goto JMP_PREFINAL; // 0 r JMP rmv +06E SIGMA = DSTREG; PREF; +------------------------------------------|---------------------------------------------------------------------------------------------- +06F RD; // 1 m JMP rmv +070 DLY; goto JMP_PREF; +071 DESCOD; IND = OPR_R; SIGMA = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +072 SIGMA += IMM; RD; // 3 RET/RET iw +073 eSP = SIGMA; DLY; goto JMP_PREF; +074 DESCOD; IND = OPR_R; SIGMA = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +075 OPR_W = EIP; WR; // 2 CALL cw +076 DESCOD; IND_DELTA = IMM8; IND = EIP + IND_DELTA; DLY; +077 eSP = SIGMA; PREF; goto JMP_FINAL; +078 SIGMA = EIP + IMM8; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +079 OPR_W = EIP; WR; // 2 r CALL rmv +07A DESCOD; IND = DSTREG; DLY; goto JMP_PREFINAL; +07B eSP = SIGMA; SIGMA = DSTREG; PREF; +------------------------------------------|---------------------------------------------------------------------------------------------- +07C RD; // 1 m CALL rmv +07D DESSTK; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; SIGMA = ESP + NEGWSZ; DLY; +07E OPR_W = EIP; WR; +07F eSP = SIGMA; DLY; goto JMP_PREF; +080 DESCOD; IND = OPR_R; SIGMA = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +081 RD; // 1 m PUSH rmv +082 DESSTK; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; SIGMA = ESP + NEGWSZ; DLY; +083 eSP = SIGMA; wr; +084 RNI; DLY; +085 OPR_R; UNL; // Weird - OPR_R source doesn't seem to be used? +------------------------------------------|---------------------------------------------------------------------------------------------- +086 OPR_W = DSTREG; WR; RNI; // 2 r PUSH rmv/rv +087 eSP = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +088 SIGMA = ESP - BITS_V; DLY; // 0 PUSHAd +089 DESSTK; IND_DELTA = -1; IND = SIGMA + IND_DELTA; SIGMA -= 1; // IND = ESP - (BITS_V + 1) SIGMA = ESP - (BITS_V + 1) +08A OPR_W = EDI; COUNTR = 6; WR; // Write eDI first (last in the PUSH sequence, lowest address) COUNTR = 6 => ESI +08B IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; // set IND for slot 1 +08C OPR_W = IRF[COUNTR]; --COUNTR; WR; // Write eSI, COUNTR = 5 +08D PUSHAd_LOOP: +08E IND += IND_DELTA; DLY; if (COUNTR != 0) goto PUSHAd_LOOP; // IND_DELTA set to WORDSZ at 08B +08F OPR_W = IRF[COUNTR]; --COUNTR; WR; RNI; // Write eBP, eSP, eBX, eDX, eCX, eAX decrease COUNTR to -1 +090 eSP = SIGMA; DLY; // ESP -= (BITS_V + 1) +------------------------------------------|---------------------------------------------------------------------------------------------- +091 eSP = SIGMA; COUNTR = 0x47; RD; // 3 POPA Read DI +092 POPAd_LOOP: DESSTK; IND = ESP; SIGMA = ESP + WORDSZ; DLY; +093 IRF[COUNTR] = OPR_R; UNL; RD; if ((COUNTR & 15) != 1) goto POPAd_LOOP; +094 eSP = SIGMA; --COUNTR; // Loop reading SI, BP, SP, BX, DX, CX, AX +095 DLY; RNI; +096 IRF[COUNTR] = OPR_R; UNL; // Store AX +------------------------------------------|---------------------------------------------------------------------------------------------- +097 eSP = SIGMA; COUNTR = 7; RD; // 3 POPAD +098 DESSTK; IND = ESP; SIGMA = ESP + WORDSZ; DLY; +099 IRF = OPR_R; UNL; RD; goto POPAd_LOOP; +09A eSP = SIGMA; --COUNTR; +------------------------------------------|---------------------------------------------------------------------------------------------- +09B OPR_W = SEGREG; WR_W; RNI; // 2 PUSH segreg +09C eSP = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +09D OPR_W = IMM; WR; RNI; // 2 PUSH i +09E eSP = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +09F eSP = SIGMA; RD; // 3 r POP rmv +0A0 RNI; DLY; +0A1 DSTREG = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +0A2 eSP = SIGMA; RD_W; // 3 POP SS +0A3 if (PM) goto PM_LD_SS; +0A4 PTR = &DES_SR; DLY; PTSAV7 TST_DES_SS; // TST_DES_SS goes to PROT_TESTS_PASSED (KN) (RETURNs) or #SS(I0,E0) or continues. +0A5 DES_SR.BASE = OPR_R << 4; SIGMA = OPR_R; UNL; RnI; +0A6 SEGREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +0A7 eSP = SIGMA; RD_W; // 3 POP ES/DS/FS/GS +0A8 if (PM) goto PM_LD_DSESFSGS; +0A9 PTR = &DES_SR; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE goes to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continues +0AA DES_SR.BASE = OPR_R << 4; SIGMA = OPR_R; UNL; RNI; +0AB SEGREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +0AC eSP = SIGMA; RD; // 3 m POP rmv +0AD DES_OS; IND_DELTA = 0; IND = EA + IND_DELTA; DLY; // Why add 0? +0AE wr; +0AF DLY; RNI; +0B0 OPR_R; UNL; // Weird - OPR_R source doesn't seem to be used? +------------------------------------------|---------------------------------------------------------------------------------------------- +0B1 rd; // 9 m XCHG rm,r +0B2 DLY +0B3 OPR_W = SRCREG; WR; +0B4 RNI; DLY; +0B5 SRCREG = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +0B6 COUNTR = SRCREG; SIGMA = DSTREG; // 0 r XCHG EAX,rv XCHG rm,r +0B7 DSTREG = COUNTR; RNI; +0B8 SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +0B9 SRCREG = IRF2; IND_DELTA = 0; IND += IND_DELTA; RNI; // 1 m LEA rv,m Weird - why add 0? +0BA +------------------------------------------|---------------------------------------------------------------------------------------------- +0BB SIGMA = 3; RD; // 1 m LDS rv,m Read offset +0BC IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +0BD RD_W; if (PM) goto PM_LDS; // Read segment +0BE TMPD = OPR_R; UNL; // TMPD = offset +0BF DLY; // This onwards is real mode only +0C0 DS = OPR_R; DS.BASE = OPR_R << 4; SIGMA = TMPD; UNL; RNI; +0C1 SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +0C2 SIGMA = 0; RD; // 1 LES rv,m Can this SIGMA ever actually get used? +0C3 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +0C4 RD_W; if (PM) goto PM_LES; +0C5 TMPD = OPR_R; UNL; +0C6 DLY; +0C7 ES = OPR_R; ES.BASE = OPR_R << 4; SIGMA = TMPD; UNL; RNI; +0C8 SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +0C9 SIGMA = IMM ^ 0x10; RD; // 1 LSS rv,m +0CA COUNTR = SIGMA; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +0CB RD_W; if (PM) goto PM_LSS; +0CC TMPD = OPR_R; UNL; +0CD DLY; +0CE IRF[COUNTR] = OPR_R; IRF[COUNTR].BASE = OPR_R << 4; SIGMA = TMPD; UNL; RNI; // COUNTR must be 0x22 for SS so IMM must be 0x32. Not sure why we can't just use SS directly like in LES. Maybe this code was shared with LSS until they realised that needed different protection tests? +0CF SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +0D0 SIGMA = IMM ^ 0x10; RD; // 1 LFS/LGS rv,m +0D1 COUNTR = SIGMA; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +0D2 RD_W; if (PM) goto PM_LFS_LGS; +0D3 TMPD = OPR_R; UNL; +0D4 DLY; +0D5 IRF[COUNTR] = OPR_R; IRF[COUNTR].BASE = OPR_R << 4; SIGMA = TMPD; UNL; RNI; // COUNTR must be 0x24/0x25 for FS/GS so IMM must be 0x34/0x35. +0D6 SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +0D7 SIGMA = EFLAGS & 0x37fd7; RNI; // 0 LAHF +0D8 AH = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +0D9 BITS8; // 0 SAHF Need BITS8 here so that eDX_AH refers to AH +0DA eDX_AH = FLAGSL; RNI; +0DB +------------------------------------------|---------------------------------------------------------------------------------------------- +0DC if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 CLTS +0DD SIGMA = -1 ^ 8; // SIGMA = -9 = 0xfffffff7 +0DE TMPB = SIGMA; +0DF SIGMA = CR0 & TMPB; RNI; +0E0 CR0 = SIGMA; // Turn off bit 3 in CR0 = TS "Task switched" Allows saving x87 task context upon a task switch only after x87 instruction used +------------------------------------------|---------------------------------------------------------------------------------------------- +0E1 if (!C) goto SALC_DONE; // 0 SALC +0E2 AL = 0; RNi; // !C case: 0e2 (RNi) AL = 0, 0e4 +0E3 AL = -1; RNI; // C case: 0e2 (delay slot - RNi has no effect), 0e3 (RNI) AL = -1, 0e4 +0E4 SALC_DONE: +------------------------------------------|---------------------------------------------------------------------------------------------- +0E5 COUNT5 = IMM; SIGMA = BITS_V; // 0 r RCL/RCR rm,ib +0E6 SIGMA += 1; +0E7 TMPB = SIGMA; goto RCLRCR_R_COMM; +0E8 TMPC = COUNTR; SIGMA = COUNTR - TMPB; +------------------------------------------|---------------------------------------------------------------------------------------------- +0E9 COUNT5 = ECX; SIGMA = BITS_V; // 0 r RCL/RCR rm,CL +0EA SIGMA += 1; +0EB TMPB = SIGMA; +0EC TMPC = COUNTR; SIGMA = COUNTR - TMPB; // TMPC = c = amount to shift by SIGMA = c - (BITS_V + 1) Why compute this and then not use it? +0ED RCLRCR_R_COMM: TMPD = DSTREG; SIGMA = DSTREG <<>>? TMPC; +0EE TMPE = SIGMA; if (G) goto RCLRCR_R_LOOP; +0EF SIGMA = TMPE >><>? BITS_V; +0F4 SIGMA = (TMPE:TMPD) >> SHRCNT; // No BSRU/BSLU/BSRM/BSLM - implicit default or from the another alu op? +0F5 TMPD = TMPE; if (G) goto RCLRCR_R_LOOP; +0F6 TMPE = SIGMA; SIGMA = SIGMA <<>>? TMPC; +0F7 SIGMA = TMPE >><>? IMM; // 0 r ROL/ROR/SHL/SHR/SAR rm,ib +0FA SIGMA = SIGMA >><>? IMM; // 0 r SHxD rmv,rv,ib +0FD SIGMA = SRCREG >><>? ECX; // 0 r ROL/ROR/SHL/SHR/SAR rm,CL +100 SIGMA = SIGMA >><>? ECX; // 0 r SHxD rmv,rv,CL +103 SIGMA = SRCREG >><>? 1; // 0 r rot rm,1 +106 SIMA = SIGMA >><>? TMPC; UNL; CW; +111 TMPE = SIGMA; DLY; if (G) goto RCLRCR_M_LOOP; +112 SIGMA = TMPE >><>? BITS_V; +118 SIGMA = (TMPE:TMPD) >> SHRCNT; // No BSRU/BSLU/BSRM/BSLM - implicit default or from the another alu op? +119 TMPD = TMPE; if (G) goto RCLRCR_M_LOOP; +11A TMPE = SIGMA; SIGMA = SIGMA <<>>? TMPC; +11B SIGMA = TMPE >><>? TMPC; UNL; +121 SIGMA = SIGMA >><>? TMPC; UNL; +127 SIGMA = SRCREG >><> SHRCNT; CF = SIGMA & 1; RNI; +133 +------------------------------------------|---------------------------------------------------------------------------------------------- +134 SIGMA = SIGN SRCREG; // 1 BT m,rv +135 SHRCNT = 3; +136 SIGMA = (SIGMA:SRCREG) >> SHRCNT; +137 SIGMA &= NEGWSZ; +138 TMPB = SIGMA; +139 IND_DELTA = TMPB; IND += IND_DELTA; DLY; +13A RD; +13B DLY; +13C TMPB = OPR_R; SHRCNT = SRCREG & BITS_V; UNL; +13D SIGMA = (TMPB:TMPB) >> SHRCNT; CF = SIGMA & 1; RNI; +13E +------------------------------------------|---------------------------------------------------------------------------------------------- +13F SHRCNT = IMM & BITS_V; // 0 BT rv,ib +140 SIGMA = (DSTREG:DSTREG) >> SHRCNT; CF = SIGMA & 1; RNI; // SIGMA not used, only CF updated +141 +------------------------------------------|---------------------------------------------------------------------------------------------- +142 RD; // 1 BT m,ib +143 DLY; +144 TMPB = OPR_R; SHRCNT = IMM & BITS_V; UNL; +145 SIGMA = (TMPB:TMPB) >> SHRCNT; CF = SIGMA & 1; RNI; +146 +------------------------------------------|---------------------------------------------------------------------------------------------- +147 SHRCNT = SRCREG & BITS_V; // 0 BTS/BTR/BTC rv,rv +148 SIGMA = (DSTREG:DSTREG) >> SHRCNT; CF = SIGMA & 1; // This must do a rotate as well as setting CF +149 SIGMA = SIGMA SERECO 1; // SERECO must set, reset or complement bit 0 must leave CF alone +14A TMPB = SIGMA; SHLCNT = SRCREG & BITS_V; +14B SIGMA = (TMPB:TMPB) << SHLCNT; RNI; // Rotate bit 0 back into position rv must leave CF alone +14C DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +14D SIGMA = SIGN SRCREG; // 9 BTS/BTR/BTC m,rv sign-extend 8/16-bit inputs to 32 bits? +14E SHRCNT = 3; +14F SIGMA = (SIGMA:SRCREG) >> SHRCNT; // SIGMA = SRCREG >> 3 using arithmetic shift = byte offset +150 SIGMA = SIGMA & NEGWSZ; // clear low bit or 2 bits (align SIGMA) +151 TMPB = SIGMA; SIGMA = 1; +152 IND_DELTA = TMPB; IND += IND_DELTA; DLY; // IND = address to access +153 SHLCNT = SRCREG & BITS_V; RD; // bit within vword +154 SIGMA = (SIGMA:1) << SHLCNT; // not sure why we use SIGMA in the high dword here +155 TMPB = SIGMA; SHRCNT = SRCREG & BITS_V; DLY; // TMPB = 1 shifted to the desired position +156 TMPC = OPR_R; SIGMA = OPR_R SERECO TMPB; UNL; // TMPC = read vword SIGMA = vword after set/reset/complement +157 OPR_W = SIGMA; WR; // Write back modified vword +158 SIGMA = (TMPC:TMPC) >> SHRCNT; CF = SIGMA & 1; DLY; RNI; // shift bit right again and test to set CF +159 +------------------------------------------|---------------------------------------------------------------------------------------------- +15A SHRCNT = IMM & BITS_V; // 0 BTS/BTR/BTC rv,ib +15B SIGMA = (DSTREG:DSTREG) >> SHRCNT; +15C SIGMA = SIGMA SERECO 1; +15D TMPB = SIGMA; SHLCNT = IMM & BITS_V; +15E SIGMA = (TMPB:TMPB) << SHLCNT; RNI; +15F DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +160 SIGMA = 1; RD; // 9 BTS/BTR/BTC m,ib +161 SHLCNT = IMM & BITS_V; +162 SIGMA = (SIGMA:1) << SHLCNT; // Seems like this must be size-sensitive since ib is taken modulo bitsize +163 TMPB = SIGMA; SHRCNT = IMM & BITS_V; DLY; +164 TMPC = OPR_R; SIGMA = OPR_R SERECO TMPB; UNL; +165 OPR_W = SIGMA; WR; +166 SIGMA = (TMPC:TMPC) >> SHRCNT; DLY; RNI; +167 +------------------------------------------|---------------------------------------------------------------------------------------------- +168 TMPB = DSTREG; COUNTR = BITS_V; // 0 BSF rv,rv +169 BSF_COMMON: SIGMA = 0 CMP TMPB; +16A TMPE = COUNTR; SHRCNT = 0; // TMPE = BITS_V +16B if (!C) goto BSF_DONE: // if (DSTREG == 0) goto BSF_DONE? (only 1 (empty) line at BSF_DONE actually executed due to RNi at 16c) +16C SIGMA = (0:TMPB) >> SHRCNT; CF = SIGMA & 1; RNi; // SHRCNT is 0 here so CF = TMPB & 1 +16D SHRCNT = 1; +16E if (!C) goto BSF_LOOP; // if ((TMPB & 1) == 0) goto BSF_LOOP; +16F SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 1 +170 SRCREG = 0; CLZF; RNI; // The ZF flag is cleared if the bits are all 0 +171 BSF_DONE: +172 BSF_LOOP: --COUNTR; +173 TMPB = SIGMA; if (!C) goto BSF_LOOP; +174 TMPC = COUNTR; SIGMA = COUNTR BITTST TMPB; // SHRCNT is 1 here +175 SIGMA = TMPE CMP TMPC; RNI; +176 SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +177 RD; // 1 BSF rv,mv +178 DLY; goto BSF_COMMON; +179 TMPB = OPR_R; COUNTR = BITS_V; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +17A TMPB = DSTREG; COUNTR = BITS_V; // 0 BSR rv,rv +17B BSR_COMMON: SIGMA = 0 CMP TMPB; +17C SHLCNT = 1; +17D if (!C) goto BSR_DONE; +17E SIGMA = 0 CMP 0; RNi; +17F BSR_LOOP: SRCREG = TMPC; SIGMA = TMPC >><> SHRCNT; // Shift right by number of remaining bits in COUNTR +1A1 TMPB = SIGMA; +1A2 SIGMA = EAX_AL + TMPB + CF; // {-0D-} must be an addition. Possibly ADC and we know that CF = 0 +1A3 AH = 0; RNI; +1A4 AL = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +1A5 MDTMP = DSTREG; COUNTR = BITS_V; // 0 MUL/IMUL r +1A6 TMPB = EAX_AL; SIGMA = 0; +1A7 iMUL_COMMON: SIGMA = SIGMA IMUL3 TMPB; RPT; DLY; // iMUL_COMMON implements the parts of MUL/IMUL common to both register and memory versions +1A8 SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle? +1A9 TMPD = COUNTR; // TMPD = remaining_bits +1AA TMPC = MDTMP; SHRCNT = TMPD & BITS_V; +1AB TMPD = SIGMA; SIGMA = (SIGMA:TMPC) >> SHRCNT; // SIGMA = (SIGMA:TMPC) >> remaining_bits +1AC eAX_AL = SIGMA; SIGMA = SZ_EX2 TMPD; // {-07-} corrects for sign in IMUL case? Only used here - presumably looks at modrm byte bit 3 to determine SX or ZX whereas SZ_EXT looks at opcode byte bit 3 +1AD SIGMA = (SIGMA:TMPD) >> SHRCNT; RNI; // SIGMA = (SIGMA:TMPD) >> remaining_bits +1AE eDX_AH = SIGMA; // eDX_AH = upper part of result +------------------------------------------|---------------------------------------------------------------------------------------------- +1AF TMPB = EAX_AL; RD; COUNTR = BITS_V; // 1 MUL/IMUL m +1B0 DLY; +1B1 MDTMP = OPR_R; UNL; goto iMUL_COMMON; +1B2 SIGMA = 0; +------------------------------------------|---------------------------------------------------------------------------------------------- +1B3 MDTMP = DSTREG; COUNTR = BITS_V; // 0 IMUL rv,rv +1B4 TMPB = SRCREG; SIGMA = 0; +1B5 IMUL2_COMMON: SIGMA = SIGMA IMUL4 TMPB; RPT; DLY; // Meat of the multiplication algorithm +1B6 SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle? +1B7 TMPD = COUNTR; +1B8 TMPC = MDTMP; SHRCNT = TMPD & BITS_V; +1B9 TMPD = SIGMA; SIGMA = (SIGMA:TMPC) >> SHRCNT; // Shift right by number of remaining bits in COUNTR +1BA SRCREG = SIGMA; SIGMA = SIGMA IMCS TMPD; // IMCS corrects for sign always? Only used here +1BB SIGMA = (SIGMA:TMPD) >> SHRCNT; RNI; // Dead code? Seems like we could have RNIed a couple of cycles earlier. Needed for flags? +1BC +------------------------------------------|---------------------------------------------------------------------------------------------- +1BD COUNTR = BITS_V; RD; // 1 IMUL rv,mv +1BE TMPB = SRCREG; DLY; +1BF MDTMP = OPR_R; UNL; goto IMUL2_COMMON; +1C0 SIGMA = 0; +------------------------------------------|---------------------------------------------------------------------------------------------- +1C1 MDTMP = IMM; COUNTR = BITS_V; RD; // 1 IMUL rv,mv,i +1C2 DLY; goto IMUL2_COMMON; +1C3 TMPB = OPR_R; SIGMA = 0; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +1C4 MDTMP = IMM; COUNTR = BITS_V; // 0 IMUL rv,rv,i +1C5 goto IMUL2_COMMON; +1C6 TMPB = DSTREG; SIGMA = 0; +------------------------------------------|---------------------------------------------------------------------------------------------- +1C7 MDTMP4 = EAX_AL; COUNTR = BITS_V; // 0 DIV r +1C8 SIGMA = EDX_AH; +1C9 TMPB = DSTREG; +1CA DIV_COMMON: SIGMA = SIGMA DIV7 TMPB; RPT; DLY; // Meat of the division algorithm +1CB SIGMA = SIGMA DIV5 TMPB; +1CC SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle? +1CD EAX_AL = MDTMP; RNI; +1CE EDX_AH = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +1CF MDTMP4 = EAX_AL; COUNTR = BITS_V; RD; // 1 DIV m +1D0 SIGMA = EDX_AH; +1D1 DLY; goto DIV_COMMON; +1D2 TMPB = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +1D3 SIGMA = -1 + BITS_V; // 0 IDIV r +1D4 COUNTR = SIGMA; +1D5 SIGMA = EDX_AH; +1D6 MDTMP4 = EAX_AL; +1D7 TMPB = DSTREG; +1D8 IDIV_COMMON: SIGMA = SIGMA IDIV0 TMPB; // First iteration is different for IDIV? Hence COUNTR being one less +1D9 SIGMA = SIGMA DIV7 TMPB; RPT; DLY; // Meat of the division algorithm +1DA SIGMA = SIGMA DIV5 TMPB; +1DB SIGMA = SIGMA IDIV1 TMPB; // Correct for signs? +1DC SIGMA = SIGMA; // Not sure why this is here. ALU needs an extra cycle? +1DD TMPB = SIGMA; +1DE SIGMA = MDTMP IDIV2; // More correcting for signs? +1DF EDX_AH = TMPB; RNI; +1E0 EAX_AL = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +1E1 SIGMA = BITS_V - 1; RD; // 1 IDIV m +1E2 COUNTR = SIGMA; +1E3 SIGMA = EDX_AH; +1E4 MDTMP4 = EAX_AL; DLY; goto IDIV_COMMON; +1E5 TMPB = OPR_R; +------------------------------------------|---------------------------------------------------------------------------------------------- +1E6 SIGMA = SIGN EAX; RNI; // 0 CWD / CDQ +1E7 EDX = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +1E8 SIGMA = SZ_EXT DSTREG; // 0 r CBW / CWDE MOVZX/MOVSX r,rm (16-bit?) +1E9 BITS16; RNI; +1EA SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +1EB RD; // 1 m MOVZX/MOVSX r,rm (16-bit?) +1EC DLY; +1ED SIGMA = SZ_EXT OPR_R; UNL; +1EE BITS16; RNI; +1EF SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +1F0 SIGMA = SZ_EXT DSTREG; // 0 r CBW / CWDE MOVZX/MOVSX r,rm (32-bit?) +1F1 BITS32; RNI; +1F2 SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +1F3 RD; // 1 m MOVZX/MOVSX r,rm (32-bit?) +1F4 DLY; +1F5 SIGMA = SZ_EXT OPR_R; UNL; +1F6 BITS32; RNI; +1F7 SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +1F8 COUNTR = eCX; // 0 REP MOVS +1F9 REPF = true; +1FA if (COUNTR != 0) goto REP_MOVS_NOT0; +1FB DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; RNI; // RNI is suppressed if it's in the delay slot +1FC +------------------------------------------|---------------------------------------------------------------------------------------------- +1FD REP_MOVS_NOT0: TMPB = SIGMA; --COUNTR; RD; +1FE DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; +1FF TMPC = SIGMA; wr; if (COUNTR == 0) goto REP_MOVS_DONE; // jump if interrupt requested? No, see 250. Jump if COUNTR == 0? +200 DES_OS; IND = TMPB; SIGMA = TMPB + INCREM; DLY; +201 REP_MOVS_LOOP: TMPB = SIGMA; --COUNTR; RD; +202 DES_ES; IND = TMPC; SIGMA = TMPC + INCREM; DLY; +203 TMPC = SIGMA; UNL; wr; if (COUNTR != 0 && !INTERRUPT_REQUESTED) goto REP_MOVS_LOOP; // {-47-} aka JCNZNI (only used here) must test both conditions since it's the only test in the loop +204 DES_OS; IND = TMPB; SIGMA = TMPB + INCREM; DLY; +205 REP_MOVS_DONE: eCX = COUNTR; if (COUNTR != 0) goto REP_MOVS_RPTI; +206 eDI = TMPC; SIGMA = TMPB; UNL; RNI; // RNI suppressed if in delay slot +207 REP_MOVS_RPTI: eSI = SIGMA; +208 RPTI: DESCSW; IND = TMPeIP; SIGMA = 0xffff; DLY; +209 SIGMA += 1; // SIGMA = 0x10000 +20A TMPB = SIGMA; // TMPB = 0x10000 +20B SIGMA = EFLAGS | TMPB; // SIGMA = EFLAGS | 0x10000 +20C EFLAGS = SIGMA; // EFLAGS |= 0x10000 Turn on resume flag +20D EIP = TMPeIP; PREF; +20E DLY; +20F RNI; +210 +------------------------------------------|---------------------------------------------------------------------------------------------- +211 DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; // 0 MOVS +212 TMPB = SIGMA; RD; +213 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; +214 wr; +215 DLY; +216 eSI = TMPB; UNL; RNI; +217 eDI = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +218 COUNTR = eCX; // 0 REP CMPS +219 // blank line must be needed between COUNTR load and test +21A if (COUNTR != 0) goto REP_CMPS_NOT0; +21B DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNI; +21C REP_CMPS_DONE: // Just a convenient place for the jumps on lines 21e and 227 to have their destinations +21D REP_CMPS_LOOP: eSI = TMPD; --COUNTR; +21E eCX = COUNTR; if (LOOPnE) goto REP_CMPS_DONE; // The goto here is just so that the RNi on line 21f will be activated +21F eDI = TMPB; SIGMA = TMPB + INCREM; DLY; RNi; +220 REP_CMPS_NOT0: TMPB = SIGMA; RD; +221 DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; +222 TMPD = SIGMA; RD; +223 TMPC = OPR_R; UNL; +224 DES_ES; IND = TMPB; DLY; if (!INTERRUPT_REQUESTED) goto REP_CMPS_LOOP; +225 SIGMA = OPR_R CMP TMPC; UNL; +226 eSI = TMPD; --COUNTR; +227 eCX = COUNTR; if (LOOPnE) goto REP_CMPS_DONE; // The goto here is just so that the RNi on line 228 will be activated +228 TMPB = eDI; IND_DELTA = INCREM; IND += IND_DELTA; SIGMA = eDI + INCREM; DLY; RNi; +229 goto RPTI; +22A +------------------------------------------|---------------------------------------------------------------------------------------------- +22B DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; // 0 CMPS +22C TMPB = SIGMA; RD; +22D DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; +22E RD; +22F TMPC = OPR_R; UNL; +230 DLY; +231 eDI = TMPB; +232 eSI = SIGMA; +233 SIGMA = OPR_R CMP TMPC; UNL; RNI; +234 +------------------------------------------|---------------------------------------------------------------------------------------------- +235 COUNTR = eCX; // 0 REP SCAS +236 +237 if (COUNTR != 0) goto REP_SCAS_NOT0; +238 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNI; +239 REP_SCAS_DONE: // Just a convenient place for the jumps on lines 23b and 243 to have their destinations +23A REP_SCAS_LOOP: --COUNTR; +23B eCX = COUNTR; if (LOOPnE) goto REP_SCAS_DONE; // The goto here is just so that the RNi on line 23c will be activated +23C DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNi; +23D REP_SCAS_NOT0: RD; +23E DLY; +23F eDI = SIGMA; +240 TMPC = OPR_R; UNL; if (!INTERRUPT_REQUESTED) goto REP_SCAS_LOOP; +241 SIGMA = EAX CMP TMPC; +242 --COUNTR; +243 eCX = COUNTR; if (LOOPnE) goto REP_SCAS_DONE; // The goto here is just so that the RNi on line 244 will be activated +244 RNi; +245 goto RPTI; +246 +------------------------------------------|---------------------------------------------------------------------------------------------- +247 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; // 0 SCAS +248 RD; +249 DLY; +24A eDI = SIGMA; +24B TMPB = OPR_R; UNL; +24C SIGMA = EAX CMP TMPB; RNI; +24D +------------------------------------------|---------------------------------------------------------------------------------------------- +24E COUNTR = eCX; goto REP_LODS_LOOP; // 0 REP LODS pointless goto? +24F REP_LODS_DONE: // Just a convenient place for the jumps on lines 250 and 256 to have their destinations +250 REP_LODS_LOOP: eCX = COUNTR; if (COUNTR == 0) goto REP_LODS_DONE; // The goto here is just so that the RNi on line 251 will be activated +251 DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; RNi; +252 --COUNTR; RD; +253 DLY; +254 eSI = SIGMA; if (!INTERRUPT_REQUESTED) goto REP_LODS_LOOP; +255 eAX_AL = OPR_R; UNL; +256 eCX = COUNTR; if (COUNTR == 0) goto REP_LODS_DONE; // Jump if COUNTR == 0? The goto here is just so that the RNi on line 257 will be activated +257 DES_OS; IND = ESI; SIGMA = ESI + INCREM; RNi; DLY; +258 goto RPTI; +259 +------------------------------------------|---------------------------------------------------------------------------------------------- +25A DES_OS; IND = ESI; SIGMA = ESI + INCREM; DLY; // 0 LODS +25B RD; +25C DLY; +25D eSI = SIGMA; RNI; +25E eAX_AL = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +25F DES_OS; IND_DELTA = EBX; IND = eAX_AL + IND_DELTA; DLY; // 0 XLATB +260 RD; +261 DLY; RNI; +262 eAX_AL = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +263 COUNTR = eCX; goto REP_STOS_LOOP; // 0 REP STOS +264 REP_STOS_DONE: // Just a convenient place for the jumps on lines 265 and 26a to have their destinations +265 REP_STOS_LOOP: eCX = COUNTR; if (COUNTR == 0) goto REP_STOS_DONE; // Jump if COUNTR == 0? The goto here is just so that the RNi on line 266 will be activated +266 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNi; +267 OPR_W = EAX; --COUNTR; WR; +268 DLY; if (!INTERRUPT_REQUESTED) goto REP_STOS_LOOP; +269 eDI = SIGMA; +26A eCX = COUNTR; if (COUNTR == 0) goto REP_STOS_DONE; // Jump if COUNTR == 0? The goto here is just so tha tthe RNi on line 26b will be activated +26B DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNi; +26C goto RPTI; +26D +------------------------------------------|---------------------------------------------------------------------------------------------- +26E DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; // 0 STOS +26F OPR_W = EAX; WR; +270 DLY; RNI; +271 eDI = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +272 if (CPL <= IOPL) goto IN_IMM_NOCHK // 0 p IN A,ib +273 DES_IO; IND = IMM; SIGMA = IMM; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +274 PORTIO_PROTCHK(); // 0 r IN A,ib +275 DES_IO; SIGMA = IMM; IND = IMM; DLY; +276 IN_IMM_NOCHK: RD; +277 DLY; RNI; +278 IN_DONE: EAX = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +279 if (CPL <= IOPL) goto IN_DX_NOCHK; // 0 p IN A,DX +27A SIGMA = EDX & 0xffff; // 0 r IN A,DX +27B PORTIO_PROTCHK(); +27C IN_DX_NOCHK: DES_IO; IND = SIGMA; DLY; +27D RD; goto IN_DONE; +27E DLY; RNi; +------------------------------------------|---------------------------------------------------------------------------------------------- +27F if (CPL <= IOPL) goto INS_NOCHK; // 0 p INS +280 DES_ES; DLY; IND = EDI; +------------------------------------------|---------------------------------------------------------------------------------------------- +281 PORTIO_PROTCHK(); // 0 r INS +282 SIGMA = EDX & 0xffff; +283 DES_ES; IND = EDI; DLY; +284 INS_NOCHK: SIGMA = EDX & 0xffff; CW; +285 DES_IO; IND = SIGMA; DLY; +286 RD; +287 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; +288 wr; UNL; RNI; +289 eDI = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +28A if (CPL <= IOPL) goto REP_INS_NOCHK; // 0 p REP INS +28B COUNTR = eCX; // 0 r REP INS +28C PORTIO_PROTCHK(); +28D REP_INS_NOCHK: SIGMA = EDX & 0xffff; +28E TMPC = SIGMA; if (COUNTR != 0) goto REP_INS_NOT0; +28F DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNI; +290 REP_INS_DONE: eCX = COUNTR; +291 REP_INS_LOOP: eDI = SIGMA; UNL; wr; if (COUNTR == 0) goto REP_INS_DONE; +292 DES_ES; IND = EDI; SIGMA = EDI + INCREM; DLY; RNi; +293 REP_INS_NOT0: eCX = COUNTR; --COUNTR; CW; +294 DES_IO; IND = TMPC; DLY; +295 RD; if (!INTERRUPT_REQUESTED) goto REP_INS_LOOP; +296 DES_ES; DLY; IND = EDI; +297 eDI = SIGMA; UNL; wr; if (COUNTR == 0) goto REP_INS_DONE; +298 DES_ES; SIGMA = EDI + INCREM; IND = EDI; DLY; RNi; +299 goto RPTI; +29A eCX = COUNTR; +------------------------------------------|---------------------------------------------------------------------------------------------- +29B if (CPL <= IOPL) goto OUT_IMM_NOCHK; // 0 p OUT ib,A +29C DES_IO; SIGMA = IMM; IND = IMM; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +29D PORTIO_PROTCHK(); // 0 r OUT ib,A +29E DES_IO; SIGMA = IMM; IND = IMM; DLY; +29F OUT_IMM_NOCHK: OPR_W = EAX; WR; RNI; +2A0 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +2A1 if (CPL <= IOPL) goto OUT_DX_NOCHK; // 0 p OUT DX,A +2A2 SIGMA = EDX & 0xffff; // 0 r OUT DX,A +2A3 PORTIO_PROTCHK(); +2A4 OUT_DX_NOCHK: DES_IO; DLY; IND = SIGMA; +2A5 OPR_W = EAX; WR; RNI; +2A6 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +2A7 if (CPL <= IOPL) goto OUTS_NOCHK; // 0 p OUTS +2A8 DES_OS; SIGMA = ESI + INCREM; IND = ESI; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +2A9 PORTIO_PROTCHK(); // 0 r OUTS +2AA SIGMA = EDX & 0xffff; +2AB DES_OS; SIGMA = ESI + INCREM; IND = ESI; DLY; +2AC OUTS_NOCHK: TMPB = SIGMA; RD; +2AD SIGMA = EDX & 0xffff; +2AE DES_IO; IND = SIGMA; DLY; +2AF eSI = TMPB; wr; UNL; RNI; +2B0 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +2B1 if (CPL <= IOPL) goto REP_OUTS_NOCHK; // 0 p REP OUTS +2B2 COUNTR = eCX; // 0 r REP OUTS +2B3 PORTIO_PROTCHK(); +2B4 REP_OUTS_NOCHK: SIGMA = EDX & 0xffff; +2B5 TMPC = SIGMA; if (COUNTR != 0) goto REP_OUTS_NOT0; +2B6 DES_OS; SIGMA = ESI + INCREM; IND = ESI; DLY; RNI; +2B7 REP_OUTS_DONE: // Just a convenient place for the jumps on lines 2b8 and 2bd to have their destinations +2B8 REP_OUTS_LOOP: DES_OS; DLY; IND = TMPB; if (COUNTR == 0) goto REP_OUTS_DONE; // The goto here is just so that the RNi on line 2b9 will be activated +2B9 eSI = TMPB; SIGMA = TMPB + INCREM; UNL; RNi; +2BA REP_OUTS_NOT0: TMPB = SIGMA; --COUNTR; RD; +2BB DES_IO = TMPC; IND = TMPC; DLY; if (!INTERRUPT_REQUESTED) goto REP_OUTS_LOOP; +2BC eCX = COUNTR; wr; +2BD DES_OS; IND = TMPB; DLY; if (COUNTR == 0) goto REP_OUTS_DONE; // The goto here is just so that the RNi on line 2bd will be activated +2BE eSI = TMPB; SIGMA = TMPB + INCREM; UNL; RNi; +2BF goto RPTI; +2C0 +------------------------------------------|---------------------------------------------------------------------------------------------- +2C1 PORTIO_PROTCHK: if (PM && CPL > 0) goto IO_PERM_BITMAP; // Skip IO permission bitmap check in real mode case (in protected mode case we've already checked for CPL <= IOPL and skipped calling this routine if so) +2C2 TMPB = SIGMA; SIGMA = NEGWSZ; // TMPB = IO_PORT (to check) +2C3 goto PORTIO_ALLOWED; +2C4 IO_PERM_BITMAP: SIGMA += NEGWSZ; // SIGMA = 2*NEGWSZ +2C5 TMPD = SIGMA; SIGMA = 6; // TMPD = 2*NEGWSZ (So -2, -4 or -8 depending on word size i.e. 0xfffffffe, 0xfffffffc or 0xfffffff8) +2C6 DES_TR; IND_DELTA = 0x60; IND = SIGMA + IND_DELTA; BITS32; DLY; // Access TSS. IND = 0x66 = address of I/O MAP BASE pointer in TSS +2C7 SLCTR2 = 0; SHRCNT = 3; RD_W; // Read IO_MAP_BASE +2C8 PROTUN = 0; SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 3 = byte in bitmap to look at +2C9 TMPC = SIGMA; DLY; PTGEN READ_RPL; // (L) TMPC = TMPB >> 3 From APRL it seems like READ_RPL copies PROTUN.RPL into latch. So this zeroes latch - what for? We don't do anything else with latch here. Used for privilege level check in TST_POIRTIO_BIT? +2CA SIGMA = OPR_R & 0xffff; UNL; +2CB DES_TR; DLY; IND_DELTA = TMPC; IND = SIGMA + IND_DELTA; // IND = (TMPB >> 3) + IO_MAP_BASE +2CC SIGMA = TMPB & 7; RD_W; // SIGMA = bit address within byte Read a word because our mask might straddle 2 bytes +2CD TMPC = SIGMA; if (BITS == 16) goto PORTIO_16BIT; // TMPC = TMPB & 7 Why, in 16-bit mode, do we skip the shift and looking at the value from the bitmap? - seems like this will cause it to always fault +2CE SIGMA = TMPD ^ -1; // SIGMA = ~(2*NEGWSZ) = 1, 3 or 7 = mask to test against. Hmm, shouldn't it be 15 in the dword case? Is NEGWSZ -8 in this case rather than -4? +2CF TMPD = SIGMA; SHLCNT = TMPC & 0x1f; // TMPD = ~(2*NEGWSZ) +2D0 SIGMA = (0:TMPD) << SHLCNT; // SIGMA = (~(2*NEGWSZ)) << (IO_PORT & 7) Surprising that the read bit mask word isn't shifted right instead +2D1 TMPD = SIGMA; BITSDE; DLY; // TMPD = (~(2*NEGWSZ)) << (IO_PORT & 7) +2D2 SIGMA = OPR_R & TMPD; UNL; // SIGMA = OPR_R & ((~(2*NEGWSZ)) << (IO_PORT & 7)) = masked bits +2D3 PORTIO_16BIT: PROTUN = SIGMA; PTSELA TST_PORTIO_BIT; // TST_PORTIO_BITMAP can continue (if both bits b and e are 1) or go to #GP(0) (otherwise) Test here should be SIGMA != 0 +2D4 PORTIO_ALLOWED: RETURN; +2D5 DES_IO; SIGMA = TMPB; IND = TMPB; +------------------------------------------|---------------------------------------------------------------------------------------------- +2D6 if (PM) goto CALL_FAR_PM; // 2 CALL cp +2D7 TMPG = IMM; COUNTR = IMM8; // COUNTR is the selector of the destination in CALL_FAR_PM, and TMPG is the offset +2D8 OPR_W = CS; WR; goto CALL_FAR_RM; +2D9 DLY; IND_DELTA = NEGWSZ; IND += IND_DELTA; +------------------------------------------|---------------------------------------------------------------------------------------------- +2DA RD; // 1 CALL mp +2DB IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +2DC TMPG = OPR_R; UNL; RD_W; +2DD DLY; if (PM) goto CALL_FAR_PM; +2DE COUNTR = OPR_R; UNL; // COUNTR is the selector of th destination in CALL_FAR_PM, and TMPG is the offset +2DF DESSTK; SIGMA = ESP + NEGWSZ; DLY; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; +2E0 OPR_W = CS; WR; +2E1 IND_DELTA = NEGWSZ; IND += IND_DELTA; DLY; +2E2 CALL_FAR_RM: SIGMA += NEGWSZ; +2E3 OPR_W = EIP; WR; goto JUMP_FAR_RM; +2E4 eSP = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +2E5 if (PM) goto JUMP_FAR_PM; // 0 JMP cp +2E6 TMPG = IMM; COUNTR = IMM8; // TMPG is the new offset, COUNTR is the new segment/selector +2E7 IRF2 = DES_CS.AR; DLY; // Real mode handling +2E8 SIGMA = IRF2 & 0xffff0000; // Keep base address bits 24-31, G, DB, A, Limit bits 16-19. Clear P/DPL/S/Type and base address 16-23 +2E9 SIGMA |= 0x8200; // Set to P=1, DPL=0, S=0, Type=2 (LDT)? +2EA DES_CS.AR = SIGMA; DLY; // Setting limit bits 16..19, A, DB, G, and base bits 24..31 as well? +2EB JMP_FAR_RM: IRF2 = DES_CS.LIMIT; DLY; +2EC TMPB = IRF2; +2ED JMP_FAR_RM_1: DES_CS.BASE = COUNTR << 4; SIGMA = COUNTR; // Seems like SBRM doesn't change AR field SIGMA = segment +2EE DES_CS.LIMIT = TMPB; // Re-install limit? +2EF PAGER5.PCR; // paging hint? It'd have to be DES_CS.BASE + TMPG +2F0 JMP_FAR_COMMON: DESCOD; DLY; IND = TMPG; +2F1 JMP_FAR_DONE: eIP = TMPG; PREF; // Start prefetching before CS set? Or does it not take effect for a couple of cycles? +2F2 PROTUN = 0; DLY; // Why do we set PROTUN here? +2F3 CS = SIGMA; RNI; +2F4 +------------------------------------------|---------------------------------------------------------------------------------------------- +2F5 RD; // 1 JMP mp +2F6 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +2F7 TMPG = OPR_R; UNL; RD_W; +2F8 DLY; if (PM) goto JUMP_FAR_PM; +2F9 COUNTR = OPR_R; UNL; +2FA IRF2 = DES_CS.LIMIT; DLY; goto JMP_FAR_RM_1; +2FB TMPB = IRF2; +------------------------------------------|---------------------------------------------------------------------------------------------- +2FC SIGMA += WORDSZ; RD; // 3 RETF/RETF iw +2FD IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +2FE SIGMA += IMM; RD; +2FF TMPG = OPR_R; UNL; +300 DLY; if (PM) goto RETF_PM; +301 COUNTR = OPR_R; UNL; +302 eSP = SIGMA; goto JMP_FAR_RM; +303 +------------------------------------------|---------------------------------------------------------------------------------------------- +304 ENTER_COMMON(); // 2 ENTER (16-bit?) +305 eSP = SIGMA; SIGMA = IMM8; // Seems like this PASS2 is immediately overwritten? No, this happens before ENTER_COMMON() +306 SIGMA = TMPC; DLY; RNI; +307 BP = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +308 ENTER_COMMON(); // 2 ENTER (32-bit?) Why are these separate routines? +309 eSP = SIGMA; SIGMA = IMM8; +30A SIGMA = TMPC; DLY; RNI; +30B EBP = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +30C ENTER_COMMON: COUNT5 = SIGMA; +30D SIGMA = ESP - IMM; +30E OPR_W = EBP; WR; if (COUNTR == 0) goto ENTER_DONE; +30F DLY; if (COUNTR == 1) goto ENTER_LASTW; +310 IND_DELTA = NEGWSZ; IND += IND_DELTA; SIGMA += NEGWSZ; +311 DESSTK; SIGMA = EBP + NEGWSZ; IND_DELTA = NEGWSZ; IND = EBP + IND_DELTA; +312 TMPB = SIGMA; --COUNTR; RD; +313 DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; +314 eSP = SIGMA; wr; if (COUNTR == 1) goto ENTER_LAST; +315 DESSTK; SIGMA = TMPB + NEGWSZ; DLY; IND_DELTA = NEGWSZ; IND = TMPB + IND_DELTA; +316 ENTER_LOOP: TMPB = SIGMA; --COUNTR; RD; +317 DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; DLY; +318 eSP = SIGMA; if (COUNTR != 1) goto ENTER_LOOP; UNL; wr; +319 DESSTK; SIGMA = TMPB + NEGWSZ; IND_DELTA = NEGWSZ; IND = TMPB + IND_DELTA; DLY; // Pointless ADD and IN=+? Not if the jump to 316 is taken +31A ENTER_LAST: DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NGEWSZ; IND = ESP + IND_DELTA; UNL; +31B SIGMA -= IMM; +31C ENTER_LASTW: OPR_W = TMPC; WR; +31D ENTER_DONE: DESSTK; IND = SIGMA; DLY; RETURN; +31E eSP = SIGMA; CW; +------------------------------------------|---------------------------------------------------------------------------------------------- +31F DESSTK; SIGMA = EBP + WORDSZ; DLY; IND = EBP; DLY; // 0 LEAVE (16-bit?) +320 eSP = SIGMA; RD; +321 DLY; RNI; +322 BP = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +323 DESSTK; SIGMA = EBP + WORDSZ; DLY; IND = EBP; DLY; // 0 LEAVE (32-bit?) Why are these separate routines? +324 eSP = SIGMA; RD; +325 DLY; RNI; +326 EBP = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +327 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 HLT +328 DESABS; IND = 2; ICESIG; // ICESIG runs even in NO_PRIVILEGE case "For a halt condition, BE2# is active." (HRM 3.1.8) +329 HLT_SHUTDOWN: HLTS; // "A halt or shutdown signal is initiated by activatin ADS# and the bus status pins as follows: M/IO# and W/R# are driven high, and D/C# is driven low" +32A DLY; +32B RPT; WIO; +32C RNI; +32D +------------------------------------------|---------------------------------------------------------------------------------------------- +32E PTR = &DESIDT; if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 LIDT mw +32F SHLCNT = BITS_V; +330 RD_W; goto LIDTGDT_COMMON; +331 DLY; IND_DELTA = 2; IND += IND_DELTA; +------------------------------------------|---------------------------------------------------------------------------------------------- +332 PTR = &DESGDT; if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 LGDT mw +333 SHLCNT = BITS_V; // 15 or 31 +334 RD_W; +335 IND_DELTA = 2; IND += IND_DELTA; DLY; +336 LIDTGDT_COMMON: SIGMA = (0xffffffff:0x000001ff) << SHLCNT; RD_D; // SIGMA = 0xffffffff (32-bit mode) or 0xffffff (16-bit mode) +337 TMPB = SIGMA; +338 SIGMA = OPR_R & 0xffff; UNL; +339 DESPTR->LIMIT = SIGMA; DLY; +33A SIGMA = OPR_R & TMPB; UNL; +33B DESPTR->BASE = SIGMA; RNI; +33C +------------------------------------------|---------------------------------------------------------------------------------------------- +33D IRF2 = DESIDT.BASE; DLY; // 0 SIDT mw +33E TMPC = IRF2; goto SIDTGDT_COMMON; +33F IRF2 = DESIDT.LIMIT; +------------------------------------------|---------------------------------------------------------------------------------------------- +340 IRF2 = DESGDT.BASE; DLY; // 0 SGDT mw +341 TMPC = IRF2; +342 IRF2 = DESGDT.LIMIT; +343 SIDTGDT_COMMON: TMPB = IRF2; // TMPB = limit, TMPC = base +344 DES_OS; IND_DELTA = 0; IND = EA + IND_DELTA; DLY; // Why set IND_DELTA = 0? +345 OPR_W = TMPB; WR_W; +346 IND_DELTA = 2; IND += IND_DELTA; DLY; +347 OPR_W = TMPC; WR_D; RNI; +348 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +349 if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 LMSW mw +34A SIGMA = CR0 & 1; +34B TMPB = SIGMA; RD_W; +34C DLY; goto LMSW_COMMON; +34D SIGMA = OPR_R | TMPB; UNL; // SIGMA = OPR_W | (CR0 & 1); Can't use LMSW to switch back to real mode +------------------------------------------|---------------------------------------------------------------------------------------------- +34E if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 LMSW rw +34F SIGMA = CR0 & 1; +350 SIGMA |= DSTREG; // SIGMA = (CR0 & 1) | DSTREG; +351 LMSW_COMMON: SIGMA &= 0x0f; // SIGMA = ((CR0 & 1) | rmw) & 0x0f +352 TMPB = SIGMA; // TMPB = ((CR0 & 1) | rmw) & 0x0f +353 SIGMA = -1 ^ 0x0f; // SIGMA = 0xfffffff0 +354 TMPC = SIGMA; // TMPC = 0xfffffff0 +355 SIGMA = CR0 & TMPC; // SIGMA = CR0 & 0xfffffff0 +356 SIGMA |= TMPB; RNI; // SIGMA = (CR0 & 0xfffffff0) | (((CR0 & 1) | rmw) & 0x0f) +357 CR0 = SIGMA; // CR0 = (CR0 & 0xfffffff0) | (((CR0 & 1) | rmw) & 0x0f) +------------------------------------------|---------------------------------------------------------------------------------------------- +358 DSTREG = CR0; RNI; // 0 SMSW rw +359 +------------------------------------------|---------------------------------------------------------------------------------------------- +35A OPR_W = CR0; WR_W; RNI; // 1 SMSW mw +35B DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +35C if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV CR0,rd +35D BITS32; +35E TMPB = SRCREG; SHLCNT = 1; +35F SIGMA = (TMPB:TMPB) << SHLCNT; // SIGMA = SRCREG rotl 1? +360 SIGMA &= 3; // SIGMA = (SRCREG rotl 1) & 3? +361 COUNTR = SIGMA; // COUNTR = (SRCREG rotl 1) & 3? +362 // Why do we have a blank line? +363 if (COUNTR == 1) goto PAGING_RM; // Setting system to real mode with paging? +364 SIGMA = TMPB; RNI; +365 CR0 = SIGMA; +366 PAGING_RM: goto #GP/#TS(I0,E0); // It's #GP here +367 SLCTR2 = 0; PTGEN SET_FAULT; +------------------------------------------|---------------------------------------------------------------------------------------------- +368 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV CR2,rd +369 BITS32; +36A CR2 = SRGREG; RNI; // CR2 is Page Fault Linear Address +36B +------------------------------------------|---------------------------------------------------------------------------------------------- +36C if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV CR3,rd +36D BITS32; +36E DESABS; IND = SRCREG; // CR3 == PDBR == Page Directory Base Register +36F PDBR.PCR = IND; RNI; // Sets PDBR = SRCREG and flushes TLB cache (same as 794) +370 PDBR; DLY; // Not sure why we reference PDBR again again here +------------------------------------------|---------------------------------------------------------------------------------------------- +371 goto STORE_CR; // 0 MOV rd,CR0 Not sure why we have this apparently pointless jump +372 SIGMA = CR0; +373 STORE_CR: if (PM && CPL > 0) goto NO_PRIVILEGE; +374 BITS32; +375 RNI; +376 DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +377 goto STORE_CR; // 0 MOV rd,CR2 +378 SIGMA = CR2; +------------------------------------------|---------------------------------------------------------------------------------------------- +379 IRF2 = PDBR.PCR; goto STORE_CR; // 0 MOV rd,CR3 +37A PDBR; SIGMA = IRF2; DLY; // Not sure why we reference PDBR again again here +------------------------------------------|---------------------------------------------------------------------------------------------- +37B GENERAL_DETECT(); // 0 MOV DR4/6,rd +37C if (PM && CPL > 0) goto NO_PRIVILEGE; +37D DR6 = SRCREG; goto LD_DR4567_DONE; // Seems like we need an empty cycle in between loading a DR and the RNI +37E +------------------------------------------|---------------------------------------------------------------------------------------------- +37F GENERAL_DETECT(); // 0 MOV DR5/7,rd +380 if (PM && CPL > 0) goto NO_PRIVILEGE; +381 DR7 = SRCREG; +382 +383 LD_DR4567_DONE: RNI +384 +------------------------------------------|---------------------------------------------------------------------------------------------- +385 SELECT_DR_TR: SIGMA = (IMM:IMM) >> SHRCNT; // IMM here must be the modrm byte, not the opcode like in LSS/LFS/LGS SHRCNT is always 3 here +386 SIGMA &= 7; +387 SIGMA |= 0x70; +388 COUNTR = SIGMA; RETURN; // COUNTR vlues for DR/TR registers are 0x70-0x77 +389 +------------------------------------------|---------------------------------------------------------------------------------------------- +38A GENERAL_DETECT(); // 0 MOV DR0-3,rd +38B if (PM && CPL > 0) goto no_PRIVILEGE; +38C SELECT_DR_TR(); // register-indexing bits are 3-5 +38D SHRCNT = 3; // For use in SELECT_DR_TR +38E IRF[COUNTR].BASE = SRCREG; DLY; +38F DESABS; IND = 0; DLY; RNI; // Clear cached physical address? (maybe not, happens with "MOV rd,DR0-3" as well) +390 +------------------------------------------|---------------------------------------------------------------------------------------------- +391 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV TRn,rd +392 BITS32; +393 SELECT_DR_TR(); +394 SHRCNT = 3; +395 DESABS; DLY; IND = SRCREG; // TODO: compare this method of writing to TRn with methods of writing to other special registers, especially the ones involved in paging. +396 IRF[COUNTR].PCR; RNI; +397 IRF[COUNTR] = -1; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +398 GENERAL_DETECT: BITS32; +399 TMPB = DR7; SHLCNT = 0x0d; +39A SIGMA = (0:1) << SHLCNT; // SIGMA = 1 << 13 = 0x2000 +39B TMPC = SIGMA; SIGMA &= TMPB; // TMPC = 1 << 13 = 0x2000 SIGMA = DR7 & 0x2000 +39C COUNTR = SIGMA; // COUNTR = DR7 & 0x2000 +39D +39E if (COUNTR != 0) goto GD_HIT; // DR7 bit 13 is GD = General Detect Enable. If set, will cause a debug exception on any attempt at accessing the DR0-DR7 registers. +39F +3A0 RETURN; +3A1 +------------------------------------------|---------------------------------------------------------------------------------------------- +3A2 GD_HIT: EIP = TMPeIP; ICEBRK; +3A3 SIGMA = DR6 | TMPC; +3A4 goto BREAKPOINT_CMN; +3A5 DR6 = SIGMA; BITS32; +------------------------------------------|---------------------------------------------------------------------------------------------- +3A6 GENERAL_DETECT(); // 0 MOV rd,DR4/6 +3A7 if (PM && CPL > 0) goto NO_PRIVILEGE; +3A8 SIGMA = DR6; RNI; // RNI must be suppressed if it's in the delay slot +3A9 DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +3AA GENERAL_DETECT(); // 0 MOV rd,DR5/7 +3AB if (PM && CPL > 0) goto NO_PRIVILEGE; +3AC SIGMA = DR7; RNI; +3AD DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +3AE GENERAL_DETECT(); // 0 MOV rd,DR0-3 +3AF if (PM && CPL > 0) goto NO_PRIVILEGE; +3B0 SELECT_DR_TR(); +3B1 SHRCNT = 3; DLY; +3B2 IRF2 = IRF[COUNTR].BASE; +3B3 DSTREG = IRF2; +3B4 DESABS; IND = 0; DLY; RNI; +3B5 +------------------------------------------|---------------------------------------------------------------------------------------------- +3B6 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 MOV rd,TRn +3B7 BITS32; +3B8 SELECT_DR_TR(); +3B9 SHRCNT = 3; DLY; +3BA IRF2 = IRF[COUNTR].PCR; +3BB IRF[COUNTR] = IRF2; SIGMA = IRF2; DLY; RNI; +3BC DSTREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +3BD PROTUN = CR0; PTGEN FPU_WAIT; // 0 WAIT FPU_WAIT can go to #NM if TS && MP (g==1 && i==1) (#NM) or continue +3BE WAIT_LOOP: if (!BUSY# && !ERROR#) goto WAIT_DONE; // WAIT is supposed to wait until BUSY# is high, and #MF if ERROR# +3BF if (ERROR#) goto WAIT_ERRT; // 3c5 is a subroutine to help implement the test "if (JBUSY# && JPEREQ) goto #MF6" +3C0 +3C1 WAIT_IRQT: if (!INTERRUPT_REQUESTED) goto WAIT_LOOP; +3C2 +3C3 goto RPTI; +3C4 +------------------------------------------|---------------------------------------------------------------------------------------------- +3C5 WAIT_ERRT: if (!PEREQ) goto #MF6; // WAIT does #MF (Interrupt 0x10 ÄÄ Coprocessor Error) if the ERROR# input pin is asserted (i.e., the 80287 has detected an unmasked numeric error). Which of these is ERROR and what is the other? +3C6 +3C7 goto WAIT_IRQT; +3C8 WAIT_DONE: +3C9 RNI; +3CA +------------------------------------------|---------------------------------------------------------------------------------------------- +3CB #MF6: goto FAULT; +3CC SIGMA = 0x10; // "Interrupt 16 ÄÄ Coprocessor Error" (#MF) +------------------------------------------|---------------------------------------------------------------------------------------------- +3CD PROTUN = CR0; PTGEN FPU_OTHER; // 0 FENI/FDISI/FCLEX/FINIT/FSETPM/FRSTPM FPU_OTHER goes to #NM or continues +3CE RPT; // Exhaust a cycle of the PTGEN? +3CF DES_IO; IND = 0x800000f8; DLY; +3D0 OPR_W = IMM; BITS32; WR_W; +3D1 FPU_FLAG_LOOP: ICESIG; DLY; +3D2 +3D3 if (JICEWT) goto FPU_FLAG_LOOP; +3D4 DESCOD; IND = EIP; +3D5 PREF; // These instructions need to restart prefetching for some reason? Same reason that CLI/STI do? +3D6 DLY; +3D7 RNI; +3D8 +------------------------------------------|---------------------------------------------------------------------------------------------- +3D9 MISC1 = true; // 0 FSTCW/FSTSW mw +3DA PROTUN = CR0; PTGEN FPU_OTHER; // 0 FSTSW AX/FNSTDW AX (387SL only?)/FNSTSG AX (387SL only?) FPU_OTHER goes to #NM or continues +3DB FPU_MISC_WAIT: if (!PEREQ) goto FPU_MISC_CORE; +3DC +3DD // Why two blank lines? To avoid hitting the delay slots of the PTGEN on line 3da? +3DE if (!INTERRUPT_REQUESTED) goto FPU_MISC_WAIT; +3DF +3E0 goto RPTI; +3E1 +------------------------------------------|---------------------------------------------------------------------------------------------- +3E2 FPU_MISC_CORE: IND = 0x800000f8; SIGMA = 0x800000f8; DES_IO; +3E3 OPR_W = IMM; WR_W; // Write IMM to FPU command port +3E4 DES_IO; IND = SIGMA; DLY; if (MISC1) goto FPU_MISC_WRITE; +3E5 RD_W; // Read from FPU status port +3E6 DLY; RNI; +3E7 AX = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +3E8 FPU_MISC_WRITE: DES_OS; IND_DELTA = 0; IND = EA + IND_DELTA; DLY; // Why set IND_DELTA = 0? This handles FSTCW/FSTSW mw +3E9 wr_W; UNL; RNI; +3EA DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +3EB #MF5: goto FAULT; // Unreachable? +3EC SIGMA = 0x10; // "Interrupt 16 ÄÄ Coprocessor Error" +------------------------------------------|---------------------------------------------------------------------------------------------- +3ED PROTUN = CR0; PTGEN FPU_OTHER; // 1 FSTENV m FPU_OTHER goes to #NM or continues +3EE DLY; goto FSAVE_WAIT; +3EF TMPG = IRF2; IND_DELTA = 0x0d; IND += IND_DELTA; MISC1 = true; // MISC1 is flag to say we're doing an FLDENV and not FRSTOR, tested by JMISC1 IND = dest + 0x0d +------------------------------------------|---------------------------------------------------------------------------------------------- +3F0 PROTUN = CR0; PTGEN FPU_OTHER; // 1 FSAVE m FPU_OTHER goes to #NM or continues +3F1 DLY; goto FSAVE_WAIT; // pointless jump? +3F2 TMPG = IRF2; IND_DELTA = 0x5d; IND += IND_DELTA; // IND = dest + 0x5d +------------------------------------------|---------------------------------------------------------------------------------------------- +3F3 FSAVE_WAIT: SIGMA = WORDSZ; // SIGMA = 2 or 4 +3F4 if (!PEREQ) goto FSAVE_CORE; // JPEREQ is jump if FPU ready? +3F5 SHLCNT = 3; +3F6 if (!INTERRUPT_REQUESTED) goto FSAVE_WAIT; +3F7 +3F8 goto RPTI; +3F9 +------------------------------------------|---------------------------------------------------------------------------------------------- +3FA FSAVE_CORE: SIGMA -= 2; // SIGMA = 0 or 2 +3FB TMPC = SIGMA; // TMPC = 0 or 2 +3FC SIGMA = (0:TMPC) << SHLCNT; // SIGMA = 0 or 16 SHLCNT is always 3 here +3FD SIGMA -= WORDSZ; // SIGMA = -2 or 12 +3FE TMPC = SIGMA; BITS32; // TMPC = -2 or 12 BITS32 changes ALU but not WORDSZ or bus +3FF IND_DELTA = TMPC; IND += IND_DELTA; DLY; // IND = dest + (0x0d or 0x5d) + (-2 or 12) +400 SHRCNT = 0x10; CW_B; // limit should be (0x0d or 0x1b) for FSTENV or (0x5d or 0x6b) for FSAVE - IND here is (dest?+) (0x0b or 0x19) or (0x5b or 0x69) - two less than limit +401 DES_OS; IND = TMPG; DLY; // IND = IRF2 +402 TMPC = CSOPCD; CW_B; // checking start as well? +403 DES_IO; IND = 0x800000f8; DLY; +404 OPR_W = IMM; WR_W; // Write opcode? +405 SIGMA = (0:TMPC) >> SHRCNT; // SIGMA = CSOPCD >> 16 = CS from CSOPCD? +406 TMPC = SIGMA; BITSDE; // TMPC = CSOPCD >> 16 = CS from CSOPCD? +407 FSAVE_COR_WAIT: if (!PEREQ) goto FSAVE_COR_WAIT; +408 TMPH = TMPG; // TMPH is detination that FSAVE_REGFILE writes to +409 FSAVE_REGFILE(); // First call to FSAVE_REGFILE has COUNTR = 3 and MISC2 = false => read 3 vwords and store (control/status/tag) +40A COUNTR = 3; +40B TMPB = TMPH; COUNTR = 4; // TMPB = dest + (6 or 12) +40C FSAVE_REGFILE(); // Second call to FSAVE_REGFILE has COUNTR = 4 and MISC2 = true => read 4 vwords and discard (?/?/?/?) +40D MISC2 = true; +40E if (PM) goto FSAVE_PM; +40F DES_OS; IND = TMPB; DLY; +410 SIGMA = CSOPCD & 0xffff; // Handle real mode case +411 TMPB = SIGMA; BITS32; // TMPB = opcode (from CSOPCD) +412 SHLCNT = 4; +413 SIGMA = (0:TMPB) << 4; // SIGMA = opcode << 4 +414 TMPB = SIGMA; // TMPB = opcode << 4 +415 SIGMA = FSVeIP + TMPB; // SIGMA = (opcode << 4) + eIP +416 TMPB = SIGMA; // TMPB = (opcode << 4) + eIP +417 SIGMA = (0:TMPC) << 4; // SIGMA = CS << 4 +418 TMPC = SIGMA; // TMPC = CS << 4 +419 SIGMA = OPROFF + TMPC; // SIGMA = OPROFF + (CS << 4) +41A TMPG = SIGMA; SHRCNT = 4; // TMPG = OPROFF + (CS << 4) +41B SIGMA = TMPG & 0xffff0000; // SIGMA = (OPROFF + (CS << 4)) & 0xffff0000 +41C TMPD = SIGMA; // TMPD = (OPROFF + (CS << 4)) & 0xffff0000 +41D SIGMA = (0:TMPD) >> 4; // SIGMA = ((OPROFF + (CS << 4)) & 0xffff0000) >> 4 +41E TMPE = SIGMA; // TMPE = ((OPROFF + (CS << 4)) & 0xffff0000) >> 4 +41F SIGMA = TMPB & 0xffff0000; // SIGMA = ((opcode << 4) + eIP) & 0xffff0000 +420 TMPD = SIGMA; // TMPD = ((opcode << 4) + eIP) & 0xffff0000 +421 SIGMA = (0:TMPD) >> 4; // SIGMA = (((opcode << 4) + eIP) & 0xffff0000) >> 4 +422 TMPD = SIGMA; BITS16; // TMPD = (((opcode << 4) + eIP) & 0xffff0000) >> 4 +423 TMPC = TMPF; SHLCNT = 8; // TMPC = TMPF (where does this come from?) +424 SIGMA = (TMPC:TMPC) << 8; // SIGMA = (TMPF << 8) - does this swap the bytes? +425 BITSDE; // Could this be restoring instruction's original bit size? +426 OPR_W = TMPB; WR; // Write (opcode << 4) + eIP should be Instruction Pointer lower word (seems like it puts other stuff at 0x0e in 32-bit mode) +427 SIGMA &= 0x7ff; // SIGMA = (TMPF << 8) & 0x7ff +428 SIGMA |= TMPD; // SIGMA = ((TMPF << 8) & 0x7ff) | ((((opcode << 4) + eIP) & 0xffff0000) >> 4) +429 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +42A OPR_W = SIGMA; WR; // Write ((TMPF << 8) & 0x7ff) | ((((opcode << 4) + eIP) & 0xffff0000) >> 4) should be Opcode (0-0x7ff) + ((IP (upper word or upper 4 bits)) << 12) So TMPF is the opcode with the bytes swapped? +42B PROTUN = CR0; DLY; IND += IND_DELTA; PTGEN FPU_FSAVE; // FPU_FSAVE can go to FSAVE_387 or FSAVE_287 (always jumps) IND_DELTA set to WORDSZ at 429 +42C OPR_W = TMPG; COUNTR = 0x29; WR; // Write OPROFF + (CS << 4) should be Operand Pointer (lower word) +42D TMPB = COUNTR; SHRCNT = 1; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 429 +42E OPR_W = TMPE; WR; // Write ((OPROFF + (CS << 4)) & 0xffff0000) >> 4 should be operand pointer (upper word or 4 bits) << 12 ? +------------------------------------------|---------------------------------------------------------------------------------------------- +42F FSAVE_PM: OPR_W = FSVeIP; WR; // Write IP offset (address 6 or 12) +430 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +431 OPR_W = CSOPCD; WR; // Write Opcode:CS or CS (address 8 or 16) +432 PROTUN = CR0; DLY; IND += IND_DELTA; PTGEN FPU_FSAVE; // FPU_FSAVE can go to FSAVE_387 or FSAVE_287 (always jumps) IND_DELTA set to WORDSZ at 430 +433 OPR_W = OPROFF; COUNTR = 0x29; WR; // Write Operand Offset (address 10 or 20) +434 TMPB = COUNTR; SHRCNT = 1; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 430 +435 OPR_W = TMPC; WR; // Write Operand Selector (address 12 or 24) - write a dword though it's only a word long +------------------------------------------|---------------------------------------------------------------------------------------------- +436 FSAVE_REGFILE: DES_IO; IND = 0x800000fc; DLY; +437 FIO; WIO; if (MISC2) goto FSAVE_NOWRITE; +438 --COUNTR; RD; // Read data from FPU - first word/dword? +439 DES_OS; SIGMA = TMPH + WORDSZ; IND = TMPH; DLY; +43A TMPH = SIGMA; wr; if (COUNTR == 0) goto FSAVE_DONEFILE; // Write same data back to memory +43B UNL; +43C FSAVE_LOOP: SIGMA = 0x800000fc; DLY; +43D DES_IO; IND = SIGMA; FIO; WIO; if (MISC2) goto FSAVE_NOWRITE; // MISC2 causes the write back to be skipped +43E --COUNTR; RD; // Read data from FPU +43F DES_OS; SIGMA = TMPH + WORDSZ; DLY; IND = TMPH; // TMPH is address to write to +440 TMPH = SIGMA; wr; if (COUNTR != 0) goto FSAVE_LOOP; // Write same data back to memory TMPH += WORDSZ +441 UNL; +442 FSAVE_DONEFILE: DLY; RETURN; +443 +------------------------------------------|---------------------------------------------------------------------------------------------- +444 FSAVE_NOWRITE: DLY; +445 if (COUNTR != 0) goto FSAVE_LOOP; +446 SIGMA = TMPH + WORDSZ; UNL; +447 TMPH = SIGMA; RETURN; +448 +------------------------------------------|---------------------------------------------------------------------------------------------- +449 FSAVE_387: if (MISC1) goto FSAVE_DONE; // TMPB is 0x29 on entry +44A SIGMA = (0:TMPB) >> SHRCNT; // Shift right by 1 SIGMA = 20 SHRCNT is always 1 here +44B COUNTR = SIGMA; MISC2 = false; DLY; // COUNTR = 20 Number of DWords to transfer for ST(0)-ST(7) for 32-bit transfers +44C SIGMA = IRF2 + WORDSZ; IND_DELTA = WORDSZ; IND += IND_DELTA; +44D FSAVE_REGFILE(); +44E TMPH = SIGMA; BITS32; +44F RNI; +450 +------------------------------------------|---------------------------------------------------------------------------------------------- +451 FSAVE_287: if (MISC1) goto FSAVE_DONE; // TMPB = 0x29 on entry +452 SIGMA = TMPB - 1; // SIGMA = 40 +453 COUNTR = SIGMA; MISC2 = false; DLY; // COUNTR = 40 Number of Words to transfer for ST(0)-ST(7) for 16-bit transfers +454 SIGMA = IRF2 + WORDSZ; IND_DELTA = WORDSZ; IND += IND_DELTA; +455 FSAVE_REGFILE(); +456 TPHS = SIGMA; BITS16; +457 FSAVE_DONE: RNI; +458 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +459 PROTUN = CR0; PTGEN FPU_OTHER; // 1 FLDENV m FPU_OTHER goes to #NM or continues +45A DLY; goto FRSTOR_WAIT; +45B TMPG = IRF2; MISC1 = true; IND_DELTA = 0x0d; IND += IND_DELTA; // MISC1 is flag to say we're doing an FLDENV and not FRSTOR, tested by JMISC1 IND = src + 0x0d +------------------------------------------|---------------------------------------------------------------------------------------------- +45C PROTUN = CR0; PTOVRR FPU_OTHER; // 1 FRSTOR m FPU_OTHER goes to #NM or continues +45D DLY; goto FRSTOR_WAIT; +45E TMPG = IRF2; IND_DELTA = 0x5d; IND += IND_DELTA; // IND = src + 0x5d +------------------------------------------|---------------------------------------------------------------------------------------------- +45F #MF4: goto FAULT; +460 SIGMA = 0x10; // "Interrupt 16 ÄÄ Coprocessor Error" +------------------------------------------|---------------------------------------------------------------------------------------------- +461 FRSTOR_WAIT: SIGMA = WORDSZ; // SIGMA = 2 or 4 +462 if (!BUSY# && !ERROR#) goto FRSTOR_CORE; +463 SHLCNT = 3; +464 if (ERROR#) goto FRSTOR_ERRT; +465 +466 FRSTOR_IRQT: if (!INTERRUPT_REQUESTED) goto FRSTOR_WAIT; +467 +468 goto RPTI; +469 +------------------------------------------|---------------------------------------------------------------------------------------------- +46A FRSTOR_ERRT: if (!PEREQ) goto #MF4; +46B +46C goto FRSTOR_IRQT; +46D +------------------------------------------|---------------------------------------------------------------------------------------------- +46E FRSTOR_CORE: SIGMA -= 2; // SIGMA = 0 or 2 +46F TMPC = SIGMA; // TMPC = 0 or 2 +470 SIGMA = (0:TMPC) << SHLCNT; // SIGMA = 0 or 16 SHLCNT is always 3 here +471 SIGMA -= WORDSZ; // SIGMA = -2 or 12 +472 TMPC = SIGMA; SHLCNT = BITS_V; // TMPC = -2 or 12 SHLCNT = 15 or 31 +473 DLY; IND_DELTA = TMPC; IND += IND_DELTA; // IND = src + (0x0d or 0x5d) + (-2 or 12) +474 CR_B; SIGMA = 1; // limit should be (0x0d or 0x1b) for FLDENV or (0x5d or 0x6b) for FRSTOR - IND here is (dest?+) (0x0b or 0x19) or (0x5b or 0x69) - two less than limit. Mostly harmless bug? +475 DES_OS; DLY; IND = TMPG; // IND = IRF2 +476 TMPC = SIGMA; CR_B; // checking start as well? TMPC = 1 +477 DES_IO; DLY IND = 0x800000f8; +478 OPR_W = IMM; SIGMA = -1; WR_W; // Write opcode? +479 SIGMA = (SIGMA:TMPC) << SHLCNT; // SIGMA = (-1:1) << BITS_V = 0x0000ffff or 0xffffffff +47A +47B FRSTOR_CORWAIT: TMPC = SIGMA; if (!PEREQ) goto FRSTOR_CORWAIT; // Waiting for something? TMPC = 0x0000ffff or 0xffffffff +47C TMPH = TMPG; COUNTR = 3; // TMPH is destination that FRSTOR_REGFILE reads from +47D FRSTOR_REGFILE(); // First call to FSAVE_REGFILE has COUNTR = 3 => write 3 vwords (control/status/tag) +47E +47F FRSTOR_REGFILE(); // Second call to FSAVE_REGFILE has COUNTR = 4 => write 4 vwords (opcode/eIP/operand address/CS/operand selector) +480 TMPB = TMPH; COUNTR = 4; // TMPB = src + (6 or 12) +481 DES_OS; IND = TMPB; DLY; // IND = src + (6 or 12) +482 COUNTR = 0x29; RD; // Read eIP +483 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +484 if (PM) goto FRSTOR_PM; RD; // Read CS Selector or Opcode (0-0x7ff) + ((IP (upper word or 4 bits)) << 12) +485 SIGMA = OPR_R & 0xffff; UNL; // SIGMA = eIP & 0xffff +486 TMPB = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 483 TMPB = eIP & 0xffff real mode from here +487 SIGMA = OPR_R & TMPC; UNL; RD; // SIGMA = (Opcode (0-0x7ff) + ((IP (upper word or 4 bits)) << 12)) & (0x0000ffff or 0xffffffff)) Read operand offset +488 TMPD = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 483 TMPD = (Opcode (0-0x7ff) + ((IP (upper word or 4 bits)) << 12)) & (0x0000ffff or 0xffffffff)) +489 SHLCNT = 8; RD; // Read operand selector (or upper part of pointer) +48A SIGMA = OPR_R & 0xffff; UNL; // SIGMA = (operand offset) & 0xffff +48B TMPE = SIGMA; BITS16; DLY; // TMPE = (operand offset) & 0xffff +48C SIGMA = (TMPD:TMPD) << SHLCNT; // SIGMA = TMPD with bytes swapped? +48D TMPF = SIGMA; BITS32; // TMPF = TMPD with bytes swapped? +48E SHLCNT = 4; +48F CSOPCD = 0; SIGMA = (0:TMPD) << SHLCNT; // SIGMA = TMPD << 4 +490 SIGMA &= 0xffff0000; // SIGMA = (TMPD << 4) & 0xffff0000 +491 SIGMA |= TMPB; // SIGMA = ((TMPD << 4) & 0xffff0000) | (eIP & 0xffff) +492 FSVeIP = SIGMA; // FSVeIP = reconstructed from read values +493 SIGMA = OPR_R & TMPC; UNL; // SIGMA = (Read operand selector (or upper part of pointer)) & (0x0000ffff or 0xffffffff) +494 TMPD = SIGMA; // TMPD = (Read operand selector (or upper part of pointer)) & (0x0000ffff or 0xffffffff) +495 SIGMA = (0:TMPD) << SHLCNT; // SIGMA = ((Read operand selector (or upper part of pointer)) & (0x0000ffff or 0xffffffff)) << 4 +496 TMPB = TMPE; // TMPB = (operand offset) & 0xffff +497 PROTUN = CR0; PTGEN FPU_FRSTOR; // FPU_FRSTOR can go to FRSTOR_387 or FRSTOR_287 (always jumps) +498 SIGMA += TMPB; // SIGMA = ((operand offset) & 0xffff) + (((Read operand selector (or upper part of pointer)) & (0x0000ffff or 0xffffffff)) << 4) +499 OPROFF = SIGMA; // OPROFF = reconstructed from read values +49A TMPB = COUNTR; SHRCNT = 1; // TMPB = 0x29 +------------------------------------------|---------------------------------------------------------------------------------------------- +49B FRSTOR_PM: SIGMA = OPR_R & TMPC; // SIGMA = eIP & 0xffff +49C FSVeIP = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 483 +49D SIGMA = OPR_R & 0xffff; UNL; RD; +49E TMPD = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 483 +49F SIGMA = OPR_R & TMPC; UNL; RD; +4A0 OPROFF = SIGMA; BITS32; DLY; +4A1 TMPB = OPR_R; UNL; SHLCNT = 0x10; +4A2 SIGMA = (0:TMPB) << SHLCNT; +4A3 PROTUN = CR0; PTGEN FPU_FRSTOR; // FPU_FRSTOR can go to FRSTOR_387 or FRSTOR_287 (always jumps) +4A4 SIGMA |= SIGMA | TMPD; +4A5 CSOPCD = SIGMA: +4A6 TMPB = COUNTR; SHRCNT = 1; +------------------------------------------|---------------------------------------------------------------------------------------------- +4A7 FRSTOR_REGFILE: DES_OS; IND = TMPH; DLY; +4A8 --COUNTR; RD; +4A9 DES_IO; IND = 0x800000fc; DLY; +4AA SIGMA = TMPH + WORDSZ; +4AB TMPH = SIGMA; FIO; WIO; if (COUNTR == 0) goto FRSTOR_DONEFIL; +4AC UNL; wr; +4AD FRSTOR_LOOP: DES_OS; IND = TMPH; DLY; +4AE --COUNTR; RD; +4AF DES_IO; IND = 0x800000fc; DLY; +4B0 SIGMA = TMPH + WORDSZ; FIO; +4B1 TMPH = SIGMA; FIO; WIO; if (COUNTR != 0) goto FRSTOR_LOOP; +4B2 UNL; wr; +4B3 FRSTOR_DONEFIL: DLY; RETURN; +4B4 +------------------------------------------|---------------------------------------------------------------------------------------------- +4B5 FRSTOR_387: if (MISC1) goto FRSTOR_DONE: +4B6 SIGMA = (0:TMPB) >> SHRCNT; RNi; // SHRCNT is always 1 here +4B7 FRSTOR_REGFILE(); +4B8 COUNTR = SIGMA; BITS32; DLY; +4B9 RNI; +4BA FRSTOR_DONE: +------------------------------------------|---------------------------------------------------------------------------------------------- +4BB FRSTOR_287: if (MISC1) goto FRSTOR_DONE: +4BC SIGMA = TMPB - 1; RNi; +4BD FRSTOR_REGFILE(); +4BE COUNTR = SIGMA; BITS16; DLY; +4BF RNI; +4C0 +------------------------------------------|---------------------------------------------------------------------------------------------- +4C1 PROTUN = CR0; PTGEN FPU_OTHER; // 0 FP instructions that don't access memory FPU_OTHER goes to #NM or continues +4C2 FPU_REG_WAIT: if (!BUSY# && !ERROR#) goto FPU_REG_CORE; +4C3 if (ERROR#) goto FPU_REG_ERRT; +4C4 +4C5 FPU_REG_IRQT: if (!INTERRUPT_REQUESTED) goto FPU_REG_WAIT; +4C6 +4C7 goto RPTI; +4C8 +------------------------------------------|---------------------------------------------------------------------------------------------- +4C9 FPU_REG_ERRT: if (JPEREQ) goto #MF3; +4CA +4CB goto FPU_REG_IRQT; +4CC FPU_REG_CORE: DES_IO; SIGMA = IMM; IND = 0x800000f8; DLY; +4CD OPR_W = IMM; WR_W; +4CE FPU_REG_CORWAI: FSVeIP = TMPeIP; if (JPEREQ) goto FPU_REG_CORWAI; // Waiting for something? +4CF CSOPCD = CS; RNI; +4D0 TMPF = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +4D1 #MF3: goto FAULT; +4D2 SIGMA = 0x10; // "Interrupt 16 ÄÄ Coprocessor Error" +------------------------------------------|---------------------------------------------------------------------------------------------- +4D3 PROTUN = CR0; PTGEN FPU_LOAD_80; // 1 FBLD/FLD mt FPU_LOAD_80 can go to FPU_LD80_287, FPU_LD80_387, or #NM (always jumps) - transfer 10 bytes FPU -> bus +4D4 TMPB = OPCODE; SIGMA = 2; DLY; +4D5 TMPG = IRF2; IND_DELTA = 9; IND += IND_DELTA; BITS32; +4D6 COUNTR = SIGMA; SHLCNT = 0x10; // COUNTR = 2 +------------------------------------------|---------------------------------------------------------------------------------------------- +4D7 PROTUN = CR0; PTGEN FPU_LOAD_3264; // 1 FADD/FMUL/FCOM/FCOMP/FSUB/FSUBR/FDIV/FDIVR/FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FLD/FILD md FPU_LOAD_3264 can go to FPU_LD3264_287, FPU_LD3264_387 or #NM (always jumps) - transfer 4 bytes fPU -> bus +4D8 TMPB = OPCODE; SIGMA = 1; DLY; +4D9 TMPG = IRF2; IND_DELTA = 3; IND += IND_DELTA; BITS32; +4DA COUNR = SIGMA; SHLCNT = 0x10; // COUNTR = 1 +------------------------------------------|---------------------------------------------------------------------------------------------- +4DB PROTUN = CR0; PTGEN FPU_LOAD_3264; // 1 FLD/FILD/FADD/FMUL/FCOM/FCOMP/FSUBR/FSUB/FDIVR/FDIV mq FPU_LOAD_3264 can go to FPU_LD3264_287, FPU_LD3264_387 or #NM (always jumps) - transfer 8 bytes FPU -> bus +4DC TMPB = OPCODE; SIGMA = 2; DLY; +4DD TMPG = IRF2; IND_DELTA = 7; IND += IND_DELTA; BITS32; +4DE COUNTR = SIGMA; SHLCNT = 0x10; // COUNTR = 2 +------------------------------------------|---------------------------------------------------------------------------------------------- +4DF MISC2 = true; DLY; // 1 FLDCW mw +4E0 PROTUN = CR0; PTGEN FPU_OTHER; // 1 FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FILD mw FPU_OTHER goes to #NM or continues - transfer 2 bytes fPU -> bus +4E1 TMPB = OPCODE; SIGMA = 1; DLY; +4E2 TMPG = IRF2; IND_DELTA = 1; IND += IND_DELTA; BITS32; +4E3 COUNTR = SIGMA; SHLCNT = 0x10; // COUNTR = 1 +4E4 SIGMA = (0:TMPB) << SHLCNT; // SIGMA = OPCODE << 16 +4E5 goto FPU_LOAD_WAIT; +4E6 BITS16; +------------------------------------------|---------------------------------------------------------------------------------------------- +4E7 FPU_LD80_287: MISC1 = true; +4E8 FPU_LD3264_287: TMPC = COUNTR; +4E9 SIGMA = COUNTR + TMPC; // SIGMA = COUNTR*2 +4EA COUNTR = SIGMA; // COUNTR = COUNTR*2 +4EB SIGMA = (0:TMPB) << SHLCNT; // SIGMA = OPCODE << 16 SHLCNT is always 16 here +4EC goto FPU_LOAD_WAIT; +4ED BITS16; +------------------------------------------|---------------------------------------------------------------------------------------------- +4EE FPU_LD80_387: MISC1 = true; // This routine might be similar to FPU_LD3264_387 +4EF SIGMA = (0:TMPB) << SHLCNT; // SIGMA = OPCODE << 16 SHLCNT is always 16 here +4F0 FPU_LOAD_WAIT: TMPB = SIGMA; if (!BUSY# && !ERROR#) goto FPU_LOAD_CORE; // TMPB = OPCODE << 16 +4F1 SIGMA = CS | TMPB; // SIGMA = CS | (OPCODE << 16) +4F2 if (ERROR#) goto FPU_LD80_ERRT; +4F3 +4F4 FPU_LOAD_IRQT: if (!INTERRUPT_REQUESTED) goto FPU_LOAD_WAIT; +4F5 +4F6 goto RPTI; +4F7 +------------------------------------------|---------------------------------------------------------------------------------------------- +4F8 FPU_LOAD_ERRT: if (!PEREQ) goto #MF2; +4F9 +4FA goto FPU_LOAD_IRQT; +4FB +------------------------------------------|---------------------------------------------------------------------------------------------- +4FC FPU_LOAD_CORE: TMPB = SIGMA; CR_B; // TMPB = CS | (OPCODE << 16) +4FD DES_OS; DLY; SIGMA = TMPG + WORDSZ; IND = TMPG; +4FE TMPH = SIGMA; SIGMA = 0x800000f8; CR_B; +4FF DES_IO; DLY IND = SIGMA; if (MISC2) goto FLDCW; +500 OPR_W = IMM; SIGMA = IMM; WR_W; +501 DES_OS; SIGMA = 0x800000fc; IND = TMPG; DLY; // TMPG is the address to read from +502 CSOPCD = TMPB; --COUNTR; RD; +503 FPU_LOAD_CORWA: DES_IO; DLY; IND = SIGMA; if (!PEREQ) goto FPU_LOAD_CORWA; // Waiting for something? +504 FIO; WIO; +505 FSVeIP = TMPeIP; UNL; wr; if (COUNTR == 0) goto FPU_LOAD_DONE; // Write back read data to FPU data port +506 FPU_LOAD_LOOP: DES_OS; DLY; IND = TMPH; +507 TMPF = IMM; --COUNTR; RD; // Read from requested address given in TMPH +508 DES_IO; IND = 0x800000fc; DLY; +509 SIGMA = TMPH + WORDSZ; FIO; +50A TMPH = SIGMA; FIO; WIO; if (COUNTR != 0) goto FPU_LOAD_LOOP; +50B UNL; wr; // Write back read data to FPU data port +50C FPU_LOAD_DONE: OPROFF = TMPG; DLY; if (MISC1) goto FPU_LD80_DONE; +50D DES_OS; IND = TMPH; RNI; +50E FPU_LD80_DONE: DLY; +50F FIO; RD_W; // Read +510 TMPF = SIGMA; FIO; WIO; +511 DES_IO; DLY; IND = 0x800000fc; +512 wr_W; UNL; RNI; // Write back read data to FPU data port +513 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +514 #MF2: goto FAULT; +515 SIGMA = 0x10; // "Interrupt 16 ÄÄ Coprocessor Error" +------------------------------------------|---------------------------------------------------------------------------------------------- +516 FLDCW: DES_OS; IND = TMPG; DLY; +517 RD_W; +518 FLDCW_COR_WAIT: DLY; if (!PEREQ) goto FLDCW_COR_WAIT; // Waiting for something? +519 DES_IO; IND = 0x800000fc; FIO; WIO; +51A wr_W; UNL; RNI; +51B DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +51C FPU_LD3264_387: SIGMA = (0:TMPB) << SHLCNT; // SHLCNT is always 16 here +51D IND = 0x800000f8; DES_IO; +51E OPR_W = IMM; WR_W; // Write IMM to FPU command port +51F FPU_LD3264_WAIT: TMPB = SIGMA; if (!BUSY# && !ERROR#) goto FPU_LD3264_COR; +520 SIGMA = CS | TMPB; +521 if (ERROR#) goto FPU_LD364_ERRT; +522 +523 FPU_LD3264_IRQT: if (!INTERRUPT_REQUESTED) goto FPU_LD3264_WAIT; +524 +525 goto RPTI; +526 +------------------------------------------|---------------------------------------------------------------------------------------------- +527 FPU_LD3264_ERRT: if (!PEREQ) goto #MF2; +528 +529 goto FPU_LD3264_IRQT; +52A FPU_LD3264_COR: DES_OS; IND = TMPG; DLY; +52B TMPB = SIGMA; RD; if (COUNTR == 1) goto FPU_LD32; // Read from requested address given in TMPG +52C IND = 0x800000fc; DES_IO; DLY; +52D wr; // Write back read data to FPU data port +52E DES_OS; IND_DELTA = WORDSZ; IND = TMPG + IND_DELTA; +52F UNL; RD; // Read from requested address given in TMPG +530 IND = 0x800000fc; DES_IO; DLY; +531 FPU_LD32: TMPF = IMM; wr; // Write back read data to FPU data port +532 CSOPCD = TMPB; +533 FPU_LD32_WAIT: FSVeIP = TMPeIP; DLY; if (!PEREQ) goto FPU_LD32_WAIT; +534 OPROFF = TMPG; RNI; +535 UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +536 #NM: goto FAULT; +537 SIGMA = 7; // "Interrupt 7 ÄÄ Coprocessor Not Available" +------------------------------------------|---------------------------------------------------------------------------------------------- +538 PROTUN = CR0; PTGEN FPU_STORE_80; // 1 FBSTP/FSTP mt FPU_STORE_80 can go to FPU_ST80_287, FPU_ST80_387, or #NM (always jumps) stores 10 bytes FPU -> bus +539 TMPB = OPCODE; SIGMA = 2; DLY; +53A TMPG = IRF2; IND_DELTA = 9; IND += IND_DELTA; BITS32; +53B COUNTR = SIGMA; SHLCNT = 0x10; +------------------------------------------|---------------------------------------------------------------------------------------------- +53C PROTUN = CR0; PTGEN FPU_STORE_3264; // 1 FST/FSTP/FIST/FISTP md FPU_STORE_3264 can go to FPU_ST3264_287, FPU_ST3264_387, or #NM (always jumps) stores 4 bytes FPU -> bus +53D TMPB = OPCODE; SIGMA = 1; DLY; +53E TMPG = IRF2; IND_DELTA = 3; IND += IND_DELTA; BITS32; +53F COUNTR = SIGMA; SHLCNT = 0x10; +------------------------------------------|---------------------------------------------------------------------------------------------- +540 PROTUN = CR0; PTGEN FPU_STORE_3264; // 1 FST/FSTP/FISTP mq FPU_STORE_3264 can go to FPU_ST3264_287, FPU_ST3264_387, or #NM (always jumps) stores 8 bytes FPU -> bus +541 TMPB = OPCODE; SIGMA = 2; DLY; +542 TMPG = IRF2; IND_DELTA = 7; IND += IND_DELTA; BITS32; +543 COUNTR = SIGMA; SHLCNT = 0x10; +------------------------------------------|---------------------------------------------------------------------------------------------- +544 PROTUN = CR0; PTGEN FPU_OTHER; // 1 FIST/FISTP mw FPU_OTHER can go to #NM or continue stores 2 bytes FPU -> bus +545 TMPB = OPCODE; SIGMA = 1; DLY; +546 TMPG = IRF2; IND_DELTA = 1; IND += IND_DELTA; BITS32; +547 SHLCNT = 0x10; COUNTR = SIGMA; +548 SIGMA = (0:TMPB) << SHLCNT; // SIGMA = TMPB << 16 +549 goto o556; +54A BITS16; +------------------------------------------|---------------------------------------------------------------------------------------------- +54B #MF: goto FAULT; +54C SIGMA = 0x10; // "Interrupt 16 ÄÄ Coprocessor Error" +------------------------------------------|---------------------------------------------------------------------------------------------- +54D FPU_ST80_287: MISC1 = true; +54E FPU_ST3264_287: TMPC = COUNTR; +54F SIGMA = COUNTR + TMPC; +550 COUNTR = SIGMA; +551 SIGMA = (0:TMPB) << SHLCNT; // SHLCNT is always 16 here +552 goto FPU_STORE_WAIT; +553 BITS16; +------------------------------------------|---------------------------------------------------------------------------------------------- +554 FPU_ST80_387: MISC1 = true; +555 FPU_ST3264_387: SIGMA = (0:TMPB) << SHLCNT; // SHLCNT is always 16 here +556 FPU_STORE_WAIT: TMPB = SIGMA; if (!BUSY# && !ERROR#) goto FPU_STORE_CORE; +557 SIGMA = CS | TMPB; +558 if (JBUSY#) goto FPU_STORE_ERRT; +559 +55A FPU_STORE_IRQT: if (!INTERRUPT_REQUESTED) goto FPU_STORE_WAIT; +55B +55C goto RPTI; +55D +------------------------------------------|---------------------------------------------------------------------------------------------- +55E FPU_STORE_ERRT: if (JPEREQ) goto #MF; +55F +560 goto FPU_STORE_IRQT; +561 +------------------------------------------|---------------------------------------------------------------------------------------------- +562 FPU_STORE_CORE: TMPB = SIGMA; CW_B; +563 DES_OS; IND = TMPG; DLY; +564 CW_B; +565 IND = 0x800000f8; DES_IO; DLY; +566 OPR_W = IMM; WR_W; +567 IND = 0x800000fc; DES_IO; DLY; +568 FPU_STORE_CORW: if (!PEREQ) goto FPU_STORE_CORW; +569 +56A TMPF = IMM; FIO; WIO; if (!PEREQ) goto FPU_STORE_ABRT; // This is a bit weird - PEREQ would have to go high and then immediately low again +56B CSOPCD = TMPB; +56C TMPH = TMPG; RD; +56D DES_OS; IND = TMPH; DLY; if (COUNTR == 1) goto FPU_STORE_DONE; +56E --COUNTR; FSVeIP = TMPeIP; wr; +56F FPU_STORE_LOOP: SIGMA = TMPH + WORDSZ; UNL; +570 TMPH = SIGMA; DLY; +571 IND = 0x800000fc; DES_IO; FIO; WIO; +572 RD; +573 DES_OS; IND = TMPH; if (COUNTR != 1) goto FPU_STORE_LOOP; +574 --COUNTR; wr; +575 FPU_STORE_DONE: OPROFF = TMPG; DLY; if (MISC1) goto FPU_STORE_287; +576 IND = 0x800000fc; DES_IO; UNL; RNI; +577 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +578 FPU_STORE_287: FIO; WIO; +579 RD_W; +57A IND_DELTA = WORDSZ; IND = TMPH + IND_DELTA; DES_OS; DLY; +57B UNL; wr_W; RNI; +57C DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +57D FPU_STORE_ABRT: FSVeIP = TMPeIP; DLY; +57E OPROFF = TMPE; RNI; +57F +------------------------------------------|---------------------------------------------------------------------------------------------- +580 PTR = &DES_SR; DLY; PTSAV1 TST_DES_SIMPLE; // 0 p MOV ES/DS/FS/GS,rw TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue +581 LD_DESCRIPTOR(); // Load new ES/DS/FS/GS descriptor +582 SLCTR = DSTREG; DLY; PTSELE TST_SEL_NONSS; // TST_SEL_NONSS can go to NULL_SELECTOR (RETURNs) or continue (L) +583 SEGREG = SLCTR2; PTR->DEL = TMPC; RNI; +584 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +585 PTR = &DES_SR; PTSAV7 TST_DES_SS; DLY; // 0 p MOV SS,rw TST_DES_SS can go to PROT_TESTS_PASSED (KN) (RETURNs), #SS(I0,E0), or continue +586 LD_DESCRIPTOR(); // Load new SS descriptor +587 SLCTR = DSTREG; PTSELE TST_SEL_SS; DLY; // TST_SEL_SS can go to #GP/#TS(I0,E0) or #GP/#TS(I0,E0) (L) or continue (L) +588 SEGREG = SLCTR2; PTR->DEL = TMPC; RnI; +589 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +58A PM_LD_DSESFSGS: DLY; LD_DESCRIPTOR(); // Load new DS/ES/FS/GS descriptor +58B SLCTR = OPR_R; UNL; PTSELE TST_SEL_NONSS; // TST_SEL_NONSS can go to NULL_SELECTOR (RETURNs) or continue (L) +58C SEGREG = SLCTR2; PTR->DEL = TMPC; RNI; // descriptor selected previously? +58D DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +58E PM_LD_SS: DLY; LD_DESCRIPTOR(); // Load new SS descriptor +58F SLCTR = OPR_R; UNL; PTSELE TST_SEL_SS; // TST_SEL_SS can go to #GP/#TS(I0,E0) or #GP/#TS(I0,E0) (L) or continue (L) +590 SEGREG = SLCTR2; PTR->DEL = TMPC; RnI; // descriptor selected previously? +591 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +592 NULL_SELECTOR: SIGMA = TMPD; UNL; RD_D; // Used by TST_SEL_NONSS, TST_SEL_LES, TST_SEL_LDS, TST_SEL_LFSLGS - interrupts LD_DESCRIPTOR and LD_DES_SSFSGS - this line happens after 5cb in LD_DESCRIPTOR or 5c6 in LD_DES_SSFSGS Why do an ignored RD from GDT entry 0 here? +593 PTR->DEH = 0; DLY; RETURN; +594 TMPC = 0; UNL; PTR->DES = 0; // descriptor selected on previous line +------------------------------------------|---------------------------------------------------------------------------------------------- +595 PM_LES: PTR = &DES_ES; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue +596 LD_DESCRIPTOR(); // Load new ES descriptor +597 SLCTR = OPR_R; PTSELE TST_SEL_LES; UNL; // TST_SEL_LES can go to NULL_SELECTOR (RETURNs) or continue (L) +598 ES = SLCTR2; DES_ES.DEL = TMPC; RNI; // descriptor selected previously? Or implicit by dest? +599 SRCREG = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +59A PM_LSS: PTR = &DES_SS; DLY; PTSAV7 TST_DES_SS; // TST_DES_SS can go to PROT_TESTS_PASSED (KN) (RETURNs), #SS(I0,E0), or continue +59B LD_DES_SSFSGS(); +59C SLCTR = OPR_R; UNL; PTSELE TST_SEL_SS; // TST_SEL_SS can go to #GP/#TS(I0,E0) or #GP/#TS(I0,E0) (L) or continue (L) +59D SS = SLCTR2; DES_SS.DEL = TMPC; RNI; // descriptor selected previously? Or implicit by dest? +59E SRCREG = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +59F PM_LDS: PTR = &DES_DS; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue +5A0 LD_DESCRIPTOR(); // Load new DS descriptor +5A1 SLCTR = OPR_R; UNL; PTSELE TST_SEL_LDS; // TST_SEL_LDS can go to NULL_SELECTOR (RETURNs) or continue (L) (same conditions as TST_SEL_LES) +5A2 DS = SLCTR2; DES_DS.DEL = TMPC; RNI; // descriptor selected previously? Or implicit by dest? +5A3 SRCREG = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +5A4 PM_LFS_LGS: SIGMA |= 0x40; // FS is register 0x24 (DES_FS is register 0x64) and GS is register 0x25 (DES_GS is register 0x65) +5A5 COUNTR = SIGMA; +5A6 +5A7 PTR = &IRF[COUNTR]; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue +5A8 LD_DES_SSFSGS(); +5A9 SLCTR = OPR_R; UNL; PTSELE TST_SEL_LFSLGS; // TST_SEL_LFSLGS can go to NULL_SELECTOR (RETURNs) or continue (L) (same conditions as TST_SEL_LES and TST_SEL_LDS) +5AA IRF[COUNTR] = SLCTR2; IRF[COUNTER].DEL = TMPC; RNI; // LD_DES_SSFSGS sets COUNTR to be 0x24 or 0x25 based on IMM (i.e. IMM ^ 0x10) +5AB SRCREG = SIGMA; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +5AC JUMP_FAR_PM: PTR = &DES_CS; PTSAV7 TST_DES_JMP; // TST_DES_JMP can go to JUMP_FAR_PM_GATE, PROT_TESTS_PASSED (N) (RETURNs), #NP(I0,E0) or continue +5AD LD_DESCRIPTOR(); // Load new CS descriptor +5AE SLCTR = COUNTR; PTSELE TST_SEL_CS; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L) +5AF PROTUN = SLCTR2; PTGEN SET_RPL_TO_CPL; // (KM) we get here if we're jumping to a code segment +5B0 PTR->DEL = TMPC; // descriptor selected previously? +5B1 PAGER5.PCR; goto JMP_FAR_COMMON; // Write to special register? +5B2 SIGMA = PROTUN; // SIGMA in JMP_FAR_COMMON is CS selector value we're jumping to +------------------------------------------|---------------------------------------------------------------------------------------------- +5B3 JUMP_FAR_PM_GATE: PTGATE TST_DES_JGATE; // TST_DES_JGATE can go to CALLGATE286, CALLGATE386, TASKGATE, AVAIL_TSS_PR, AVAIL_TSS_NP, #NP(I0,E0) or continue +5B4 TMPH = SIGMA; RPT; // Does RPT exhaust the delay slots for the protection test? Or one of them? SIGMA set to DES on line 5d0 (this is the destination selector) +5B5 PTR = &DES_CS; DLY; PTSAV7 TST_DES_JGDEST; // TST_DES_JGDEST can go to PROT_TESTS_PASSED2 (N) (RETURN), #NP(I0,E0), or continue. Not testing immediately but waiting for the next PTOVRR? +5B6 goto #GP/#TS(I0,E0); +5B7 PTGEN SET_FAULT; +------------------------------------------|---------------------------------------------------------------------------------------------- +5B8 CALL_FAR_PM_GATE: COUNT5 = PROTUN; PTGATE TST_DES_CGATE; // TST_DES_CGATE can go to CALLGATE286, CALLGATE386, TASKGATE, AVAIL_TSS_PR, AVAIL_TSS_NP, #NP(I0,E0) or continue parameter count is low 5 bits of DEH +5B9 TMPH = SIGMA; INTERRUPT_HW = true; RPT; // Does RPT exhaust the delay slots for the protection test? Or one of them? (Must do or we'd always ends up in #GP/#TS(I0,E0) from here) SIGMA set to DES on line 5d0 (this is the destination selector) Not sure why we set INTERRUPT_HW here +5BA PTR = &DES_CS; DLY; PTSAV7 TST_DES_CGDEST; // TST_DES_CGDEST can go to PROT_TESTS_PASSED2 (N) (RETURN), MORE_PRIVILEGE (KLN), #NP(I0,E0), or continue. +5BB GENERAL_FAULTP: goto #GP/#TS(I0,E0); +5BC PTGEN SET_FAULT; +------------------------------------------|---------------------------------------------------------------------------------------------- +5BD CALLGATE286: MISC2 = true; +5BE CALLGATE386: SIGMA = TMPC & 0xffff; // SIGMA = DEL & 0xffff (== offset & 0xffff) TMPC set to DEL at 5d0 +5BF TMPC = SIGMA; // SIGMA = offset & 0xffff +5C0 SIGMA = TMPB & 0xffff0000; // SIGMA = DEH & 0xffff0000 (== offset & 0xffff0000) TMPB set to DEH at 5ce +5C1 SIGMA |= TMPC; // SIGMA = offset (reconstructed from gate) +5C2 TMPG = SIGMA; goto LD_DESCRIPTOR; // TMPG = offset Load new CS descriptor - Go back into LD_DESCRIPTOR which returns from where the first one was called (JUMP_FAR_PM or CALL_FAR_PM) +5C3 SLCTR = TMPH; DLY; PTSELE TST_SEL_CS; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L) TMPH set to DES at 5b4/5b9 +------------------------------------------|---------------------------------------------------------------------------------------------- +5C4 LD_DES_SSFSGS: DESSDT; IND_DELTA = 4; IND = SLCTR + IND_DELTA; +5C5 SIGMA = IMM ^ 0x10; rd_D; +5C6 COUNTR = SIGMA; IND_DELTA = -4; IND += IND_DELTA; DLY; +5C7 rd_D; goto LD_DESCRIPTOR2; // NULL DESCRIPTOR can take over here? +5C8 PROTUN = OPR_R; UNL; PTOVRR TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue +------------------------------------------|---------------------------------------------------------------------------------------------- +5C9 LD_DESCRIPTOR: DESSDT; IND_DELTA = 4; IND = SLCTR + IND_DELTA; // SLCTR is passed in as the selector of the descriptor to read +5CA rd_D; // First read = access/high = DEH +5CB DLY; IND_DELTA = -4; IND += IND_DELTA; // IND = SLCTR +5CC rd_D; // Second read = limit low / base low = DEL NULL_DESCRIPTOR can take over here? +5CD PTOVRR TST_DES_SIMPLE; PROTUN = OPR_R; // TST_DES_SIMPLE can go to #NP(I0,E0) or PROT_TESTS_PASSED (N) (RETURNs) or continue PROTUN = access/high = DEH +5CE LD_DESCRIPTOR2: TMPB = OPR_R; BITS32; // TMPB = access/high = DEH +5CF SHLCNT = 0x10; DLY; +5D0 TMPC = OPR_R; SIGMA = (OPR_R:TMPB) << SHLCNT; UNL; // SIGMA = (OPR_R:TMPB) << 16 = ((access byte) << 24) | ((base address) & 0xffffff) = DES +5D1 goto #GP/#TS(I0,E0); // we end up here if 5cd continues +5D2 PTGEN SET_FAULT; +------------------------------------------|---------------------------------------------------------------------------------------------- +5D3 PRESENT_TSS: TMPC = SIGMA; goto PROT_TESTS_CMN; +5D4 PTR->DEH = TMPB; BITSDE; +------------------------------------------|---------------------------------------------------------------------------------------------- +5D5 PROT_TESTS_PASSED: TMPC = SIGMA; IND_DELTA = 4; IND += IND_DELTA; DLY; // TMPC = DES +5D6 OPR_W = PROTUN; WR_W; // PROTUN must be to setting the accessed bit (bit 8 of DEH) - this is probably done by the N bit in the pla4 output +5D7 PTR->DEH = TMPB; BITSDE; DLY; // (sets byte 3 of base, byte 2 (G/DB/-/A bits) of access, and byte 2 (bits 16-19) of limit) Presumably setting DEH causes limit bits 16-19 to be shifted if G is set (and similarly with DEL) +5D8 PROT_TESTS_CMN: PTR->DES = TMPC; RETURN; // (sets byte 3 (P/DPL/S/Type) bits of access, and bytes 0-2 of base) descriptor selected previously +5D9 TMPC = OPR_R; SIGMA = TMPD; // restore SIGMA to TMPD TMPC = limit low / base low = DEL for later SDEL (sets bytes 0-1 of limit) +------------------------------------------|---------------------------------------------------------------------------------------------- +5DA PROT_TESTS_PASSED2: TMPC = SIGMA; IND_DELTA = 4; IND += IND_DELTA; DLY; +5DB OPR_W = PROTUN; WR_W; +5DC PTR->DEH = TMPB; DLY; if (MISC2) goto PROT_TESTS_P16; // Because of RETURN in delay slot (next line), only 5df is executed at the destination (instead of 5de) in the MISC2 case MISC2 set at CALLGATE286/INTGATE286/TRAPGATE286 +5DD PTR->DES = TMPC; RETURN; // descriptor seleted above? +5DE TMPC = OPR_R; BITS32; +------------------------------------------|---------------------------------------------------------------------------------------------- +5DF PROT_TESTS_P16: TMPC = OPR_R; BITS16; // Only executed in the delay slot of RETURN at 5dd +------------------------------------------|---------------------------------------------------------------------------------------------- +5E0 CALL_FAR_PM: PTR = &DES_CS; PTSAV7 TST_DES_CALL; DLY; // TST_DES_CALL can go CALL_FAR_PM_GATE, PROT_TESTS_PASSED (N) (RETURNs), #NP(I0,E0), or continue on entry, COUNTR = selector of destination and TMPG = offset of destination +5E1 LD_DESCRIPTOR(); // Load new CS descriptor +5E2 SLCTR = COUNTR; PTSELE TST_SEL_CS; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L) +5E3 PROTUN = SLCTR2; PTR->DEL = TMPC; // descriptor selected previously? +5E4 PAGER5.PCR; PTGEN SET_RPL_TO_CPL; // (KM) +5E5 DESSTK; SIGMA = ESP + NEGWSZ; DLY; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; +5E6 OPR_W = CS; WR; // push CS +5E7 TMPB = PROTUN; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 5e5 +5E8 OPR_W = EIP; WR; // push eIP +5E9 SIGMA += NEGWSZ; +5EA DLY; goto JMP_FAR_COMMON; +5EB eSP = SIGMA; SIGMA = TMPB; +------------------------------------------|---------------------------------------------------------------------------------------------- +5EC MORE_PRIV16: SHRCNT = (-2) & BITS_V; // shift right by 0x1e (or 0x0e?) +5ED SIGMA = (SIGMA:0) >> SHRCNT; // SIGMA <<= 2 - each stack selector/offset pair is 4 bytes in the TSS +5EE goto FOUND_STACK; +5EF DES_TR; IND_DELTA = 2; IND = SIGMA + IND_DELTA; BITS16; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +5F0 GENERAL_FAUL2P: goto #GP/#TS(I0,E0); +5F1 SLCTR2 = TMPH; PTGEN SET_FAULT; +------------------------------------------|---------------------------------------------------------------------------------------------- +5F2 PUSH_V86_SREGS: SIGMA = TMPH & 3; // This seems to be the Push(GS) code in https://www.felixcloutier.com/x86/intn:into:int3:int1 +5F3 OPR_W = GS; WR_W; +5F4 COUNTR = SIGMA; DLY; IND += IND_DELTA; // IND -= WORDSZ IND_DELTA set to NEGWSZ at 60a +5F5 OPR_W = FS; WR_W; +5F6 DLY; IND += IND_DELTA; if (COUNTR != 0) goto GENERAL_FAUL2P; // IND -= WORDSZ IND_DELTA set to NEGWSZ at 60a +5F7 OPR_W = DS: WR_W; +5F8 DLY; IND += IND_DELTA; // IND -= WORDSZ IND_DELTA set to NEGWSZ at 60a +5F9 OPR_W = ES; WR_W; goto MORE_PRIV2; +5FA DLY; IND += IND_DELTA; // IND -= WORDSZ IND_DELTA set to NEGWSZ at 60a +------------------------------------------|---------------------------------------------------------------------------------------------- +5FB MORE_PRIVILEGE: TMPE = TMPB; IND_DELTA = 4; IND += IND_DELTA; BITS32; DLY; // Also handles the INTERRUPT-TO-INNER-PRIVILEGE case? TMPB is DEH from the last LD_DESCRIPTOR (which is the one in CALL_FAR_PM loading CS) +5FC OPR_W = PROTUN; SHRCNT = 0x5d & BITS_V; WR_W; // Actually loading 0x1d (Or 0x0d?) +5FD PROTUN = SLCTR2; PTGEN WRITE_RPL; // (M) +5FE MDTMP4 = TMPC; RPT; if (BITS == 16) goto MORE_PRIV16; // exhaust one of the PTGEN's delay slots? (BITS here clearly isn't affected by BITS32 on line 5fb) +5FF TMPH = PROTUN; SIGMA = PROTUN & 3; // determine privilege level +600 SIGMA = (SIGMA:0) >> SHRCNT; // SIGMA = ((PROTUN & 3) << 3) - each stack selector/offset pair is 8 bytes in the TSS +601 DES_TR; IND_DELTA = WORDSZ; IND = SIGMA + IND_DELTA; DLY; +602 FOUND_STACK: SLCTR2 = TR; TSS_ACCESS_FLAG = true; RD; // Read eSP for privilege level +603 DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 601 +604 TMPD = OPR_R; UNL; RD_W; // Store eSP in TMPD. Read SS for privilege level +605 PTR = &DES_CS; DLY; PTSAV3 TST_DES_MOREPR; // TST_DES_MOREPR can go to #SS(I0,E0), PROT_TESTS_PASSED2 (N) (RETURNs), or continue. We're putting the new stack in CS temporarily so we still have access to the old stack and can copy params between them +606 LD_DESCRIPTOR(); // Load new CS descriptor +607 SLCTR = OPR_R; UNL; PTSELA TST_SEL_MOREPR; // TST_SEL_MOREPR can go to #GP/#TS(I0,E0) or continue +608 PTR->DEL = TMPC; TSS_ACCESS_FLAG = false; // descriptor selected previously? +609 if (VM) goto PUSH_V86_SREGS; // Can we actually get here in the VM case? Must be an interrupt? +60A DESCSW; IND_DELTA = NEGWSZ; IND = TMPD + IND_DELTA; DLY; +60B MORE_PRIV2: OPR_W = SS; WR_W; if (MISC1) goto MORE_PRIV_INT; // MISC1 is set on 8b2 in INTERRUPT_PM +60C TMPD = COUNTR; SIGMA = COUNTR + ESP; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 60a If we got here via 5f9 then COUNTR must be 0 COUNTR loaded at 5b8 +60D OPR_W = ESP; if (COUNTR == 0) goto COPY_PRMS_SKIP; WR; +60E DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 60a +60F if (MISC2) goto MORE_PRIV3; // We must be in the !VM case here +610 SIGMA += TMPD; +611 SIGMA += TMPD; +612 SIGMA += TMPD; +613 MORE_PRIV3: eSP = SIGMA; goto COPY_PARAMS; // SIGMA ends up as either ESP + 2*TMPD or ESP + 4*TMPD depending on MISC2 (MISC2 set for CALLGATE286) +614 TMPD = IRF2; IND_DELTA = 0; IND += IND_DELTA; // Not sure why we'd want IND_DELTA = 0 +------------------------------------------|---------------------------------------------------------------------------------------------- +615 MORE_PRIV_INT: OPR_W = ESP; WR; +616 SIGMA = FLAGSB & 0x37fd7; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 60a +617 OPR_W = SIGMA; WR; goto COPY_PRMS_SKIP; +618 CLT; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 60a +------------------------------------------|---------------------------------------------------------------------------------------------- +619 COPY_PARAMS: DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; DLY; +61A eSP = SIGMA; --COUNTR; RD; // Read a param +61B DESCSW; SIGMA = TMPD + 0; IND = TMPD; DLY; // Why ADD 0 here? +61C TMPD = SIGMA; wr; if (COUNTR == 0) goto COPY_PRMS_DONE; // Write back param +61D DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; DLY; +61E COPY_PRMS_LOOP: eSP = SIGMA; --COUNTR; RD; // Read a param +61F DESCSW; SIGMA = TMPD + NEGWSZ; IND_DELTA = NEGWSZ; IND = TMPD + IND_DELTA; DLY; +620 TMPD = SIGMA; UNL; wr; if (COUNT != 0) goto COPY_PRMS_LOOP; // write back param +621 DESSTK; SIGMA = ESP + NEGWSZ; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; DLY; +622 COPY_PRMS_DONE: DESCSW; UNL; IND_DELTA = NEGWSZ; IND = TMPD + IND_DELTA; +623 COPY_PRMS_SKIP: OPR_W = CS; WR_W; // Old CS onto new stack +624 IND_DELTA = NEGWSZ; IND += IND_DELTA; DLY; +625 OPR_W = ESP; COUNTR = TMPB; WR; // Old ESP onto new stack +626 eIP = TMPG; if (!ERROR_CODE_FLAG) goto NO_ERROR_CODE; DLY; +627 PROTUN = TMPE; BITS32; // TMPE set on line 5fb and is a CS AR? +628 SHRCNT = 0x10; TMPD = TMPF; // Where did TMPF get set? +629 SIGMA = (0:TMPD) >> SHRCNT; DLY; IND += IND_DELTA; // SIGMA = TMPD >> 16; IND_DELTA set to NEGWSZ at 624 This sort of looks like PUSH_ERRORCODE +62A OPR_W = SIGMA; WR_W; // Return address? +62B NO_ERROR_CODE: TMPD = MDTMP; PTGEN COPY_STACK_DPL; DLY; // (KN) +62C TMPG = IRF2; SHRCNT = 0x10; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 624 +62D DES_CS.DEH = TMPE; SIGMA = (TMPE:TMPD) >> SHRCNT; +62E TMPB = SIGMA; +62F DES_CS.DES = TMPB; // descriptor selected above +630 TMPG = TMPB; DES_CS.DEL = TMPD; // descriptor selected above +631 PAGER5.PCR; if (VM) goto ZERO_V86_SREGS; +632 SIGMA = EFLAGS & 0xffff; DLY; +633 MORE_PRIV_DONE: EFLAGS = SIGMA; // clear resume flag and virtual mode 8086 flag +634 DESCOD; IND = 0; DLY; +635 SIGMA = (COUNTR:TMPC) >> SHRCNT; PREF; // SIGMA = (COUNTR << 16) | (TMPC >> 16)? +636 TMPD = SIGMA; DLY; +637 DES_SS.DEH = COUNTR; SIGMA = TMPB; +638 SS = SLCTR2; DES_SS.DES = TMPD; // descriptor selected above? Or implied by dest? +639 CS = TMPH; DES_SS.DEL = TMPC; RNI; +63A eSP = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +63B ZERO_V86_SREGS: DS.AR = 0; +63C ES.AR = 0; +63D FS.AR = 0; goto MORE_PRIV_DONE; +63E GS.AR = 0; +------------------------------------------|---------------------------------------------------------------------------------------------- +63F IRETd_V86: DESSTK; IND = SIGMA; // STACK-RETURN-TO-V86 in PRM +640 SIGMA = 0xffff; RD_D; // Read from SS:ESP? Read new value for ESP +641 MDTMP4 = SIGMA; IND_DELTA = 4; IND += IND_DELTA; DLY; // MDTMP4 = 0xffff This can't be the same as COUNTR as that would result in DES_CS.BASE being set to 0xffff0 +642 ESP = OPR_R; SHLCNT = 0x0d; UNL; RD_D; // Read new value for SS +643 SIGMA = (0:3) << SHLCNT; DLY; IND += IND_DELTA; // SIGMA = 3 << 13 = 0x6000 IND_DELTA set to WORDSZ at 676 +644 TMPB = OPR_R; UNL; RD_D; // Read new value for ES +645 SIGMA |= 0x8200; DLY; IND += IND_DELTA; // SIGMA = 0xe200 IND_DELTA set to WORDSZ at 676 +646 TMPD = OPR_R; UNL; RD_D; // Read new value for DS +647 TMPC = SIGMA; DLY; IND += IND_DELTA; // TMPC = 0xe200 IND_DELTA set to WORDSZ at 676 +648 TMPE = OPR_R; UNL; RD_D; // Read new value for FS +649 IP = TMPG; DLY; IND += IND_DELTA; // IND_DELTA set to WORDSZ at 676 +64A SLCTR2 = OPR_R; UNL; RD_D; // Read new value for GS +64B PROTUN = -1; PTF COPY_STACK_DPL; DLY; // (KN) +64C DES_CS.AR = TMPC; +64D DES_CS.BASE = COUNTR << 4; // COUNTR is set at 67a +64E DES_CS.LIMIT = MDTMP; // MDTMP seems to be the same register as MDTMP4 +64F PAGER5.PCR; +650 DES_CS; IND = EIP; DLY; +651 SIGMA = COUNTR; PREF; // SIGMA = new CS value +652 FS = SLCTR2; FS.BASE = SLCTR2 << 4; COUNTR = 0x65; // Presumably FS.SBRM does the same thing as DES_FS.SBRM etc. Do other operations on dest activate DES_ dest|0x40 ? Register 0x65 == DES_GS +653 DS = TMPE; DS.BASE = TMPE << 4; +654 SS = TMPB; SS.BASE = TMPB << 4; +655 ES = TMPD; ES.BASE = TMPD << 4; +656 GS = OPR_R; GS.BASE = OPR_R << 4; UNL; +657 IRETd_V86_LOOP: DES_ES.AR = TMPC; // Loop to set all AR bytes to 0xe2 and all limits to MDTMP/MDTMP4 = 0xffff +658 IRF[COUNTR].AR = TMPC; if ((COUNTR & 15) != 1) goto IRETd_V86_LOOP; +659 IRF[COUNTR].LIMIT = MDTMP; --COUNTR; +65A DES_ES.LIMIT = MDTMP; RNI; +65B CS = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +65C TASK_RETURN: TMPD = SIGMA; COUNTR = 0x5d; // TASK-RETURN described in https://www.felixcloutier.com/x86/iret:iretd:iretq ? Happens when executing IRETd with NT flag set +65D SIGMA = (-1)^0x4000; // SIGMA = 0xbfff +65E TMPB = SIGMA; FLAGS_BACKED_UP = true; +65F FLAGSB = EFLAGS; SIGMA = EFLAGS & TMPB; // turn off NT (Nested Task) flag +660 EFLAGS = SIGMA; +661 SAVE_TASK(); +662 SIGMA = COUNTR - 1; +663 DES_TR; IND = 0; DLY; TASK_SAVED = false; // Is this right? Why would be clearing the TASK_SAVED flag so soon after setting it (in SAVE_TASK())? +664 TSS_ACCESS_FLAG = true; RD_W; // Read backlink from old task +665 PTR = &DES_TR; DLY; PTSAV1 TST_DES_TSSTSR; // TST_DES_TSSTSR can go to #NP(I0,E0), PRESENT_TSS or continue +666 LD_DESCRIPTOR(); // Load new TR descriptor - for backlink +667 SLCTR = OPR_R; UNL; PTSELA TST_SEL_GDT; // TST_SEL_GDT can go to #GP/#TS(I0,E0) or continue SLCTR is backlink from old task +668 TMPG = SLCTR2; PTR->DEL = TMPC; BITS32; // descriptor selected previously? TMPG is backlink from old task (i.e. new TR) +669 TMPC = TR; SHLCNT = 0x10; +66A SIGMA = TMPC << 16; // SIGMA = TR << 16 +66B TMPC = SIGMA; // TMPC = TR << 16 +66C SIGMA = TMPG & 0xffff; // SIGMA = SLCTR2 & 0xffff +66D if (BITS == 16) goto LOAD_TASK_16B; +66E DESABS; IND_DELTA = TMPC; IND = SIGMA + IND_DELTA; DLY; // IND = (SLCTR2 & 0xffff) + (TR << 16) +66F TSDB; goto LOAD_TASK_32; +670 DES_TR; IND = 0x60; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +671 LOAD_TASK_16B: TSDB; goto LOAD_TASK_16A; +672 COUNTR = 0x29; +------------------------------------------|---------------------------------------------------------------------------------------------- +673 if (NT) goto TASK_RETURN; // 3 p IRETd +674 CLRNMI; +675 SIGMA += WORDSZ; RD; // Read from SS:ESP +676 IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; // IND = ESP + WORDSZ; +677 SIGMA += WORDSZ; RD; // Read from SS:ESP+WORDSZ +678 TMPG = OPR_R; UNL; // TMPG = [SS:ESP] = eIP to return to +679 FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; DLY; IND += IND_DELTA; // IND = ESP + WORDSZ*2 IND_DELTA set to WORDSZ at 676 +67A COUNTR = OPR_R; UNL; RD; // COUNTR = [SS:ESP+WORDSZ] = CS to return to +67B DLY; +67C FLAGS = OPR_R; UNL; // FLAGS = [SS:ESP + WORDSZ*2] = eFLAGS to restore +67D DLY; +67E if (VM) goto IRETd_V86; +67F RETF_PM: PTR = &DES_CS; PTSAV3 TST_DES_RETF; // TST_DES_RETF can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs - must be from LD_DESCRIPTOR) or continue +680 eSP = SIGMA; +681 LD_DESCRIPTOR(); // Load new CS descriptor +682 SLCTR = COUNTR; PTSELE TST_SEL_RET; DLY; // TST_SEL_RET can go to #GP/#TS(I0,E0), RETF_OUTER_LEV (L), or continue (L) or continue +683 SIGMA = COUNTR; PTR->DEL = TMPC; // SAME-LEVEL case (RPL == CPL) only happens when LD_DESCRIPTOR() returns, i.e. TST_SEL_RET continues +684 PAGER5.PCR; goto JMP_FAR_DONE; +685 DESCOD; IND = TMPG; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +686 RETF_OUTER_LEV: rd_D; LD_DESCRIPTOR2(); // OUTER-PRIVILEGE-LEVEL in PRM (RPL > CPL) - LD_DESCRIPTOR() was interrupted, so go back and finish it +687 PROTUN = OPR_R; PTOVRR TST_DES_SIMPLE; UNL; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue - this is actually the TST_DES_RETF though? +688 TMPB = COUNTR; PTR->DEL = TMPC; // descriptor selected previously? +689 PAGER5.PCR; SHLCNT = 0x0d; +68A DESSTK; IND = ESP; DLY; +68B SIGMA = (0:TMPB) << SHLCNT; RD; // SIGMA = TMPB << 13; +68C TMPH = COUNTR; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +68D PROTUN = SIGMA; PTGEN COPY_STACK_DPL; RD; // (KN) +68E SIGMA = OPR_R + IMM; UNL; +68F DESCOD; DLY; IND = TMPG; +690 TMPD = SIGMA; COUNTR = 0x1f; PREF; // TMPD is eSP to restore at the end +691 PTR = &DES_SS; PTSAV3 TST_DES_RTOLSS; DLY; // TST_DES_RTOLSS can go to #SS(I0,E0), PROT_TESTS_PASSED (N) (which RETURNs) or continue +692 LD_DESCRIPTOR(); // Load new SS descriptor +693 SLCTR = OPR_R; PTSELA TST_SEL_RET_OL; UNL; // TST_SEL_RET_OL can go to #GP/#TS(I0,E0) or continue +694 SS = SLCTR2; PTR->DEL = TMPC; // descriptor selected previously? +695 IRF2 = DES_ES.AR; SIGMA = COUNTR + 1; DLY; // SIGMA = 0x20 +696 PROTUN = IRF2; PTF TST_DES_RTOLOS; // TST_DES_RTOLOS can go to ZERO_SLCTR_AR or continue - test DES_ES.AR +697 RETF_OL_ES(); +698 COUNTR = SIGMA; // COUNTR = 0x20 +699 RETF_OL_ES: IRF2 = DES_DS.AR; SIGMA = COUNTR + 3; // If the test at 696 went to ZERO_SLCTR_AR, control flow will go 699->6a8->6a9->699, zeroing IRF[0x20]=ES SIGMA = 0x23 +69A PROTUN = IRF2; PTF TST_DES_RTOLOS; // TST_DES_RTOLOS can go to ZERO_SLCTR_AR or continue - test DES_DS.AR +69B RETF_OL_DS(); +69C COUNTR = SIGMA; // COUNTR = 0x23 +69D RETF_OL_DS: IRF2 = DES_FS.AR; SIGMA = COUNTR + 1; // If the test at 69a went to ZERO_SLCTR_AR, control flow will go 69d->6a8->6a9->69d, zeroing IRF[0x23]=DS SIGMA = 0x24 +69E PROTUN = IRF2; PTF TST_DES_RTOLOS; // TST_DES_RTOLOS can go to ZERO_SLCTR_AR or continue - test DES_FS.AR +69F RETF_OL_FS(); +6A0 COUNTR = SIGMA; // COUNTR = 0x24 +6A1 RETF_OL_FS: IRF2 = DES_GS.AR; SIGMA = COUNTR + 1; // If the test at 69e went to ZERO_SLCTR_AR, control flow will go 6a1->6a8->6a9->6a1, zeroing IRF[0x24]=FS SIGMA = 0x25 +6A2 PROTUN = IRF2; PTF TST_DES_RTOLOS; // TST_DES_RTOLOS can go to ZERO_SLCTR_AR or continue - test DES_GS.AR +6A3 RETF_OL_GS(); +6A4 COUNTR = SIGMA; // COUNTR = 0x25 +6A5 RETF_OL_GS: CS = TMPH; SIGMA = TMPD; // If the test at 6a2 went to ZERO_SLCTR_AR, control flow will go 6a5->6a8->6a9->6a5, zeroing IRF[0x25]=GS +6A6 eIP = TMPG; RNI; +6A7 eSP = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +6A8 ZREO_SLCTR_AR: RETURN; // This subroutine zeroes a selector and corresponding AR in the case where the register setting is not valid for the outer level +6A9 IRF[COUNTR] = 0; IRF[COUNTR].DEH = 0; +------------------------------------------|---------------------------------------------------------------------------------------------- +6AA PROTUN = SRCREG; PTSELA READ_RPL; RD_W; // 1 p ARPL mw,rw SET_L never jumps but sets pla4 output l +6AB RPT; // exhaust one of the PTSELA's delay slots? +6AC DLY; +6AD PROTUN = OPR_R; PTSELA TST_SEL_ARPL; UNL; // TST_SEL_ARPL can go to ARPL_FAILED or continue (M) or continue +6AE RPT; // exhaust one of the PTSELA's delay slots? +6AF +6B0 OPR_W = PROTUN; SEZF; WR_R; +6B1 RNI; +6B2 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +6B3 ARPL_FAILED: CLZF; +6B4 RNI; +6B5 +------------------------------------------|---------------------------------------------------------------------------------------------- +6B6 PROTUN = SRCREG; PTSELA READ_RPL; // 0 p ARPL rw,rw SET_L never jumps but sets pla4 output l +6B7 RPT; // exhaust one of the PTSELA's delay slots? +6B8 +6B9 PROTUN = DSTREG; PTSELA TST_SEL_ARPL; // TST_SEL_ARPL can go to ARPL_FAILED or continue (M) or continue +6BA RPT; // exhaust one of the PTSELA's delay slots? +6BB +6BC DSTREG = PROTUN; SEZF; RNI; +6BD +------------------------------------------|---------------------------------------------------------------------------------------------- +6BE if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 p LTR mw +6BF +6C0 RD_W; +6C1 goto LTR_COMMON; DLY; +6C2 SLCTR = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +6C3 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 p LTR rw +6C4 SLCTR = DSTREG; +6C5 LTR_COMMON: PTR = &DES_TR; PTSAV1 TST_DES_TSSLTR; DLY; // TST_DES_TSSLTR can go to #NP(I0,E0), PRESENT_TSS, or continue +6C6 LD_DESCRIPTOR(); // Load new TR descriptor +6C7 SLCTR2; PTSELA TST_SEL_GDT; // TST_SEL_GDT can go to #GP/#TS(I0,E0) or continue Why is SLCTR2 mentioned here as source with no dest? +6C8 TR = SLCTR2; PTR->DEL = TMPC; DLY; +6C9 DESSDT; IND_DELTA = 4; IND = SLCTR + IND_DELTA; +6CA SIGMA = PROTUN | 0x8200; +6CB OPR_W = SIGMA; WR_W; RNI; +6CC DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +6CD OPR_W = TR; WR_W; RNI; // 1 p STR mw +6CE +------------------------------------------|---------------------------------------------------------------------------------------------- +6CF DSTREG = TR; RNI; // 0 p STR rw +6D0 +------------------------------------------|---------------------------------------------------------------------------------------------- +6D1 if (PM && CPL > 0) goto NO_PRIVILEGE; // 1 p LLDT mw +6D2 +6D3 RD_W; +6D4 goto LLDT_COMMON; DLY; +6D5 SLCTR = OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +6D6 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 p LLDT rw +6D7 SLCTR = DSTREG; +6D8 LLDT_COMMON: PTR = &DESLDT; PTSAV1 TST_DES_LDT; DLY; // TST_DES_LDT can go to #NP(I0,E0), PROT_TESTS_PASSED (RETURNs) or continue. +6D9 LD_DESCRIPTOR(); // Load new LDT descriptor +6DA PROTUN; PTSELA TST_SEL_LLDT; // TODO: What happens to PROTUN? Where does it come from? Presumably we're testing SLCTR here. TST_SEL_LLDT can go to LLDT_TEST_PASS or #GP/#TS(I0,E0) or continue +6DB LDTR = SLCTR2; RNI; PTR->DEL = TMPC; // is SLCTR2 the same as SLCTR? // descriptor selected previously? +6DC +------------------------------------------|---------------------------------------------------------------------------------------------- +6DD LLDT_TEST_PASS: LDT = SLCTR2; UNL; RD_D; +6DE DESLDT.DEH = 0; RNI; DLY; +6DF UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +6E0 OPR_W = LDT; RNI; WR_W; RNI; // 1 p SLDT mw +6E1 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +6E2 DSTREG = LDT; RNI; // 0 p SLDT rw +6E3 +------------------------------------------|---------------------------------------------------------------------------------------------- +6E4 LAR_LSL_VERRWM(); RD_W; // 1 p LAR rv,mv +6E5 DLY; PTR = 0; PTSAV1 TST_DES_LAR; // TST_DES_LAR can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial +6E6 SRCREG = SIGMA; // Executed after RETURN in the RNI's delay slot (RNI is in the RETURN's delay slot in LAR_VERRW_SUCCEEDED) +------------------------------------------|---------------------------------------------------------------------------------------------- +6E7 LAR_LSL_VERRWR(); // 0 p LAR rv,rv +6E8 DLY; PTR = 0; PTSAV1 TST_DES_LAR; // TST_DES_LAR can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial +6E9 SRCREG = SIGMA; +------------------------------------------|---------------------------------------------------------------------------------------------- +6EA LAR_LSL_VERRWM(); RD_W; // 1 p LSL rv,mv +6EB DLY; PTR = 0; PTSAV1 TST_DES_LSL; // TST_DES_LSL can go to LSL_HELPER or continue. PTR doesn't actually seem to be used - this may be vestigial +------------------------------------------|---------------------------------------------------------------------------------------------- +6EC LAR_LSL_VERRWR(); // 0 p LSL rv,rv +6ED DLY; PTR = 0; PTSAV1 TST_DES_LSL; // TST_DES_LSL can go to LSL_HELPER or continue. PTR doesn't actually seem to be used - this may be vestigial +------------------------------------------|---------------------------------------------------------------------------------------------- +6EE LSL_HELPER: BITS32; DLY; +6EF TMPB = SLCTR2; SHRCNT = 8; UNL; +6F0 SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 8 +6F1 PROTUN = SIGMA; PTF TST_DES_GRANUL; // TST_DES_GRANUL can go to LSL_GRANUARITY_COARSE or LSL_GRANULARITY_FINE based on pla4 input e. +6F2 SIGMA = TMPG & 0xffff; +6F3 TMPB = SIGMA; // TMPB = TMPG & 0xffff +6F4 SIGMA = SLCTR2 & 0xf0000; +------------------------------------------|---------------------------------------------------------------------------------------------- +6F5 LSL_GRANULARITY_COARSE: SIGMA |= TMPB; +6F6 SIGMA += 1; +6F7 TMPC = SIGMA; SIGMA = 0x0d; +6F8 SIGMA -= 1; // SIGMA = 0x0c +6F9 TMPD = SIGMA; // TMPD = 0x0c +6FA TMPB = 0; SHLCNT = TMPD; +6FB SIGMA = (0:TMPC) << SHLCNT; // SIGMA = TMPC << 12 +6FC SIGMA -= 1; +6FD LSL_GRANULARITY_FINE: BITSDE; +6FE SIGMA |= TMPB; RNI; +6FF SRCREG = SIGMA; SEZF; // Set zero flag happens in the case where the register is set +------------------------------------------|---------------------------------------------------------------------------------------------- +700 LAR_LSL_VERRWM(); RD_W; // 1 p VERR mw +701 PTSAV1 TST_DES_VERR; DLY; PTR = 0; // TST_DES_VERR can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial +702 +------------------------------------------|---------------------------------------------------------------------------------------------- +703 LAR_LSL_VERRWR(); // 0 p VERR rw +704 PTSAV1 TST_DES_VERR; DLY; PTR = 0; // TST_DES_VERR can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial +705 +------------------------------------------|---------------------------------------------------------------------------------------------- +706 LAR_LSL_VERRWM(); RD_W; // 1 p VERW mw +707 PTSAV1 TST_DES_VERW; DLY; PTR = 0; // TST_DES_VERW can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial +708 +------------------------------------------|---------------------------------------------------------------------------------------------- +709 LAR_LSL_VERRWR(); // 0 p VERW rw +70A PTSAV1 TST_DES_VERW; DLY; PTR = 0; // TST_DES_VERW can go to LAR_VERRW_SUCCEEDED or continue PTR doesn't actually seem to be used - this may be vestigial +70B +------------------------------------------|---------------------------------------------------------------------------------------------- +70C LAR_LSL_VERRWM: goto LAR_LSL_VERRW; DLY; +70D SLCTR = OPR_R; PTSELA TST_SEL_LLVV; UNL; // TST_SEL_LLVV can go to LAR_LSL_VERRW_NULL_SELECTOR or continue (L) +------------------------------------------|---------------------------------------------------------------------------------------------- +70E LAR_LSL_VERRWR: SLCTR = DSTREG; PTSELA TST_SEL_LLVV; DLY; // TST_SEL_LLVV can go to LAR_LSL_VERRW_NULL_SELECTOR or continue (L) +70F LAR_LSL_VERRW: DESSDT; NO_FAULT = true; IND_DELTA = 4; IND = SLCTR + IND_DELTA; +710 BITS32; RPT; // exhaust one of the PTSELA's delay slots? +711 TMPE = SLCTR2; SHRCNT = 8; rd_D; // If this read would fault, NO_FAULT handling takes over? +712 IND_DELTA = -4; IND += IND_DELTA; DLY; +713 SIGMA = (0:0xffff0000) >> SHRCNT; rd_D; // SIGMA = 0xffff0000 >> 8 = 0x00ffff00 If this read would fault, NO_FAULT handling takes over? +714 SLCTR = OPR_R; UNL; PTOVRR TST_DES_LAR; // TST_DES_LAR can go to LAR_VERRW_SUCCEEDED or continue - default, overridden by TST_DES_LSL/TST_DES_VERR/TST_DES_VERW for LSL/VERR/VERW respectively +715 TMPB = SIGMA; BITSDE; DLY; // TMPB = 0x00ffff00 +716 SIGMA = SLCTR2 & TMPB; RD_W; // SIGMA = SLCTR2 & 0x00ffff00 +717 TMPG = OPR_R; UNL; // How is this TMPG used? +718 CLZF; RNI; DLY; // We get here if the test on line 714 continues - this is the failure case +719 OPR_R; UNL; +------------------------------------------|---------------------------------------------------------------------------------------------- +71A LAR_VERRW_SUCCEEDED: DLY; RETURN; +71B OPR_R; SEZF; RNI; UNL; // RNI in RETURN delay slot? What happens to OPR_R? +------------------------------------------|---------------------------------------------------------------------------------------------- +71C TASKGATE: PTR = &DES_TR; DLY; PTSAV1 TST_DES_TSSTSG; // TST_DES_TSSTSG can go to #NP(I0,E0) or AVAIL_TSS or continue Does PTSAV1 put addr from pla4 into ret? LD_DESCRIPTOR is normally called... +71D goto LD_DESCRIPTOR; // Load new TR descriptor +71E SLCTR = SIGMA; PTSELA TST_SEL_TASKGT; DLY; // TST_SEL_TASKGT can go to #GP/#TS(I0,E0) or continue (L) +------------------------------------------|---------------------------------------------------------------------------------------------- +71F AVAIL_TSS: TMPG = SIGMA; +720 SIGMA = PROTUN | 0x8200; // Set Present and TSS Busy bits? +721 PROTUN = SIGMA; +722 goto SWITCH_TASK; +723 SIGMA = TMPG; +------------------------------------------|---------------------------------------------------------------------------------------------- +724 SAVE_TASK: SLCTR2 = TR; if (BITS == 16) goto SAVE_TASK_16; // SIGMA is 0x5c on entry to SAVE_TASK = Offset of GS in 386 Task State Segment. +725 BITS16; +726 DES_TR; TASK_SAVED = true; DLY; IND = SIGMA; +727 OPR_W = GS; BITS32; WR_W; // Write GS +728 IND_DELTA = NEGWSZ; IND += IND_DELTA; TSS_ACCESS_FLAG = true; DLY; +729 OPR_W = FS; goto SAVE_TASK_COMM; WR_W; // Write FS +72A DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 728 +------------------------------------------|---------------------------------------------------------------------------------------------- +72B SAVE_TASK_16: COUNTR = 0x29; +72C SIGMA = COUNTR - 1; // SIGMA = 0x28 = Offset of DS in 286 Task State Segment +72D DES_TR; TASK_SAVED = true; DLY; IND = SIGMA; +72E SAVE_TASK_COMM: OPR_W = DS; TSS_ACCESS_FLAG = true; WR_W; // Write DS +72F IND_DELTA = NEGWSZ; IND += IND_DELTA; DLY; +730 OPR_W = SS; WR_W; // Write SS +731 DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f +732 OPR_W = CS; COUNTR = 7; WR_W; // Write CS +733 DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f +734 OPR_W = ES; WR_W; // Write ES +735 DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f +736 OPR_W = IRF[COUNTR] --COUNTR; WR; // Write EDI COUNTR = 6 +737 SAVE_TASK_LOOP: DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f +738 if (COUNTR != 0) goto SAVE_TASK_LOOP; +739 OPR_W = IRF[COUNTR]; --COUNTR; WR; // Write ESI, EBP, ESP, EBX, EDX, ECX, EAX +73A SIGMA = EFLAGS & 0x37fd7; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f +73B OPR_W = SIGMA; WR; // Write eFLAGS +73C COUNTR = 0x5d; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f +73D OPR_W = EIP; WR; RETURN; // Write EIP +73E CLT; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 72f +------------------------------------------|---------------------------------------------------------------------------------------------- +73F CALL_SAVE_TASK: SAVE_TASK(); +740 SIGMA = COUNTR - 1; +741 DES_TR.DEH = TMPB; DLY; goto LOAD_TASK; +742 SLCTR2 = TMPG; DES_TR.DES = TMPD; // descriptor selected above? +------------------------------------------|---------------------------------------------------------------------------------------------- +743 AVAIL_TSS_PR: TMPG = SIGMA; // This is very similar to AVAIL_TSS but with an extra test +744 SIGMA = PROTUN | 0x8200; // Set Present and TSS Busy bits? +745 PROTUN = SLCTR2; PTSELA TST_SEL_TASKGT // TST_SEL_TASKGT can go to #GP/#TS(I0,E0) or continue (L) +746 RPT; // exhaust one of the PTSELA's delay slots? +747 PROTUN = SIGMA; goto SWITCH_TASK; // Odd, this jump seems to be a no-op? +748 SIGMA = TMPG; +------------------------------------------|---------------------------------------------------------------------------------------------- +749 SWITCH_TASK: TMPD = SIGMA; COUNTR = 0x5d; +74A SIGMA = SLCTR2 & 0xffff; DLY; +74B DESSDT; TSS_ACCESS_FLAG = true; IND_DELTA = 4; IND = SLCTR + IND_DELTA; +74C OPR_W = PROTUN; WR_W; if (!TASK_SAVED) goto CALL_SAVE_TASK; // Mark TSS as busy in descriptor +74D TMPG = SIGMA; // TMPG = SLCTR2 & 0xffff +74E DES_TR.DEH = TMPB; DLY; +74F SLCTR2 = TMPG; DES_TR.DES = TMPD; // descriptor selected above? +750 LOAD_TASK: BITS32; DES_TR.DEL = TMPC; // descriptor selected above? TODO: Check that we're also referring to DES_TR when we come in here via a jump to LOAD_TASK +751 TMPC = TR; SHLCNT = 0x10; +752 SIGMA = (0:TMPC) << SHLCNT; // SIGMA = TR << 16; +753 TMPC = SIGMA; // TMPC = TR << 16 +754 DESABS; DLY; IND_DELTA = TMPC; IND = TMPG + IND_DELTA +755 TSDB; if (!MISC1 && !INTERRUPT_HW) goto TR_BACKLINK_OK; +756 DES_TR; DLY; IND = 0; +757 OPR_W = TR; WR_W; // Update backlink in TSS +758 TR_BACKLINK_OK: TMPE = 0; if (BITS == 16) goto LOAD_TASK_16; +759 DES_TR; BITS32; DLY; IND = 0x60; +75A LOAD_TASK_32: SIGMA = -1; RD_W; // Read from TR:0x60 +75B TMPD = SIGMA; IND_DELTA = -4; IND += IND_DELTA; DLY; // TMPD = -1 IND = 0x5c +75C LDT = OPR_R; UNL; RD_W; // LDT = W[TR:0x60] Read from TR:0x5c +75D DLY; IND += IND_DELTA; // IND = 0x58 IND_DELTA set to -4 at 75b +75E GS = OPR_R; UNL; RD_W; // GS = W[TR:0x5c] Read from TR:0x58 +75F DLY; IND += IND_DELTA; // IND = 0x54 IND_DELTA set to -4 at 75b +760 FS = OPR_R; UNL; RD_W; // FS = W[TR:0x58] Read from TR:0x54 +761 DLY; IND += IND_DELTA; // IND = 0x50 IND_DELTA set to -4 at 75b +762 DS = OPR_R; UNL; RD_W; goto LOAD_TASK_COMM; // DS = W[TR:0x54] Read from TR:0x50 +763 DLY; IND += IND_DELTA; // IND = 0x4c IND_DELTA set to -4 at 75b +------------------------------------------|---------------------------------------------------------------------------------------------- +764 LOAD_TASK_16: COUNTR = 0x29; // 16 bit 32 bit +765 LOAD_TASK_16A: DES_TR; BITS16; IND_DELTA = 1; IND = COUNTR + IND_DELTA; DLY; // IND = 0x2a (&LDT) +766 SIGMA = 0xffff; RD_W; // Read from TR:0x2a +767 TMPD = SIGMA; DLY; IND_DELTA = -2; IND += IND_DELTA; // IND = 0x28 (&DS) TMPD = 0xffff +768 LDT = OPR_R; UNL; RD_W; // LDT = W[TR:0x2a] Read from TR:0x28 +769 DLY; IND += IND_DELTA; // IND = 0x26 (&SS) IND_DELTA set to -2 at 767 +76A DS = OPR_R; UNL; // DS = W[TR:0x28] +76B FS = 0; RD_W; // Read from TR:0x26 +76C GS = 0; DLY; IND += IND_DELTA; // IND = 0x24 (&CS) IND_DELTA set to -2 at 767 +76D LOAD_TASK_COMM: SS = OPR_R; COUNTR = 7; UNL; RD_W; // SS = W[TR:0x26] Read from TR:0x24 SS = W[TR:0x50] Read from TR:0x4c +76E SIGMA = -1 - TMPD; DLY; IND += IND_DELTA; // SIGMA = 0xffff0000 IND = 0x22 IND = 0x48 SIGMA = 0 (&ES) +76F CS = OPR_R; UNL; RD_W; // CS = W[TR:0x24] Read from TR:0x22 CS = W[TR:0x4c] Read from TR:0x48 +770 IND_DELTA = NEGWSZ; IND += IND_DELTA; TMPC = SIGMA; DLY; // IND = 0x20 TMPC = 0xffff0000 IND = 0x44 TMPC = 0 (&DI/&EDI) +771 ES = OPR_R; UNL; RD; // ES = W[TR:0x22] Read from TR:0x20 ES = W[TR:0x48] Read from TR:0x44 +772 TMPE = 0; DLY; IND += IND_DELTA; // IND = 0x1e IND = 0x40 (&SI/&ESI) +773 LOAD_TASK_LOOP; SIGMA = OPR_R | TMPC; UNL; RD; // SIGMA = OPR_R | 0xffff0000 Read from TR:0x1e..TR:0x10 Read from TR:0x40..TR:0x24 SIGMA = OPR_R +774 IRF[COUNTR] = SIGMA; if (COUNTR != 0) goto LOAD_TASK_LOOP; DLY; IND += IND_DELTA; // Store to registers 7..0 +775 --COUNTR; +776 PTF READ_RPL; PROTUN = CS; +777 SIGMA = OPR_R & TMPD; UNL; RD; // SIGMA = W[TR:0x10] & 0xffff Read from TR:0x0e Read from TR:0x20 SIGMA = [TR:0x24] +778 EFLAGS = SIGMA; COUNTR = 0; DLY; IND += IND_DELTA; // EFLAGS = W[TR:0x10] & 0xffff IND = 0x0c IND = 0x1c EFLAGS = [TR:0x24] (&SS2/&CR3) COUNTR = 0 here so we don't set CR3 in the 16-bit case +779 eIP = OPR_R; if (BITS == 16) goto LOAD_TASK_NOPG; UNL; // eIP = W[TR:0x0e] Skip paging stuff in 16-bit mode EIP = [TR:0x20] +77A SIGMA = SIGN CR0; // if paging enabled then SIGMA = 0xffffffff else SIGMA = 0 ? +77B TMPB = SIGMA; RD_D; // TMPB = PG ? 0xffffffff : 0 Read from TR:0x1c +77C DLY; +77D IRF2 = PDBR.PCR; +77E TMPD = IRF2; DLY; // TMPD = PDBR.PCR = oldCR3 +77F TMPC = OPR_R; SIGMA = OPR_R - TMPD; UNL; // SIGMA = newCR3 - oldCR3 TMPC = newCR3 +780 DES_TR; IND_DELTA = 0x65; IND = -1 + IND_DELTA; DLY; // IND = 0x64 +781 SIGMA &= TMPB; RD_W; // SIGMA = (newCR3 - oldCR3) & (PG ? 0xffffffff : 0) Read from W[TR:0x64] = debug trap bit and IO MAP BASE in 32-bit TSS +782 COUNTR = SIGMA; DLY; // COUNTR = (newCR3 - oldCR3) & (PG ? 0xffffffff : 0) +783 SIGMA = OPR_R & 1; UNL; // SIGMA = W[TR:0x64] & 1 == debug trap bit +784 TMPE = SIGMA; // TMPE = debug trap bit +785 LOAD_TASK_NOPG: TMPeSP = ESP; // Back to both 16-bit and 32-bit +786 TMPeIP = EIP; FLAGS_BACKED_UP = true; +787 if (!MISC1 && !INTERRUPT_HW) goto NOT_NESTED_TSK; SLCTR2 = TR; +788 FLAGSB = EFLAGS; SIGMA = EFLAGS | 0x4000; // Set Nested Task flag +789 FLAGSB = SIGMA; +78A EFLAGS = SIGMA; goto SET_TSKSWTCHED; +78B TR = TMPG; TASK_SAVED = false; +------------------------------------------|---------------------------------------------------------------------------------------------- +78C NOT_NESTED_TSK: SLCTR2; DLY; // TODO: What are we doing with SLCTR2 here? +78D DESSDT; IND_DELTA = 4; IND = SLCTR + IND_DELTA; +78E TR = TMPG; rd_W; // Read W[DT:SLCTR+4] +78F DLY; +790 SIGMA = OPR_R & ~0x200; UNL; // SIGMA = W[DT:SLCTR+4] & 0xfffffdff Clear bit 9 => mark TSS as available +791 OPR_W = SIGMA; TASK_SAVED = false; WR_W; // Write back modified descriptor +792 SET_TSKSWTCHED: DESABS; if (COUNTR == 0) goto WRITE_BACK_CR0; DLY; IND = TMPC; // COUNTR (set at 782) is 0 if paging is disabled or if the new CR3 is the same as the old CR3. In these cases we can skip flushing the TLB +793 SIGMA = CR0 | 8; // Set "Task Switched" bit +794 PDBR.PCR = IND; // Load new CR3 value, flushing the TLB +795 WRITE_BACK_CR0: CR0 = SIGMA; COUNTR = 0x65; +796 TMPC = CS; goto TASK_FINAL_PM; +797 if (VM) goto TASK_FINAL_V86; // !VM case: execution continues at 7ab == TASK_FINAL_PM from jump at 796. VM case: one line at 7ab == TASK_FINAL_PM executed and then continues at 798 == TASK_FINAL_V86 +------------------------------------------|---------------------------------------------------------------------------------------------- +798 TASK_FINAL_V86: PROTUN = -1; PTF COPY_STACK_DPL; // (KN) +799 DES_FS.BASE = FS << 4; +79A DES_DS.BASE = DS << 4; +79B DES_SS.BASE = SS << 4; +79C DES_CS.BASE = CS << 4; +79D DES_GS.BASE = GS << 4; SIGMA = 0xffff; +79E TMPG = SIGMA; SHLCNT = 0x0d; DLY; // TMPG = 0xffff +79F SIGMA = (0:3) << SHLCNT; // SIGMA = 3 << 13 = 0x6000 +7A0 SIGMA |= 0x8200; // SIGMA = 0xe200 +7A1 TASK_FV86_LOOP: DES_ES.BASE = ES << 4; +7A2 IRF[COUNTR].AR = SIGMA; if ((COUNTR & 15) != 1) goto TASK_FV86_LOOP; // COUNTR = 0x65 => DES_GS Set all AR bytes to 0xe2 == present, ring 3, LDT +7A3 IRF[COUNTR].LIMIT = TMPG; --COUNTR; // Set all limits to 0xffff +7A4 DES_ES.AR = SIGMA; +7A5 DES_ES.LIMIT = TMPG; +7A6 PTR = &DESLDT; DLY; PTSAV1 TST_DES_LDT // TST_DES_LDT can go to #NP(I0,E0), PROT_TESTS_PASSED (RETURNs) or continue. +7A7 LD_DESCRIPTOR(); // Load new LDT descriptor +7A8 SLCTR = LDTR; PTSELA TST_SEL_TR_TSF; DLY; // TST_SEL_TR_TSF can go to NULL_SELECTOR2 (RETURNs), #GP/#TS(I0,E0), or continue. +7A9 goto HANDLE_TS_BP; +7AA COUNTR = TMPE; PTR->DEL = TMPC; // descriptor selected previously? +------------------------------------------|---------------------------------------------------------------------------------------------- +7AB TASK_FINAL_PM: SHLCNT = 0x0d; DLY; +7AC DESLDT.AR = 0; SIGMA = (0:TMPC) << SHLCNT; // SIGMA = TMPC << 13 +7AD PROTUN = SIGMA; PTF COPY_STACK_DPL; // (KN) +7AE DES_GS.AR = 0; +7AF DES_FS.AR = 0; +7B0 DES_DS.AR = 0; +7B1 DES_SS.AR = 0; +7B2 DES_ES.AR = 0; +7B3 PTR = &DESLDT; PTSAV1 TST_DES_LDTTSK; DLY; // TST_DES_LDTTSK can go to #GP/#TS(I0,E0), PROT_TESTS_PASSED (RETURN) or continue. +7B4 LD_DESCRIPTOR(); // Load new LDT descriptor +7B5 SLCTR = LDT; PTSELA TST_SEL_TR_TSF; DLY; // TST_SEL_TR_TSF can go to NULL_SELECTOR2 (RETURNs), #GP/#TS(I0,E0), or continue. +7B6 PTR->DEL = TMPC; // descriptor selected previously? +7B7 PTR = &DES_SS; DLY; PTSAV7 TST_DES_SS; // TST_DES_SS can jump to #SS(I0,E0) or PROT_TESTS_PASSED (KN) (RETURNs) or continue. +7B8 LD_DESCRIPTOR(); // Load new SS descriptor +7B9 SLCTR = SS; DLY; PTSELA TST_SEL_MOREPR; // TST_SEL_MOREPR can go to #GP/#TS(I0,E0) or continue. +7BA PTR->DEL = TMPC; // descriptor selected previously? +7BB PTR = &DES_CS; DLY; PTSAV7 TST_DES_JGDEST; // TST_DES_JGDEST can go to #NP(I0,E0), PROT_TESTS_PASSED2 (N) (RETURN) or continue +7BC LD_DESCRIPTOR(); // Load new CS descriptor +7BD SLCTR = CS; DLY; PTSELE TST_SEL_CS; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L) +7BE PTR->DEL = TMPC; // descriptor selected previously? +7BF PAGER5.PCR; +7C0 PTR = &DES_DS; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue +7C1 LD_DESCRIPTOR(); // Load new DS descriptor +7C2 SLCTR = DS; DLY; PTSELA TST_SEL_TASKFI; // TST_SEL_TASKFI can go to NULL_SELECTOR2 (RETURNs) or continue (L) +7C3 PTR->DEL = TMPC; // descriptor selected previously? +7C4 PTR = &DES_ES; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue +7C5 LD_DESCRIPTOR(); // Load new ES descriptor +7C6 SLCTR = ES; DLY; PTSELA TST_SEL_TASKFI; // TST_SEL_TASKFI can go to NULL_SELECTOR2 (RETURNs) or continue (L) +7C7 PTR->DEL = TMPC; // descriptor selected previously? +7C8 PTR = &DES_FS; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue +7C9 LD_DESCRIPTOR(); // Load new FS descriptor +7CA SLCTR = FS; DLY; PTSELA TST_SEL_TASKFI; // TST_SEL_TASKFI can go to NULL_SELECTOR2 (RETURNs) or continue (L) +7CB PTR->DEL = TMPC; // descriptor selected previously? +7CC PTR = &DES_GS; DLY; PTSAV1 TST_DES_SIMPLE; // TST_DES_SIMPLE can go to #NP(I0,E0), PROT_TESTS_PASSED (N) (RETURNs) or continue +7CD LD_DESCRIPTOR(); // Load new GS descriptor +7CE SLCTR = GS; DLY; PTSELA TST_SEL_TASKFI; // TST_SEL_TASKFI can go to NULL_SELECTOR2 (RETURNs) or continue (L) +7CF PTR->DEL = TMPC; COUNTR = TMPE; BITS32; // TMPE set to debug trap bit on line 784 +7D0 HANDLE_TS_BP: if (!ERROR_CODE_FLAG) goto TSKF_NO_ERRCOD; DESCOD; DLY; IND = EIP; // Last phase of task switching - handle breakpoints +7D1 TMPB = TMPF; PREF; +7D2 if (BITS == 16) goto ADJ_STACK_16; +7D3 DESSTK; SIGMA = ESP - 4; DLY; IND_DELTA = -4; IND = ESP + IND_DELTA; +7D4 ADJ_STACK_DONE: SHRCNT = 0x10; eSP = SIGMA; +7D5 SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 16; +7D6 OPR_W = SIGMA; WR_W; // Push error code? +7D7 TSKF_NO_ERRCOD: TMPB = DR7; SIGMA = 0x65; DLY; +7D8 SIGMA -= 0x10; // SIGMA = 0x55; +7D9 SIGMA ^= -1; // SIGMA = 0xffffffaa; +7DA TMPC = SIGMA; SHLCNT = 2; +7DB SIGMA = (0:TMPC) << SHLCNT; // SIGMA = 0xffffffaa << 2 = 0xfffffea8; +7DC SIGMA |= 2; // SIGMA = 0xfffffeaa; +7DD SIGMA &= TMPB; // SIGMA = 0xfffffeaa & DR7; Bit pattern 1111 1111 1111 1111 1111 1110 1010 1010 +7DE DR7 = SIGMA; // Disable all local breakpoints and Local Exact Breakpoint Enable +7DF if ((COUNTR & 15) != 1) goto NO_DEBUG_BP; TMPeIP = EIP; // if debug trap bit is 0 then we're done +7E0 SIGMA = DR6 | 0x8200; RNi; // RNi means RNI only if it's executed in the delay slot, and 7eb is a convenient empty uop +7E1 goto BREAKPOINT; +7E2 DR6 = SIGMA; // Set DR6 bits 15 BT "Task Switch Breakpoint" and 9 (reserved) +------------------------------------------|---------------------------------------------------------------------------------------------- +7E3 ADJ_STACK_16: goto ADJ_STACK_DONE; +7E4 DESSTK; SIGMA = ESP - 2; IND_DELTA = -2; IND = ESP + IND_DELTA; +------------------------------------------|---------------------------------------------------------------------------------------------- +7E5 NULL_SELECTOR2: IND_DELTA = 4; IND += IND_DELTA; DLY; // Occurs after 5cb in LD_DESCRIPTOR. IND = SLCTR + 4 i.e. IND set to high dword of descriptor (containing access byte) +7E6 UNL; wr_W; RETURN; // Write back access byte (but what has changed?) +7E7 PTR->DEH = 0; DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +7E8 AVAIL_TSS_NP: PROTUN = SLCTR2; PTSELA TST_SEL_TASKGT // TST_SEL_TASKGT can go to #GP/#TS(I0,E0) or continue (L) +7E9 +7EA goto #NP(I0,E0); +7EB NO_DEBUG_BP: +------------------------------------------|---------------------------------------------------------------------------------------------- +7EC CLI_STI: DESCOD; IND = EIP; +7ED PREF; +7EE DLY; +7EF FLGOPS; // 0 CLC/STC/CLD/STD/CMC +7F0 RNI; +7F1 +------------------------------------------|---------------------------------------------------------------------------------------------- +7F2 eSP = SIGMA; // 2 p PUSHFd +7F3 SIGMA = EFLAGS & 0xffff; // PUSHFD in protected mode stores the RF and VM flags as 0? +7F4 SIGMA &= 0x37fd7; // SIGMA = EFLAGS & 0x7fd7; +7F5 OPR_W = SIGMA; WR; RNI; +7F6 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +7F7 if (CPL <= IOPL) goto CLI_STI; // 0 CLI/STI +7F8 BITS32; +------------------------------------------|---------------------------------------------------------------------------------------------- +7F9 if (CPL <= IOPL) goto "p PUSHFd"; // 2 r PUSHFd +7FA +------------------------------------------|---------------------------------------------------------------------------------------------- +7FB if (CPL <= IOPL) goto "p POPFd"; // 3 r POPFd +7FC +------------------------------------------|---------------------------------------------------------------------------------------------- +7FD if (CPL <= IOPL) goto "p INT ib"; // 0 r INT ib +7FE +------------------------------------------|---------------------------------------------------------------------------------------------- +7FF if (CPL <= IOPL) goto IRET_REAL_MODE; // 3 r IRETd +800 // PLAJMP destinations for v86 mode, IRET_REAL_MODE for actual real mode? "CPL is always three in V86 mode; therefore, if IOPL < 3, these instructions will trigger a general-protection exceptions." +------------------------------------------|---------------------------------------------------------------------------------------------- +801 OVERLONG_INST: goto #GP/#TS(I0,E0); +802 SLCTR2 = 0; PTGEN SET_FAULT; +------------------------------------------|---------------------------------------------------------------------------------------------- +803 eSP = SIGMA; RD; // 3 p POPFd SIGMA initially set to eSP+WORDSZ +804 BITS16; DLY; // Setting BITS16 (after the RD) because POPFD does not modify the resume and V86 flags? (https://www.felixcloutier.com/x86/popf:popfd:popfq suggests RF is cleared) +805 SIGMA = OPR_R; UNL; // TODO: What is UNL? +806 FLAGS = SIGMA; RNI; // Don't really need to BITS16 since we're writing to FLAGS instead of EFLAGS? +807 +------------------------------------------|---------------------------------------------------------------------------------------------- +808 goto INTERRUPT; // 0 p INT ib +809 SIGMA = IMM; +------------------------------------------|---------------------------------------------------------------------------------------------- +80A IRET_REAL_MODE: SIGMA += WORDSZ; RD; // Non-v86 real mode First read is offset? segment? +80B FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; DLY; IND_DELTA = WORDSZ; IND += IND_DELTA; +80C SIGMA += WORDSZ; RD; // Second read is segment? offset? +80D TMPG = OPR_R; CLRNMI; UNL; // TMPG = value from first read +80E eSP = SIGMA; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; +80F COUNTR = OPR_R; SIGMA = 0xffff; UNL; RD; // COUNTR = value from second read Third read is flags +810 SIGMA += 0xffff; // SIGMA = 0x1fffe +811 SIGMA |= 0xffff; DLY; // SIGMA = 0x1ffff +812 TMPB = SIGMA; // TMPB = 0x1ffff +813 SIGMA = OPR_R & TMPB; UNL; // SIGMA = OPR_R & 0x1ffff Clear VM flag (don't allow real mode IRET to enable V86 mode) +814 DLY; goto JMP_FAR_RM; +815 FLAGS = SIGMA; // FLAGS = OPR_R & 0x1ffff +------------------------------------------|---------------------------------------------------------------------------------------------- +816 goto INTERRUPT; // 0 INT 3 +817 SIGMA = 3; // "Interrupt 3 ÄÄ Breakpoint" +------------------------------------------|---------------------------------------------------------------------------------------------- +818 SIGMA = 7; RD; // 1 BOUND rv,m2v read lower bound +819 TMPB = SIGMA; IND_DELTA = WORDSZ; IND += IND_DELTA; DLY; // TMPB = 7 +81A SIGMA = OPR_R - SRCREG; UNL; RD; // read upper bound +81B DLY; +81C TMPC = OPR_R; UNL; if (JG) goto #BR; // if (OPR_R > SRCREG) goto BOUD_RANGE_EX; +81D SIGMA = SRCREG - TMPC; +81E // Why is this blank? Need a cycle to update flags between SUB and JL? +81F if (JG) goto #BR; +820 RNI; +821 +------------------------------------------|---------------------------------------------------------------------------------------------- +822 #BR: goto FAULT; +823 SIGMA = TMPB + -2; // SIGMA = 5 "Interrupt 5 ÄÄ Bounds Check" +------------------------------------------|---------------------------------------------------------------------------------------------- +824 DIVIDE_ERROR: CONTRIBUTORY_FAULT = true; +825 goto FAULT; +826 SIGMA = 0; // "Interrupt 0 ÄÄ Divide Error" +------------------------------------------|---------------------------------------------------------------------------------------------- +827 if (OVERFLOW_FLAG == 0) goto NO_OVERFLOW; // 0 INTO +828 SIGMA = 4; RNi; // RNi means "RNI but only if it's executed in the delay slot" +829 goto INTERRUPT; +82A NO_OVERFLOW: // If O then no jump so RNi does nothing and we go to INTERRUPT and this is the delay slot. If NO then jump here but RNi executed in the delay slot and this is the empty delay slot for the RNi. +------------------------------------------|---------------------------------------------------------------------------------------------- +82B #UD: goto FAULT; +82C SIGMA = 6; +------------------------------------------|---------------------------------------------------------------------------------------------- +82D HARDWARE_IRQ: TMPeSP = ESP; ICESIG; // TODO: Saved ESP? +82E DESABS; BITS32; DLY; IND = 4; // HRM 3.1.7 "The address driven during the first cycle is 4;" +82F TMPeIP = EIP; SHRCNT = 8; IACK; // "BE3#, BE2#, and BE1# are high, BE0# is low" +830 DESABS; CINTLA; DLY; IND = 0; // HRM 3.1.7 "during the second cycle, the address is 0." +831 SIGMA = (0:0xffff) >> SHRCNT; UNL; // SIGMA = 0xffff >> 8 = 0xff +832 RPT; // not sure what this is for - no slow operation to wait for +833 TMPB = SIGMA; IACK; // TMPB = 0xff +834 DLY; goto INTERRUPT_X; +835 SIGMA = OPR_R & TMPB; UNL; // Mask off low 8 bits of PIC response as interrupt vector number +------------------------------------------|---------------------------------------------------------------------------------------------- +836 NMI: TMPeSP = ESP; SETNMI; // SETNMI sets "NMI processing" flag to avoid further NMI interrupts until we're done with this one? Gets reset by something in IRET +837 goto INTERRUPT_X; +838 TMPeIP = EIP; SIGMA = 2; // "Interrupt 2 ÄÄ NMI" +------------------------------------------|---------------------------------------------------------------------------------------------- +839 TRIPLE_FAULT: ICESIG; +83A TRIPLE_FT_WAIT: if (JICEWT) goto TRIPLE_FT_WAIT; +83B +83C CONTRIBUTORY_FAULT = true; OPR_R; +83D goto HLT_SHUTDOWN; +83E DESABS; DLY; IND = 0; // "For a shutdown condition, BE0# is active" (HRM 3.1.8) +------------------------------------------|---------------------------------------------------------------------------------------------- +83F #DF: SIGMA = TMPF & 0xffff; DLY; // TODO: Why DLY? +840 TMPF = SIGMA; ERROR_CODE_FLAG = true; +841 SIGMA = 8; +842 goto FAULT; +843 CONTRIBUTORY_FAULT = true; // "Interrupt 8 ÄÄ Double Fault" +------------------------------------------|---------------------------------------------------------------------------------------------- +844 NO_PRIVILEGE: CONTRIBUTORY_FAULT = true; +845 ERROR_CODE_FLAG = true; +846 SIGMA = TMPF & 0xffff; +847 goto FAULT; +848 TMPF = SIGMA; SIGMA = 0x0d; // "Interrupt 0x0d ÄÄ General Protection Exception" +------------------------------------------|---------------------------------------------------------------------------------------------- +849 unused?: PTGEN SET_FAULT; // Is there actually any way to get here or is it an instruction removed from the decoder? +84A SIGMA = TMPF & 0xffff; // Assuming this was a removed instruction, it unconditionally causes a page fault exception with the error code set to the last error code from the paging unit and CR2 set to some mysterious value from the paging unit instead of the fault linear address. What could this mysterious value be? +84B BITS32; // TODO: What is BITS32? +84C // TODO: Why is this line blank? +84D SHLCNT = 0x10; TMPB = SIGMA; // TMPB = TMPF & 0xffff +84E SIGMA = (0:7) << SHLCNT; // SIGMA = 7 << 16 = 0x70000 +84F TMPC = SIGMA; DLY; // TMPC = 0x70000 +850 IRF2 = PFERRC.PCR; ERROR_CODE_FLAG = true; +851 SIGMA = IRF2 & TMPC; DLY; // SIGMA = IND & 0x70000 +852 IRF2 = PGUNUS.PCR; SIGMA |= TMPB; // SIGMA = (IND & 0x70000) | (TMPF & 0xffff) - another LATTTF? +853 CR2 = IRF2; CONTRIBUTORY_FAULT = true; DLY; // "CR2 is used for handling page faults when PG is set. The processor stores in CR2 the linear address that triggers the fault." +854 TMPF = SIGMA; SIGMA = 0x0d; // TMPF = (IND & 0x70000) | (TMPF & 0xffff) +855 goto FAULT; +856 SIGMA += 1; // SIGMA = 0xe means "Interrupt 0x0e ÄÄ Page Fault" +------------------------------------------|---------------------------------------------------------------------------------------------- +857 ACCESS_VIOLATI: IRF2 = DESERR.AR; // We get here from the small PLA, so probably in response to some non-microcode signal. Limit, RO, EO, null selector, privilege? +858 IRF2 = PROTUN.AR; PTGEN TST_ACCESS_VIO; // TST_ACCESS_VIO can go to #GP(0), #GP/#TS(SIGMA), #SS(0), #SS(SIGMA), #GP(SIGMA | 2) or continue The value we're testing seems to be a descriptor index. The incantation to test it is strange, though - I have no idea how it works +859 SIGMA = SLCTR2 & -4; RPT; // exhaust (one of) the PTGEN's delay slots? EXT = 0, I = 0 +85A CONTRIBUTORY_FAULT = true; +85B #GP(0): goto FAULT_ERR_CODE; +85C TMPE = 0; SIGMA = 4; // SIGMA = 4 means "Interrupt 0x0d ÄÄ General Protection Exception" +------------------------------------------|---------------------------------------------------------------------------------------------- +85D #GP/#TS(I0,E0): SIGMA = SLCTR2 & -4; // EXT = 0, I = 0 +85E #GP/#TS(SIGMA): if (TSS_ACCESS_FLAG) goto #TS(SIGMA); +85F +860 #GP(SIGMA): goto FAULT_ERR_CODE; +861 TMPE = SIGMA; SIGMA = 4; // SIGMA = 4 means "Interrupt 0x0d ÄÄ General Protection Exception" +------------------------------------------|---------------------------------------------------------------------------------------------- +862 #SS(0): SIGMA = 0; +863 #SS(SIGMA): goto FAULT_ERR_CODE; +864 TMPE = SIGMA; SIGMA = 3; // SIGMA = 3 means "Interrupt 0x0c ÄÄ Stack Exception" +------------------------------------------|---------------------------------------------------------------------------------------------- +865 #GP(I1,E0): SIGMA = SLCTR2 & -4; // See 871 EXT = 0 #GP(I1,E0) == #GP((SLCTR2 & -4) | 2) +866 #GP(SIGMA | 2): goto #GP(SIGMA); +867 SIGMA |= 2; // I = 1 => the index portion of the error code refers to a gate descriptor in the IDT +------------------------------------------|---------------------------------------------------------------------------------------------- +868 #TS(SIGMA): goto FAULT_ERR_CODE; +869 TMPE = SIGMA; SIGMA = 1; // SIGMA = 1 means "Interrupt 0x0a ÄÄ Invalid TSS" +------------------------------------------|---------------------------------------------------------------------------------------------- +86A #SS(I0,E0): SIGMA = SLCTR2 & -4; // See 871 mask off RPL bits EXT = 0, I = 0 #SS(I0,E0) == #SS(SLCTR2 & -4) +86B DLY; goto FAULT_ERR_CODE; +86C TMPE = SIGMA; SIGMA = 3; // TMPE = SLCTR2 & -4; SIGMA = 3 means "Interrupt 0x0c ÄÄ Stack Exception" +------------------------------------------|---------------------------------------------------------------------------------------------- +86D FAULT_SUPPRESS: if (JICEWT) goto FAULT_SUPPRESS; // RNI is in the delay slot - does that break the loop? (No, RNI is suppressed if it's in the delay slot) +86E LAR_LSL_VERRW_NULL_SELECTOR: CLZF; RNI; +86F OPR_R; // Ack bus +------------------------------------------|---------------------------------------------------------------------------------------------- +870 #NP(I0,E0): goto NP_COMMON; // #NP(I0,E0) == #NP(SLCTR2 & -4) EXT = 0, I = 0 +871 #NP(I1,E0): SIGMA = SLCTR2 & -4; // #NP(I1,E0) == #NP((SLCTR2 & -4)|2) EXT = 0, I = 1 +872 SIGMA |= 2; // SIGMA = (SLCTR2 & -4) | 2 +873 NP_COMMON: TMPE = SIGMA; SIGMA = 2; // SIGMA = 2 means "Interrupt 0x0b ÄÄ Segment Not Present" +874 FAULT_ERR_CODE: if (NO_FAULT) goto FAULT_SUPPRESS; // TMPE on entry here is fault error code +875 SIGMA += 9; +876 CONTRIBUTORY_FAULT = true; +877 TMPC = SIGMA; BITS32; // TODO: What is BITS32? Store interrupt number to TMPC +878 if (EVENT_EXTERNAL_TO_PROGRAM) goto EXT_BIT_DONE; // "The processor sets the EXT bit if an event external to the program caused the exception." - where does this information come from? happens when we come through smallpla? +879 SIGMA = TMPE | 1; +87A SIGMA = TMPE & 0xfffffffe; // EXT bit cleared - event was internal to the program +87B EXT_BIT_DONE: TMPB = SIGMA; SHLCNT = 0x10; // TMPB = (TMPE & 0xfffffffe) | EXT +87C SIGMA = (0:TMPB) << SHLCNT; // SIGMA = TMPB << 16 +87D TMPB = SIGMA; ERROR_CODE_FLAG = true; // TMPB = TMPB << 16 = ((TMPE & 0xfffffffe) | EXT) << 16 +87E SIGMA = TMPF & 0xffff; // SIGMA = TMPF & 0xffff +87F SIGMA |= TMPB; // SIGMA = (TMPF & 0xffff) | (((TMPE & 0xfffffffe) | EXT) << 16) +880 TMPF = SIGMA; goto FAULT; // TMPF = (TMPF & 0xffff) | (((TMPE & 0xfffffffe) | EXT) << 16) +881 SIGMA = TMPC; // Restore interrupt number from TMPC +------------------------------------------|---------------------------------------------------------------------------------------------- +882 STRING_CORRECT: SIGMA = COUNTR + 1; // Seems like this corrects ECX/EDI/ESI for interrupted string operations (but not IRQ/NMI/debug?) so they can be resumed +883 TMPB = SIGMA; SIGMA = WORDSZ; // TMPB = COUNTR + 1 +884 COUNTR = SIGMA; SIGMA = SIGMA - INCREM; // COUNTR = WORDSZ; SIGMA = WORDSZ - INCREM This SIGMA isn't used directly - setting flags for JG to test? +885 TMPC = eCX; CREPF; +886 if (JG) goto STRCORR_DOWN; eCX = TMPB; // eCX = COUNTR + 1 +887 SIGMA = TMPB - TMPC; // SIGMA = (COUNTR + 1) - old_eCX < 0 +888 SIGMA = TMPC - TMPB; // SIGMA = old_eCX - (COUNTR + 1) > 0 +889 STRCORR_DOWN: TMPC = SIGMA; SIGMA += ESI; +88A STRCORR_LOOP: eSI = SIGMA; --COUNTR; +88B SIGMA = TMPC + EDI; +88C eDI = SIGMA; if (COUNTR != 0) goto STRCORR_LOOP; // loop executes WORDSZ times (1, 2, or 4) +88D SIGMA = TMPC + ESI; +88E goto INTERRUPT_X; +88F SIGMA = TMPD; +------------------------------------------|---------------------------------------------------------------------------------------------- +890 FAULT: IRF2 = DES_SS.AR; DLY; if (!FLAGS_BACKED_UP) goto FLAGS_OK; +891 PTGEN COPY_STACK_DPL; PROTUN = IRF2; // (KN) PROTUN = DES_SS.AR +892 EFLAGS = FLAGSB; // Restore flags from backup +893 FLAGS_OK: TMPD = SIGMA; if (TSS_ACCESS_FLAG) goto RESUME_FLAG_OK; +894 EIP = TMPeIP; ICESIG; +895 SIGMA = 0xffff; +896 SIGMA += 1; // SIGMA = 0x10000 +897 TMPB = SIGMA; // TMPB = 0x10000 +898 SIGMA = EFLAGS | TMPB; // SIGMA = EFLAGS | 0x10000 +899 EFLAGS = SIGMA; SIGMA = TMPD; // EFLAGS |= 0x10000 - set Resume Flag +89A RESUME_FLAG_OK: ESP = TMPeSP; if (JICEWT) goto RESUME_FLAG_OK; +89B OPR_R; TSS_ACCESS_FLAG = false; // Does OPR_R on its own just ack any pending read in the bus logic? +89C if (REPF) goto STRING_CORRECT; // Is REPF only set for REP MOVS and not for the other REP string instructions? Former if it's only set by SREPF +89D TMPD = SIGMA; BITSDE; // SIGMA saved in TMPD so that it is restored by STRING_CORRECT +89E INTERRUPT_X: INTERRUPT_HW = true; +89F INTERRUPT: ICESIG // TODO: What is ICESIG? Software interrupts arrive here, skipping the INTERRUPT_HW set +8A0 if (PM) goto INTERRUPT_PM; +8A1 BITS32; +8A2 if (VM) goto INTERRUPT_PM; // Doesn't VM imply PM (except in instruction decoding)? +8A3 SHLCNT = 2; TMPB = SIGMA; +8A4 SIGMA = (0:TMPB) << SHLCNT; // SIGMA = TMPB << 2? We must be in real mode here +8A5 DESIDT; DLY; IND = SIGMA; +8A6 FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; RD_D; // Fetch of the offset? Or segment:offset since this is real mode? +8A7 IRF2 = DES_CS.LIMIT; CLI; DLY; +8A8 TMPC = IRF2; +8A9 SHRCNT = 0x10 & BITS_V; TMPB = OPR_R; UNL; +8AA SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 16? +8AB PROTUN = SIGMA; +8AC DES_CS.BASE = PROTUN << 4; +8AD DES_CS.LIMIT = TMPC; BITS16; +8AE PAGER5.PCR; goto PUSH_INT_FRAME; +8AF TMPG = TMPB; +------------------------------------------|---------------------------------------------------------------------------------------------- +8B0 INTERRUPT_PM: SHLCNT = 3; TMPB = SIGMA; // IDT contains task/interrupt/trap gate descriptors. Offset in bytes 0-1 and 6-7, selector in bytes 2-3, P/DPL in byte 5 +8B1 SIGMA = (0:TMPB) << SHLCNT; // SIGMA = TMPB << 3? +8B2 DESIDT; MISC1 = true; DLY; IND_DELTA = 4; IND = SIGMA + IND_DELTA; +8B3 SHRCNT = 0x10; SLCTR2 = SIGMA; rd_D; // Fetching bytes 4-7 of the gate +8B4 FLAGSB = EFLAGS; FLAGS_BACKED_UP = true; IND_DELTA = -4; IND += IND_DELTA; DLY; // Clear NT +8B5 PROTUN = OPR_R; SIGMA = OPR_R & 0xffff0000; UNL; rd_D; // Fetching bytes 0-3 of the gate +8B6 TMPB = SIGMA; DLY; if (!INTERRUPT_HW) goto INTERRUPT_SW; // TMPB = OPR_R & 0xffff0000 INTERRUPT_HW is only used here - determines whether we do TST_DES_INT_SW (which has an extra priv check) or TST_DES_INT_HW +8B7 TMPD = OPR_R; SIGMA = OPR_R & 0xffff; UNL; +8B8 SIGMA |= TMPB; // SIGMA = recombined offset from gate +8B9 TMPG = SIGMA; PTF TST_DES_INT_HW; // TST_DES_INT_HW can go to TASKGATE, #NP(I1,E0), TRAPGATE286, INTGATE286, TRAPGATE386, INTGATE386 or continue +8BA INTERRUPT_COMM: SIGMA = (0:TMPD) >> SHRCNT; // SIGMA = TMPD >> 16? +8BB TMPH = SIGMA; +8BC PTR = &DES_CS; DLY; PTSAV7 TST_DES_CGDEST; // TST_DES_CGDEST can go to PROT_TESTS_PASSED2 (N) (RETURNs), MORE_PRIVILEGE (KLN), #NP(I0,E0), continue. +8BD goto #GP(I1,E0); // we end up here if TST_INTERRUPT* continues +8BE PTGEN JMP_GFAULT_INT; // JMP_GFAULT_INT is unconditional jump to #GP(I1,E0) with FAULT flag set. But we're already going there, so I don't know why this isn't just a SET_FAULT. Also not sure if this causes 3 microops at #GP(I1,E0) to run twice +------------------------------------------|---------------------------------------------------------------------------------------------- +8BF INTERRUPT_SW: SIGMA |= TMPB; // SIGMA = recombined offset from gate +8C0 goto INTERRUPT_COMM; +8C1 TMPG = SIGMA; PTF TST_DES_INT_SW; // TST_DES_INT_SW can go to TASKGATE, #NP(I1,E0), TRAPGATE286, INTGATE286, TRAPGATE386, INTGATE386 or continue +------------------------------------------|---------------------------------------------------------------------------------------------- +8C2 INTGATE286: CLI; // Trap gates don't clear interrupt and trap flags, interrupt gates do. +8C3 TRAPGATE286: SIGMA = (-1)^0x4000; // SIGMA = 0xffffbfff 0x4000 corresponds to NT (Nested Task) flag +8C4 TMPB = SIGMA; MISC2 = true; +8C5 SIGMA = EFLAGS & TMPB; +8C6 EFLAGS = SIGMA; // Clear NT +8C7 LD_DESCRIPTOR(); // Load new CS descriptor +8C8 SLCTR = TMPH; PTSELE TST_SEL_CS; DLY; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L) +8C9 goto TRAP_INT_GATE; +8CA PROTUN = TMPH; BITS16; DLY; PTR->DEL = TMPC; // descriptor selected previously? +------------------------------------------|---------------------------------------------------------------------------------------------- +8CB INTGATE386: CLI; // Trap gates don't clear interrupt and trap flags, interrupt gates do. +8CC TRAPGATE386: SIGMA = (-1)^0x4000; // SIGMA = 0xffffbfff 0x4000 corresponds to NT (Nested Task) flag +8CD TMPB = SIGMA; MISC2 = false; +8CE SIGMA = EFLAGS & TMPB; +8CF EFLAGS = SIGMA; // Clear NT +8D0 LD_DESCRIPTOR(); // Load new CS descriptor +8D1 SLCTR = TMPH; PTSELE TST_SEL_CS; DLY; // TST_SEL_CS can go to #GP/#TS(I0,E0) or continue (L) +8D2 PROTUN = TMPH; BITS32; DLY; PTR->DEL = TMPC; // descriptor selected previously? INTERRUPT-TO-SAME-PRIVILEGE-LEVEL case (RETURN from LD_DESCRIPTOR) +8D3 TRAP_INT_GATE: PAGER5.PCR; PTGEN SET_RPL_TO_CPL; // (KM) +8D4 if (VM) goto GENERAL_FAULTP; // GENERAL_FAULTP goes to a jump to #GP/#TS(I0,E0). +8D5 PUSH_INT_FRAME: SIGMA = EFLAGS & 0xffff; +8D6 EFLAGS = SIGMA; // clear Resume Flag and Virtual 8086 Mode Flag? +8D7 DESCOD; IND = TMPG; +8D8 SIGMA = FLAGSB & 0x37fd7; PREF; +8D9 DESSTK; DLY; IND_DELTA = NEGWSZ; IND = ESP + IND_DELTA; +8DA OPR_W = SIGMA; WR; // write flags to bus? +8DB DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 8d9 +8DC OPR_W = CS; WR_W; // write return segment/selector to bus? +8DD TMPB = TMPF; CLT; DLY; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 8d9 +8DE OPR_W = EIP; WR; // write return offset to bus? +8DF eIP = TMPG; DLY; if (!ERROR_CODE_FLAG) goto TRAP_INT_DONE; +8E0 eSP = IRF2; BITS32; IND += IND_DELTA; // IND_DELTA set to NEGWSZ at 8d9 Does IRF2 here mean IND? +8E1 if (PM) goto PUSH_ERRORCODE; +8E2 SHRCNT = 0x10; +8E3 TRAP_INT_DONE: CS = PROTUN; RNI; +8E4 +------------------------------------------|---------------------------------------------------------------------------------------------- +8E5 PUSH_ERRORCODE: eSP = IRF2; IND_DELTA = 0; IND += IND_DELTA; // Why IND_DELTA = 0? Does IRF2 here mean IND? +8E6 SIGMA = (0:TMPB) >> SHRCNT; // SIGMA = TMPB >> 16? SHRCNT = 0x10 at 8e2 +8E7 OPR_W = SIGMA; WR_W; goto TRAP_INT_DONE; +8E8 DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +8E9 #PF: ICESIG; +8EA PAGE_FAULTLOOP: if (JICEWT) goto PAGE_FAULTLOOP; +8EB SIGMA = TMPF & 0xffff; // TODO: Where does TMPF come from? +8EC BITS32; // TODO: What is BITS32? +8ED TMPC = SIGMA; {-7E-}; DLY; // TODO: What is {-7E-}? TMPC = TMPF & 0xffff +8EE IRF2 = PFERRC.PCR; CONTRIBUTORY_FAULT = true; OPR_R; +8EF TMPB = IRF2; SHLCNT = 0x10; DLY; // Read TMPB from special register {-7A-}? +8F0 IRF2 = LATTTF.PCR; SIGMA = (0:TMPB) << SHLCNT; // LATTTF = Linear Address That Triggered The Fault. SIGMA = TMPB << 16; +8F1 CR2 = IRF2; ERROR_CODE_FLAG = true; // "CR2 is used for handling page faults when PG is set. The processor stores in CR2 the linear address that triggers the fault." +8F2 SIGMA |= TMPC; // SIGMA = (IND << 16) | (TMPF & 0xffff) +8F3 TMPF = SIGMA; SIGMA = 0x0d; // TMPF = (IND << 16) | (TMPF & 0xffff) Is this the error code (bit 0 = P, bit 1 = W/R, bit 2 = U/S)? (initial TMPF) with upper 16 bits coming from PFERRC +8F4 goto FAULT; +8F5 SIGMA += 1; // SIGMA = 0xe means "Interrupt 0x0e ÄÄ Page Fault" +------------------------------------------|---------------------------------------------------------------------------------------------- +8F6 if (PM && CPL > 0) goto NO_PRIVILEGE; // 0 LOADALL386 +8F7 ICESIG; +8F8 SIGMA = 0x800000fc; +8F9 SIGMA &= 0x7ff; // SIGMA = 0xfc +8FA DES_ES; IND_DELTA = EDI; IND = SIGMA + IND_DELTA; BITS32; DLY; // ES:EDI is the location to read from (uses actual ES, not the ES descriptor) +8FB DLY; IND_DELTA = 4; IND += IND_DELTA; // First read is is at EDI + 0x100 +8FC SIGMA = 0x0f; RD_D; +8FD SIGMA += 4; // SIGMA = 0x13 +8FE COUNTR = SIGMA; SIGMA = 0x0d; DLY; // COUNTR = 0x13 Why DLY? +8FF PROTUN = OPR_R; UNL; // PROTUN is first mystery read. +900 SIGMA -= 2; // SIGMA = 0x0b +901 EAX = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 8fb +902 LOADALL_LOOP1: SIGMA = COUNTR - EAX; RD_D; +903 DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 8fb +904 IRF[COUNTR] = OPR_R; UNL; if (JG) goto LOADALL_LOOP1; +905 --COUNTR; // Loop to load registers 0x13 down to 0x0b? - 9 of the 10 mystery reads described at https://www.rcollins.org/articles/loadall/tspec_a3_doc.html ? SLCTR2 TMPG TMPH FLAGSB TMPF TMPE TMPD TMPC TMPB +906 DES_ES; DLY; IND_DELTA = -4; IND = EDI + IND_DELTA; // Next reads back down to EDI (below the mystery reads). +907 DLY; IND_DELTA = 4; IND += IND_DELTA; +908 RD_D; +909 COUNTR = 9; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907 +90A MDTMP4 = OPR_R; UNL; RD_D; // 11th read (should be CR0) is to MDTMP4? +90B LOADALL_LOOP2: DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907 +90C IRF[COUNTR] = OPR_R; if (COUNTR != 1) goto LOADALL_LOOP2; UNL; RD_D; // Read EFLAGS? EIP EDI ESI EBP ESP EBX EDX ECX EAX (12th - 21st reads) +90D --COUNTR; +90E DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907 +90F EAX = OPR_R; SIGMA = 0x29; UNL; RD_D; +910 SIGMA -= 3; // SIGMA = 0x26 +911 COUNTR = SIGMA; DLY; IND += IND_DELTA; // COUNTR = 0x26; IND_DELTA set to 4 at 907 +912 DR6 = OPR_R; UNL; RD_D; // 22nd read is to DR6 +913 SIGMA = 0x5d; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907 +914 DR7 = OPR_R; UNL; RD_W; // 23rd read is to DR7 +915 TMPB = SIGMA; DLY; IND += IND_DELTA; // TMPB = 0x26 IND_DELTA set to 4 at 907 +916 TR = OPR_R; UNL; RD_W; // 24th read is to TR +917 LOADALL_LOOP3: SIGMA = TMPB + 0x0d; DLY; IND += IND_DELTA; // SIGMA = 0x33 IND_DELTA set to 4 at 907 +918 IRF[COUNTR] = OPR_R; if ((COUNTR & 15) != 1) goto LOADALL_LOOP3; UNL; RD_W; // Loop to load the segment/selector registers? LDT GS FS DS SS CS ES +919 --COUNTR; +91A COUNTR = SIGMA; DLY; IND += IND_DELTA; // COUNTR = 0x33 IND_DELTA set to 4 at 907 +91B ES = OPR_R; UNL; +91C LOADALL_LOOP4: PROTUN = COUNTR; SIGMA = COUNTR - 1; RD_D; +91D COUNTR = SIGMA; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 907 +91E TMPB = OPR_R; UNL; RD_D; +91F DLY; +920 SIGMA = IRF2 + 4; IND += IND_DELTA; // IND_DELTA set to 4 at 907 +921 TMPC = OPR_R; UNL; RD_D; +922 IRF[COUNTR].AR = TMPB; DLY; // Select AR field of descriptor cache +923 IRF[COUNTR].BAS = TMPC; DLY; // Select BASE field of descriptor cache +924 IRF[COUNTR].LIM = OPR_R; UNL; // Select LIMIT field of descriptor cache +925 DES_ES; IND_DELTA = 4; IND = SIGMA + IND_DELTA; +926 COUNTR = PROTUN; +927 // Why do we have a blank line here? +928 if ((COUNTR & 15) != 1) goto LOADALL_LOOP4; // Loop to load descriptor cache entries +929 --COUNTR; +92A IRF2 = DES_SS.AR; SIGMA = CR0 & 0xffff0000; DLY; // Paging bit is top bit of CR0 +92B PTGEN COPY_STACK_DPL; PROTUN = IRF2; // (KN) +92C SIGMA &= 0x800000fc; // Isolate paging bit? +92D COUNTR = SIGMA; +92E CR0 = MDTMP; // What is MDTMP? Value from MDTMP4 on line 90a? +92F if (COUNTR != 0) goto LOADALL_PAGING; TMPeIP = EIP; +930 IRF2 = DES_CS.LIMIT; ICEEXT; // ICEEXT only used here - presumably it exits ICE mode (sending a signal to the ICE that LOADALL has completed successfully?) +931 SIGMA = IRF2; +932 LOADALL_FINAL: DES_CS; CLRNMI; DLY; IND = SIGMA; +933 PAGER5.PCR; SIGMA = DR6; +934 DESCOD; ICEBRK; IND = EIP; +935 DR6 = SIGMA; PREF; +936 TMPeSP = ESP; DLY; +937 RNI; +938 +------------------------------------------|---------------------------------------------------------------------------------------------- +939 LOADALL_PAGING: SIGMA = IRF2; IRF2 = PDBR.PCR; // IRF2 = CR3 +93A DESABS; IND = IRF2; goto LOADALL_FINAL; // IND = CR3 +93B PDBR.PCR = IND; // CR3 = CR3 - don't change CR3, just flush the TLB +------------------------------------------|---------------------------------------------------------------------------------------------- +93C BITS32; // 0 ICEBP +93D goto BREAKPOINT_CMN; +93E ICEBRK; +------------------------------------------|---------------------------------------------------------------------------------------------- +93F SINGLE_STEP: SIGMA = DR6 | 0x4000; // Presumably we enter here (via the small PLA) if we're doing a single step (trap flag) breakpoint. "The BS bit is associated with the TF (trap flag) bit of the EFLAGS register. The BS bit is set if the debug handler is entered due to the occurrence of a single-step exception. The single-step trap is the highest-priority debug exception; therefore, when BS is set, any of the other debug status bits may also be set." +940 DR6 = SIGMA; +941 BREAKPOINT: TMPeIP = EIP; ICEBRK; // Presumably we enter here (via the small PLA) if one of the debug register breakpoints is hit +942 TMPeSP = ESP; BITS32; +943 BREAKPOINT_CMN: SHRCNT = 2; // ICEBRK always happens before we get to BREAKPOINT_CMN (whether from BREAKPOINT, ICEBP or GDHIT). BREAKPOINT_CMN can either do INT 1 or ICE_SINGLESTEP (which does STOREALL) +944 SIGMA = (0:0x4000) >> SHRCNT; // SIGMA = 0x4000 >> 2 = 0x1000 +945 TMPB = SIGMA; ICESIG; // TMPB = 0x1000 +946 SIGMA = DR7 & TMPB; // Undocumented bit of DR7 "0 MEANS INTEL RESERVED. DO NOT DEFINE." in manual https://en.wikipedia.org/wiki/X86_debug_register says "Action on breakpoint match: 0 = INT 1 (#DB exception, default) 1 = Break to ICE/SMM" +947 COUNTR = SIGMA; SHLCNT = 13; +948 SIGMA = (0:1) << SHLCNT; // SIGMA = 1 << 13 = 0x2000 +949 TMPB = TMPeIP; if (COUNTR != 0) goto ICE_SINGLESTEP; +94A SIGMA ^= -1; // SIGMA = 0xdfff +94B TMPB = SIGMA; // TMPB = 0xdfff +94C SIGMA = DR7 & TMPB; // SIGMA = DR7 & 0xdfff - clear "General Detect Enable" (If set, will cause a debug exception on any attempt at accessing the DR0-DR7 registers.) https://en.wikipedia.org/wiki/X86_debug_register +94D goto INTERRUPT_X; +94E DR7 = SIGMA; SIGMA = 1; // DR7 &= 0xdfff "Interrupt 1 ÄÄ Debug Exceptions" +------------------------------------------|---------------------------------------------------------------------------------------------- +94F ICE_SINGLESTEP: if (JICEWT) goto ICE_SINGLESTEP; +950 +951 goto STOREALL; +952 ICEENT; +------------------------------------------|---------------------------------------------------------------------------------------------- +953 ICE_PIN: ICEBRK; // this acts like BREAKPOINT_CMN but always does the ICE break instead of INT 1 +954 TMPB = DR7; BITS32; +955 SHRCNT = 2; +956 SIGMA = (0:0x4000) >> SHRCNT; // SIGMA = 0x4000 >> 2 = 0x1000 +957 TMPC = SIGMA; SIGMA = TMPC | TMPB; // TMPC = 0x1000 SIGMA = 0x1000 | DR7; Set "Action on breakpoint match:" to "1 = Break to ICE/SMM" (This will cause a system hang if an ICE is not connected.) +958 DR7 = SIGMA; DLY; // Why DLY? +959 TMPB = TMPeIP; ICESIG; +95A ICE_PIN_LOOP: if (JICEWT) goto ICE_PIN_LOOP; +95B SIGMA = DR6 | TMPC; // Waiting for something? Set BK/SMMS "SMM or ICE mode entered" bit in DR6 +95C goto STOREALL; +95D DR6 = SIGMA; ICEENT; +------------------------------------------|---------------------------------------------------------------------------------------------- +95E STOREALL16: TMPeIP = IRF2; COUNTR = 0x8200; +95F MDTMP4 = COUNTR; goto STOREALL_COMM; // MDTMP4 = 0x8200; +960 IRF2 = DES_TR.LIMIT; +------------------------------------------|---------------------------------------------------------------------------------------------- +961 STOREALL: SHLCNT = 0x10; IRF2 = DES_TR.AR; DLY; // do we actually do anything with IRF2? +962 MDTMP4 = -1; if (BITS == 16) goto STOREALL16; +963 IRF2 = DES_TR.BASE; SIGMA = (0:6) << SHLCNT; // SIGMA = 6 << 16 = 0x60000 +964 TMPeIP = IRF2; +965 IRF2 = DES_TR.LIMIT; +966 STOREALL_COMM: TMPeSP = IRF2; +967 COUNTR = SIGMA; SIGMA = 0x8200; // COUNTR = 0x60000 +968 DES_TR.AR = SIGMA; SIGMA = 0x800000fc; +969 SIGMA &= 0x7ff; // SIGMA = 0xfc +96A DES_TR.BASE = COUNTR // DES_TR.BASE = 0x60000 = 384kB mark? Why there? +96B DES_TR.LIMIT = 0xffffffff; DLY; +96C DES_TR; IND_DELTA = 4; IND = SIGMA + IND_DELTA; +96D OPR_W = PROTUN; SIGMA = 0x0f; WR_D; // WR_D is special write operation for ICE memory space (see https://web.archive.org/web/19970613081422/http://www.x86.org/ddj/Jan97/Jan97.html ). +96E SIGMA += 4; // SIGMA = 0x13 +96F COUNTR = SIGMA; // COUNTR = 0x13 +970 STOREALL_LOOP1: SIGMA = COUNTR - 0x0d; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 96c +971 OPR_W = IRF[COUNTR]; WR_D; +972 IRF[COUNTR] = 0; if (JG) goto STOREALL_LOOP1; // if (COUNTR > 0x0d) goto STOREALL_LOOP1; Loop to write SLCTR2, TMPG, TMPH, FLAGSB, TMPF, TMPE, TMPD +973 --COUNTR; +974 DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 96c COUNTR = 0x0c now? +975 OPR_W = TMPC; WR_D; // Write TMPC +976 DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 96c +977 OPR_W = TMPB; SIGMA = -4; WR_D; // Write TMPB +978 DLY; +979 IRF2 = PDBR.PCR; // IRF2 = CR3 +97A DESABS; IND = IRF2; // IND = CR3 +97B PDBR.PCR = IND; // CR3 = CR3 - don't change CR3 but flush TLB +97C DES_TR; IND_DELTA = 4; IND = SIGMA + IND_DELTA; DLY; SIGMA = 4; +97D SIGMA += 6; // SIGMA = 10 +97E COUNTR = SIGMA; goto STOREALL_LOOPS; +97F PROTUN = 0; PTGEN COPY_STACK_DPL; // (KN) +------------------------------------------|---------------------------------------------------------------------------------------------- +980 STOREALL_LOOP2: TMPB = 0; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 97c +981 STOREALL_LOOPS: OPR_W = IRF[COUNTR]; WR_D; if (COUNTR != 0) goto STOREALL_LOOP2; // Write 10-0 CR0 EFLAGS EIP EDI ESI EBP ESP EBX EDX ECX EAX +982 IRF[COUNTR] = 0; --COUNTR; +983 COUNTR = 0x29; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 97c +984 OPR_W = DR6; WR_D; // Write DR6? +985 SIGMA = COUNTR - 3; DLY; IND += IND_DELTA; // SIGMA = 0x26 IND_DELTA set to 4 at 97c +986 OPR_W = DR7; WR_D; // Write DR7? +987 COUNTR = SIGMA; DLY; IND += IND_DELTA; // COUNTR = 0x26 IND_DELTA set to 4 at 97c +988 OPR_W = TR; WR_W; // Write TR selector +989 STOREALL_LOOP3: TR = 0; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 97c +98A OPR_W = IRF[COUNTR]; WR_W; if ((COUNTR & 15) != 1) goto STOREALL_LOOP3; // Write other selectors (LDT GS FS DS SS CS) +98B IRF[COUNTR] = 0; --COUNTR; +98C DLY; +98D SIGMA = IRF2 + 4; IND += IND_DELTA; // IND_DELTA set to 4 at 97c +98E OPR_W = ES; WR_W; // Write ES +98F TMPE = SIGMA; SIGMA = 0x70; +990 SIGMA -= 7; // SIGMA = 0x69; +991 COUNTR = SIGMA; goto STOREALL_L4_ST; // COUNTR = 0x69; +992 ES = 0; SIGMA = 0 - (-1); DLY; +------------------------------------------|---------------------------------------------------------------------------------------------- +993 STOREALL_LOOP4: IRF2 = IRF[COUNTR].BASE; SIGMA = COUNTR & 0x1f; +994 TMPeIP = IRF2; // Load value 2 from descriptor cache = base? +995 IRF2 = IRF[COUNTER].LIMIT; SIGMA -= 0; // TODO: Why are we subtracting 0? +996 TMPeSP = IRF2; // Load value 3 from descriptor cache = limit? +997 IRF[COUNTER].BASE = 0; SIGMA = 0xffff; +998 IRF[COUNTER].LIMIT = SIGMA; SIGMA = 0x8200; // IRF[COUNTER].LIMIT = 0xffff +999 IRF[COUNTER].AR = SIGMA; // IRF[COUNTER].AR = 0x8200 +99A STOREALL_L4_ST: DES_TR; IND_DELTA = 4; IND = TMPE + IND_DELTA; +99B OPR_W = MDTMP; WR_D; // OPR_W = access rights ? +99C DR7 = 0; DLY; IND += IND_DELTA; // IND_DELTA set to 4 at 99a +99D OPR_W = TMPeIP; --COUNTR; WR_D; // Write value 2 = base? +99E DLY; +99F SIGMA = IRF2 + 4; IND += IND_DELTA; // IND_DELTA set to 4 at 99a +9A0 TMPE = SIGMA; +9A1 OPR_W = TMPeSP; WR_D; // Write value 3 = limit? +9A2 IRF2 = IRF[COUNTER].AR; DLY; if (JG) goto STOREALL_LOOP4; // if (IRF2 > -4) goto STOREALL_LOOP4; (Flags set from ALU op done at 99f?) +9A3 MDTMP4 = IRF2; // Is MDTMP4 same as MDTMP? +9A4 goto BOOTUP_JUMP; +9A5 DES_TR.BASE = 0; CLT; +------------------------------------------|---------------------------------------------------------------------------------------------- +9A6 BOOTUP: SIGMA = 0x29 | 0x40; // SIGMA = 0x69 +9A7 BOOTUP_LOOP1: TMPC = SIGMA; if (COUNTR != 0) goto BOOTUP_LOOP1; // TMPC = 0x69 +9A8 IRF[COUNTR] = 0; --COUNTR; // zero registers from 0x29 to 0 (TR, IDTR, GDTR, LDTR, GS, FS, DS, SS, CS, ES, ?, ?, MDTMP, OPROFF, FSVeIP, CSOPCD), DR7, DR6, TMPeSP, TMPeIP, PROTUN, MDTMP4, SLCTR2, TMPG, TMPH, FLAGSB, TMPF, TMPE, TMPD, TMPC, TMPB, CR0, EFLAGS, EIP, EDI-EAX) +9A9 COUNTR = 0x73; DESABS.BASE = 0; DLY; // SBAS selects base field of descriptor cache. However, I'm not sure that SBAS actually does anything here. Referencing DESABS should just put a phantom address (IND) on the address bus +9AA PDBR.PCR = IND; // Clear page cache? IND here is set to LDTR (nonsense value reused from jump uop). Maybe the value doesn't matter, we're just initializing/flushing the TLB but it needed to be something with a deterministic value. +9AB BOOTUP_LOOP2: DR7 = 0; if ((COUNTR & 15) != 1) goto BOOTUP_LOOP2; +9AC IRF[COUNTR].BAS = 0; --COUNTR; // zeroing all base fields in the descriptor cache? +9AD SIGMA = 0xffff; CR2 = 0; +9AE COUNTR = TMPC; TMPB = SIGMA; // TMPC here is 0x69 assuming it hasn't been zeroed. TMPB = 0xffff +9AF BOOTUP_LOOP3: SIGMA = 0x8200; DR6 = 0; +9B0 IRF[COUNTR].AR = SIGMA; if ((COUNTR & 15) != 1) goto BOOTUP_LOOP3; // IRF[COUNTR].AR = 0x8200. SAR = Select AR field of descriptor cache. 8200 = (G=0 DB=0 AVL=0 P=1 DPL=0 S=0 TYPE=2) = LDT? +9B1 IRF[COUNTR].LIMIT = TMPB; --COUNTR; // IRF[COUNTR].LIMIT = 0xffff. Initialises the descriptor cache with limit 0xffff and attributes 0x8200 SLIM selects LIMIT field of descriptor cache +9B2 DES_ES.AR = SIGMA; CONTRIBUTORY_FAULT = true; // DES_ES.AR = 0x8200 +9B3 DES_ES.LIMIT = TMPB; BITS32; // DES_ES.LIMIT = 0xffff +9B4 DR6 = 0; +9B5 SIGMA = 0x0303; TMPD = BIST1; // 0x0303 is initial EDX value (CPU type/stepping). +9B6 EDX = SIGMA; // set initial EDX value +9B7 TMPE = BIST2; SIGMA = TMPE ^ TMPD; // Compute the total BIST checksum +9B8 SIGMA ^= 0x3ddc0c2c; // XOR against expected value - result should be 0 if self-test passed +9B9 EAX = SIGMA; if (!BUSY# && !ERROR#) goto BOOTUP_JUMP; +9BA SIGMA = 0x10; CR0 = 0; // The 80387 holds its ERROR# output low after reset, whereas the 80287 holds its ERROR# output high. Not sure why we're checking BUSY# rather than ERROR# here. +9BB CR0 = SIGMA; // CR0 = 0x10 - set bit to indicate 80387 is present. CR0 bit 4 zero means "the configuration either contains an 80287 or does not contain a coprocessor" +9BC BOOTUP_JUMP: SHRCNT = 4; PROTUN = 0; // Initialize barrel shifter to shift right by 4? Presumably this routine sets up initial CS descriptor and IP +9BD SIGMA = (0:0xf0000) >> SHRCNT; // SIGMA = 0xf000 This is the initial CS value +9BE TMPB = SIGMA; SIGMA = 0xffff0000; +9BF DESCOD.BAS = SIGMA; SIGMA = 0xffff; // DESCOD = 0xffff0000 - this is the initial CS base (in order that the linear address of the first instruction is fffffff0) +9C0 DESCOD.LIM = SIGMA; +9C1 PAGER5.PCR; SIGMA -= 0x0f; // SIGMA = 0xfff0 +9C2 goto JMP_FAR_COMMON; +9C3 TMPG = SIGMA; SIGMA = TMPB; // TMPG = 0xfff0 - this is the initial EIP value +9C4 =====================================| +9C5 =====================================| +9C6 =====================================| +9C7 =====================================| +9C8 =====================================| +9C9 =====================================| +9CA =====================================| +9CB =====================================| +9CC =====================================| +9CD =====================================| +9CE =====================================| +9CF =====================================| +9D0 =====================================| +9D1 =====================================| +9D2 =====================================| +9D3 =====================================| +9D4 =====================================| +9D5 =====================================| +9D6 =====================================| +9D7 =====================================| +9D8 =====================================| +9D9 =====================================| +9DA =====================================| +9DB =====================================| +9DC =====================================| +9DD =====================================| +9DE =====================================| +9DF =====================================| +9E0 =====================================| +9E1 =====================================| +9E2 =====================================| +9E3 =====================================| +9E4 =====================================| +9E5 =====================================| +9E6 =====================================| +9E7 =====================================| +9E8 =====================================| +9E9 =====================================| +9EA =====================================| +9EB =====================================| +9EC =====================================| +9ED =====================================| +9EE =====================================| +9EF =====================================| +9F0 =====================================| +9F1 =====================================| +9F2 =====================================| +9F3 =====================================| +9F4 =====================================| +9F5 =====================================| +9F6 =====================================| +9F7 =====================================| +9F8 =====================================| +9F9 =====================================| +9FA =====================================| +9FB =====================================| +9FC =====================================| +9FD =====================================| +9FE =====================================| +9FF =====================================| diff --git a/80386/parts.txt b/80386/parts.txt new file mode 100644 index 0000000..cf70ad0 --- /dev/null +++ b/80386/parts.txt @@ -0,0 +1,84 @@ +Main ROM: + Image (3).raw + 256x370 physically, 37x2560 logically + Actual microcode data + Opcodes are row-major + Ordered from bottom to top and right to left + Column pairs are swapped + See fields.txt for descriptions of which bit patterns mean what + See microcode_10.txt for full diassembly (generated by disassembler program) + See microcode_notes.txt for reenigne's line-by-line notes on microcode (some notes may be out of date) + +Decoder (aka pla2/pla3): + 386 files\\bits_l.py input + 386 files\\bits_r.py input + 386 files\\bits_addr_l.py output + 386 files\\bits_addr_r.py output + 13 bits input, 16 bits output + 184 entries in each, 368 entries total + Input bits: + Bits 1-8 opcode + Bit 12 = 0F prefix present + Bit 11 = this is an instruction? + Bit 10 = protected mode? + Bit 9 = repeat flag present + Bit 0 = 32 bit mode? + Output bits: + 12 are microcode addresses + 4 indicate how memory is used: + 0 = register only, SIDT/SGDT mw, some ESC m? + 1 = modrm memory, A<->[i] (sets EA, and points IND at EA) + 2 = CALL, PUSH, ENTER (points IND at eSP?) + 3 = POP, RET, IRET (points IND at eSP?) + 9 = memory read/modify/write operations? + Some output to "invalid opcode" handler address + Some output to all zeros + Some output to a 6-bit opcode that is then fed back into the decoder + in the cases where decoder #2/#3 output is 0x0000 to 0x003f (call the output bits 0000000000ABCDEF) and it's decoding an instruction that has a modrm byte, + that output is fed back into decoder #2/#3 with inputs .ABrrrCDEFm0x where + rrr are the reg bits from the modrm byte, + m is 1 if the modrm byte refers to memory (i.e. mod != 11). + I'm not sure where the x bit comes from yet but it doesn't seem to distinguish between two different actual possibilities (usually one of the x values maps to all zeroes output, i.e. "can never happen"). + See decoder23.txt and decode2.txt for details + +rom1: + rom1_input_new.txt + rom1_output_new.txt + 176 entries + 19 input bits + Input bits 16-19 might be different prefixes. + Bits 1-6 might be "decoder state" - they're ?00000 if we're decoding an opcode - I suspect the other values might encode where we are in decoding modrm/sib bytes. + 12 output bits + equivalent of group ROM (instruction flags) when 5 bits are all 0? + see rom1_processed.txt + +pla4: + pla4_input_new.txt + pla4_output_new.txt + 16 input bits + Input bits 0-2 are rarely care, + 3 is never care, + 4-9 are sometimes care and + 10-15 are usually care. (These correspond to ABCDEF bits from the main ROM) + It gets its inputs through a different path than the others. Specifically, it gets bits directly from the data bus, rather than through the instruction prefetch. It looks at bits 0-15 as well as bits 22 and 23. + 23, 22, 15, 14, 13, 12 go through a tiny PLA to be transformed into a 4 bit code which is then combined with bits 11-0 in PLA#4 + Are these 4 bits input bits 0-3 (and only 8 cases are generated by the tiny PLA so bit 3 is unused?) + 18 output bits + Bits 15..4 are microcode addresses (addresses 0xedd and 0xffd are also generated but can never happen) + protection unit + 160 entries, 338 once expanded (see pla4_expanded.txt) + See tests.txt for interpretation + See pla1_pla4_z386.md for nand2mario's notes on rom1 and pla4 + +Small jump table PLA: + small_pla.txt + 11 entries? + 14 input bits? + 12 output bits = microcode address + +Constant ROM: + See constant_rom.txt + 32 bits output - most seem to be useful values + 36 entries - 6 bits input? + Numbering doesn't seem to match with constants deduced from code + diff --git a/80386/pla1_pla4_z386.md b/80386/pla1_pla4_z386.md new file mode 100644 index 0000000..4fe6863 --- /dev/null +++ b/80386/pla1_pla4_z386.md @@ -0,0 +1,83 @@ + + +## z386 ROM1 and PLA4 notes + +For ROM1 (`pla_control` in z386), I feed it with: + +``` +{state[6:0], inst_byte[7:0], mode[4:0]} +``` + +`inst_byte` is either the opcode byte or the ModR/M byte, depending on the +decode state. The `mode` bits are: + +``` +mode[4] = 0F escape seen +mode[3] = addr32 && mod != 3 && r/m == 4, so a SIB byte follows +mode[2] = addr32 && mod == 0 && r/m == 5, so disp32-only addressing +mode[1] = addr16 && mod == 0 && r/m == 6, so disp16-only addressing +mode[0] = addr32 +``` + +The ROM1 output is 12 bits (`abcdefghijkl`). In the opcode state z386 +interoperates it as: + +``` +l structural decode complete, excluding trailing immediates/displacements +k opcode has a W bit +j 0 means opcode[2:0] is an embedded register; j=1,l=0 means ModR/M follows +i segment-register PUSH/POP class +h ALU/update-flags class +c,d prefix / ModR/M / two-operand classification +ab immediate-size class for ModR/M instructions +abcdef immediate/layout class for non-ModR/M instructions +``` + +For ModR/M decoding, the most important output bits are: + +``` +f SIB byte follows +e,d displacement class +fed 000 none, 010 disp8, 011 disp16/32, + 100 SIB only, 101 SIB+disp8, 110 SIB+disp16/32, + 111 SIB+disp32 +``` + +For PLA4 / ROM4 (`protection.sv`), I feed it with: + +``` +{state[15:6], const[5:0]} +``` + +`const[5:0]` is the `ABCDEF` field from the microcode word. The upper ten state +bits come from the small "tiny PLA" / muxing logic in front of ROM4. In z386 I +name those bits: + +``` +bit 15 p1 privilege comparison 1, depending on protection ALU op +bit 14 p2 privilege comparison 2, depending on protection ALU op +bit 13 b13 appears unused +bit 12 b12 appears unused +bit 11 p descriptor present bit, descriptor G bit for the granularity test, + or selector-null for selector-only tests +bit 10 u descriptor S bit, or CR0.ET for FPU tests +bit 9 x descriptor type[3], executable, or CR0.TS for FPU tests +bit 8 ce descriptor type[2], conforming/expand-down, or CR0.EM for FPU tests +bit 7 rw descriptor type[1], readable/writable, or CR0.MP for FPU tests +bit 6 a descriptor type[0], accessed +``` + +The `p1/p2` formulas depend on the protection ALU op (`PTOVRR`, `PTSELA`, +`PTSELE`, `PTF`, etc.). The current formulas are enough for z386, but I would +still treat them as inferred. + +For PLA4 output, the high four bits are the `KLMN` side-effect flags. z386 uses +them as: + +``` +K stack operation / CPL update side effect +L perform limit/type validation +M descriptor or selector validation OK, safe to commit +N set the descriptor accessed bit +``` + diff --git a/80386/pla4_expanded.txt b/80386/pla4_expanded.txt new file mode 100644 index 0000000..ce7bc5f --- /dev/null +++ b/80386/pla4_expanded.txt @@ -0,0 +1,338 @@ +?????0000010000? 00 000000000000 0000 +?????10000100?0? 00 000000000000 0000 +??????1000100000 00 000000000000 0000 +???????1001000?0 00 000000000000 0000 +???????010100000 00 000000000000 0000 +?????0?1101000?0 00 000000000000 0000 +??????0001100000 00 000000000000 0000 +??????1001100?00 00 000000000000 0000 +???????101100000 00 000000000000 0000 +????????11100000 00 000000000000 0000 +??????????11000? 00 000000000000 0000 +?????000000010?0 00 000000000000 0000 +?????1000000100? 00 000000000000 0000 +?????0100000100? 00 000000000000 0000 +?????11000001000 00 000000000000 0000 +?????00100001?00 00 000000000000 0000 +?????10100001000 00 000000000000 0000 +??????1100001000 00 000000000000 0000 +?????00010001000 00 000000000000 0000 +?????100100010?0 00 000000000000 0000 +??????1010001000 00 000000000000 0000 +???????110001000 00 000000000000 0000 +???????001001000 00 000000000000 0000 +???????10100100? 00 000000000000 0000 +????????11001000 00 000000000000 0000 +0????00???101000 00 000000000000 0000 +?????10???101000 00 000000000000 0000 +??????1???101000 00 000000000000 0000 +????1??1??11100? 00 000000000000 0000 +?????0000?10010? 00 000000000000 0000 +??????100010?100 00 000000000000 0000 +???????10010?100 00 000000000000 0000 +????????1?10010? 00 000000000000 0000 +?????10?0110010? 00 000000000000 0000 +?????0?10110010? 00 000000000000 0000 +?????00000?01100 00 000000000000 0000 +?????1??0?001100 00 000000000000 0000 +0????01?0?001100 00 000000000000 0000 +????????1?001100 00 000000000000 0000 +?????00?01001100 00 000000000000 0000 +?????100?0101100 00 000000000000 0000 +?????0?01?101100 00 000000000000 0000 +0????11010101100 00 000000000000 0000 +?????0?110101100 00 000000000000 0000 +0????1?110101100 00 000000000000 0000 +???????001101100 00 000000000000 0000 +???????1?1101100 00 000000000000 0000 +0????1?011101100 00 000000000000 0000 +???????0?0011100 00 000000000000 0000 +???????100011100 00 000000000000 0000 +???????11001110? 00 000000000000 0000 +????????01011100 00 000000000000 0000 +????????1101110? 00 000000000000 0000 +?0??1?????111100 00 000000000000 0000 +???????0?0100010 00 000000000000 0000 +?????????1100010 00 000000000000 0000 +????1??1??110010 00 000000000000 0000 +?????10000001?10 00 000000000000 0000 +??????1000001010 00 000000000000 0000 +???????1?0001010 00 000000000000 0000 +?????0?010001010 00 000000000000 0000 +?????11010001?10 00 000000000000 0000 +?????????1001010 00 000000000000 0000 +0????000??10101? 00 000000000000 0000 +?????01???101010 00 000000000000 0000 +00???001??10101? 00 000000000000 0000 +100??001??101010 00 000000000000 0000 +?1???001??10101? 00 000000000000 0000 +??????00??011010 00 000000000000 0000 +00????10??011010 00 000000000000 0000 +1?????10??011010 00 000000000000 0000 +00?????1??011010 00 000000000000 0000 +1??????1??011010 00 000000000000 0000 +00????????111010 00 000000000000 0000 +?????00?0?10?110 00 000000000000 0000 +?????1??0?10?110 00 000000000000 0000 +00???01?0?10?110 00 000000000000 0000 +?1???01?0?10?110 00 000000000000 0000 +????????1?10?110 00 000000000000 0000 +???????0?0010110 00 000000000000 0000 +???????100010110 00 000000000000 0000 +???????11001?110 00 000000000000 0000 +????????01010110 00 000000000000 0000 +????????1101?110 00 000000000000 0000 +?0??1?????110110 00 000000000000 0000 +0????010??001110 00 000000000000 0000 +?????1100?00111? 00 000000000000 0000 +0????0010?00111? 00 000000000000 0000 +0????1010000111? 00 000000000000 0000 +0?????110?00111? 00 000000000000 0000 +?????100100?1110 00 000000000000 0000 +0??????11000111? 00 000000000000 0000 +?????10?0100111? 00 000000000000 0000 +?????1??11001110 00 000000000000 0000 +0????0?11100111? 00 000000000000 0000 +?????0?00?011110 00 000000000000 0000 +0????10000011110 00 000000000000 0000 +0????110?0011110 00 000000000000 0000 +???????10?011110 00 000000000000 0000 +?????0?010011110 00 000000000000 0000 +0????1?001011110 00 000000000000 0000 +??????100010?001 00 000000000000 0000 +?????0?100100001 00 000000000000 0000 +????????10100001 00 000000000000 0000 +?????????1100001 00 000000000000 0000 +?????00000?01001 00 000000000000 0000 +?????110000010?1 00 000000000000 0000 +??????0100001001 00 000000000000 0000 +??????11000010?1 00 000000000000 0000 +????????1?0010?1 00 000000000000 0000 +???????001?01001 00 000000000000 0000 +?????100?0101001 00 000000000000 0000 +???????100101001 00 000000000000 0000 +?????0?01?101001 00 000000000000 0000 +0????11010101001 00 000000000000 0000 +?????0?110101001 00 000000000000 0000 +0????1?110101001 00 000000000000 0000 +???????1?1101001 00 000000000000 0000 +0????1?011101001 00 000000000000 0000 +?????00000000101 00 000000000000 0000 +?????1000000?101 00 000000000000 0000 +??????1000000101 00 000000000000 0000 +???????100?00101 00 000000000000 0000 +????????10000101 00 000000000000 0000 +?????????1000101 00 000000000000 0000 +??????100?100101 00 000000000000 0000 +0????0100?001101 00 000000000000 0000 +?????110?0001101 00 000000000000 0000 +0????0?10?001101 00 000000000000 0000 +?????1?10?001101 00 000000000000 0000 +?????00?1?001101 00 000000000000 0000 +?????100100?1101 00 000000000000 0000 +0????01?1?001101 00 000000000000 0000 +?????1?110001101 00 000000000000 0000 +?????1?0?1001101 00 000000000000 0000 +?????1?1110011?1 00 000000000000 0000 +0????000??101101 00 000000000000 0000 +?????01???101101 00 000000000000 0000 +00???001??101101 00 000000000000 0000 +100??001??101101 00 000000000000 0000 +?1???001??101101 00 000000000000 0000 +?????0?00?011101 00 000000000000 0000 +???????10?011101 00 000000000000 0000 +?????0?010011101 00 000000000000 0000 +00??1?????111101 00 000000000000 0000 +?????00?0?100011 00 000000000000 0000 +?????1??0?100011 00 000000000000 0000 +00???01?0?100011 00 000000000000 0000 +?1???01?0?100011 00 000000000000 0000 +????????1?100011 00 000000000000 0000 +?????010000?1011 00 000000000000 0000 +??????1?01001011 00 000000000000 0000 +?????10???101011 00 000000000000 0000 +??????1???101011 00 000000000000 0000 +?????0000?011011 00 000000000000 0000 +?????10?0?011011 00 000000000000 0000 +?????0?100011011 00 000000000000 0000 +??????001?011011 00 000000000000 0000 +?????01?10011011 00 000000000000 0000 +?????01??1011011 00 000000000000 0000 +?0??0?????111011 00 000000000000 0000 +??????11??000111 00 000000000000 0000 +0????000??100111 00 000000000000 0000 +?????10???100111 00 000000000000 0000 +??????1???100111 00 000000000000 0000 +00???001??100111 00 000000000000 0000 +?1???001??100111 00 000000000000 0000 +?????100?0001111 00 000000000000 0000 +0????0100??01111 00 000000000000 0000 +0?????101?001111 00 000000000000 0000 +0????10011001111 00 000000000000 0000 +?????1????101111 00 000000000000 0000 +0????0?10?101111 00 000000000000 0000 +?????00?1?101111 00 000000000000 0000 +0????01?1?101111 00 000000000000 0000 +??????????010000 00 000000000000 0001 +????11?1101000?0 00 000000111000 0111 +1???100???101000 00 000000111000 0111 +????111101100100 00 000000111000 0111 +1???111010101100 00 000000111000 0111 +1???11?011101100 00 000000111000 0111 +1???1000??10101? 00 000000111000 0111 +101?1001??101010 00 000000111000 0111 +????11?100100001 00 000000111000 0111 +1???111010101001 00 000000111000 0111 +1???11?011101001 00 000000111000 0111 +1???1000??101101 00 000000111000 0111 +101?1001??101101 00 000000111000 0111 +10??1001??101011 00 000000111000 0111 +1???1000??100111 00 000000111000 0111 +10??1001??100111 00 000000111000 0111 +????10000?101111 00 000000111000 0111 +1???10100?101111 00 000000111000 0111 +1???10?10?101111 00 000000111000 0111 +1???101?1?101111 00 000000111000 0111 +01????10??011010 00 000001010101 1010 +01?????1??011010 00 000001010101 1010 +?????111??000110 00 000001011100 1010 +1???11?110101100 00 000001011111 1011 +1???11?110101001 00 000001011111 1011 +?????1????101010 00 000001110110 1010 +?????011??000010 00 000010101010 1010 +1???010000011110 00 000011001100 0110 +????010000011101 00 000011001100 0110 +?????011??000110 00 000011100010 1010 +1???011010101100 00 000011100011 1010 +1???011010011110 00 000011100011 1010 +1???011010101001 00 000011100011 1010 +????011010011101 00 000011100011 1010 +1???011001011110 00 000100001100 0110 +????011001011101 00 000100001100 0110 +?????00101011011 00 000100011000 0110 +?????11101011011 00 000100011000 0110 +????0?????01100? 00 000100100110 1010 +????0?????010111 00 000100100110 1010 +????0?????111111 00 000100100110 1010 +10??101?0?10?110 00 000101011000 0111 +10??101?0?100011 00 000101011000 0111 +1????01?0?001100 00 000101100011 1010 +?????0000?001101 00 000101100011 1010 +1????0100?0011?1 00 000101100011 1010 +1????0?10?001101 00 000101100011 1010 +1????01?1?001101 00 000101100011 1010 +?????000??001111 00 000101100011 1010 +1????0010?001111 00 000101100011 1010 +1????10100001111 00 000101100011 1010 +1?????110?001111 00 000101100011 1010 +1?????101?001111 00 000101100011 1010 +1??????110001111 00 000101100011 1010 +1????10011001111 00 000101100011 1010 +1????0?111001111 00 000101100011 1010 +?????10111011011 00 000110011000 0110 +??????0???000100 00 000110110010 1010 +??????10??000100 00 000110110010 1010 +??????0???000?1? 00 000110110010 1010 +??????10??000?1? 00 000110110010 1010 +??????0?0?001011 00 000110110010 1010 +?????111??000011 00 000111001010 1010 +????0?????110111 00 000111011000 0110 +?????011??000100 00 000111011100 1010 +?????000??001110 00 000111011101 1010 +1????010??001110 00 000111011101 1010 +1????0010?001110 00 000111011101 1010 +1????10100001110 00 000111011101 1010 +1?????110?001110 00 000111011101 1010 +1??????110001110 00 000111011101 1010 +1????0?111001110 00 000111011101 1010 +?????1100?011011 00 000111101000 0110 +?????10110011011 00 000111101000 0110 +1???010011101100 00 000111110110 1010 +1???010011101001 00 000111110110 1010 +?????1????000001 00 001000101000 1010 +1???110000011110 00 001000111000 0111 +1???1110?0011110 00 001000111000 0111 +1???11?001011110 00 001000111000 0111 +????110000011101 00 001000111000 0111 +????1110?0011101 00 001000111000 0111 +????11?001011101 00 001000111000 0111 +?????0????000001 00 001001001000 1010 +??????????010101 00 001010011000 0111 +????0?????110100 00 001010011111 1010 +????0??1??110010 00 001010011111 1010 +?????011??000011 00 001010101010 1010 +????01110110010? 00 001010101110 1010 +?????0????000000 00 001010110100 1010 +????0?????011111 00 001010111101 1010 +?????111??000010 00 001011001010 1010 +????1??0??111000 00 001011101000 0111 +????0?????11110? 00 001011101000 0111 +?1??1?????111100 00 001011101000 0111 +????1??0??110010 00 001011101000 0111 +????0?????11?110 00 001011101000 0111 +?1??1?????110110 00 001011101000 0111 +???????0??111001 00 001011101000 0111 +????0??1??111001 00 001011101000 0111 +????111101100101 00 001011101000 0111 +???????0??110101 00 001011101000 0111 +????0??1??110101 00 001011101000 0111 +01??1?????111101 00 001011101000 0111 +????0?????110011 00 001011101000 0111 +????0??1??111000 00 001011101101 1010 +????0??0??111000 00 001011101101 1111 +1???011011101100 00 001011110110 1010 +1???011011101001 00 001011110110 1010 +????1?????011111 00 001011111101 1010 +????0??0??110010 00 001011111111 1111 +1???01?110101100 00 001100001011 1010 +1???01?110101001 00 001100001011 1010 +1???011000011110 00 001100001100 0110 +????011000011101 00 001100001100 0110 +?????00111011011 00 001100011000 0110 +????01?110100000 00 001100101110 1010 +????01?100100001 00 001100101110 1010 +1?????????111010 00 001100110101 1010 +?????1????101101 00 001100110110 1010 +1???010001011110 00 001101001100 0110 +????010001011101 00 001101001100 0110 +?????11100011011 00 001101101000 0110 +?????11?1?011011 00 001101101000 0110 +?????00110011011 00 001101101000 0110 +?1??0?????111011 00 001101101000 0111 +????1?????111011 00 001101101000 0111 +?????1????000000 00 001101110100 1010 +?????111??000100 00 001110011100 1010 +????01?110100010 00 001111100011 1010 +1???0000??101000 00 010101101110 1010 +10??0001??101000 00 010101101110 1010 +10??001?0?100011 00 010101101110 1010 +1???0000??101011 00 010101101110 1010 +10??0001??101011 00 010101101110 1010 +1???0000??101010 00 011010101110 1010 +101?0001??101010 00 011010101110 1010 +10??001?0?100110 00 011010101110 1010 +1???0000??101101 00 011010101110 1010 +101?0001??101101 00 011010101110 1010 +1???0000??100111 00 011010101110 1010 +10??0001??100111 00 011010101110 1010 +????00000?101111 00 011010101110 1010 +1???00100?101111 00 011010101110 1010 +1???00?10?101111 00 011010101110 1010 +1???001?1?101111 00 011010101110 1010 +01????????111010 00 100000000000 0000 +??????????010011 00 100000000000 0000 +????1?????01100? 01 000000000000 0000 +??????????010100 01 000000000000 0000 +????1?????110100 01 000000000000 0000 +????1?????111110 01 000000000000 0000 +????1??1??110101 01 000000000000 0000 +10??1?????111101 01 000000000000 0000 +?0??1?????110011 01 000000000000 0000 +????1?????010111 01 000000000000 0000 +????1?????11?111 01 000000000000 0000 +11??1?????111101 01 000110000101 1010 +?1??1?????110011 01 001011101000 0111 +??????????010001 10 010000000000 0000 +10??001?0?101110 10 011010101110 1010 +??????????010010 10 100000000000 0000 +11??0001??101000 11 011101111110 1010 diff --git a/80386/rom1_processed.txt b/80386/rom1_processed.txt new file mode 100644 index 0000000..daee127 --- /dev/null +++ b/80386/rom1_processed.txt @@ -0,0 +1,350 @@ +nopqrs 76543210 tuvwx abcdefghijkl + + +?00000 0000011? 0???? 100000001101 PUSH/POP ES +?00000 00001111 0???? 000000000100 0F prefix +?00000 00010110 0???? 100000001101 PUSH SS +?00000 0001?111 0???? 100000001101 POP SS/DS +?00000 000?1110 0???? 100000001101 PUSH CS/DS +?00000 001??110 0???? 000000000100 ES:/DS:/CS:/SS: +?00000 001??111 0???? 100000010101 DAA/DAS/AAA/AAS +?00000 00???0?? 0???? 101100010110 alu r<->rm +?00000 00???100 0???? 100111010111 alu AL,ib +?00000 00???101 0???? 110111010111 alu eAX,iv +?00000 010????? 0???? 100000010001 INC rv/DEC rv/PUSH rv/POP rv +?00000 0110000? 0???? 100000000101 PUSHAd/POPAd +?00000 0110001? 0???? 101100000100 BOUND/ARPL +?00000 011001?? 0???? 000000000100 FS:/GS:/OPSIZE:/ADSIZE: +?00000 01101000 0???? 110111000101 PUSH imm +?00000 01101001 0???? 011100010100 IMUL Gv,Ev,Iz +?00000 01101010 0???? 000111000101 PUSH ib +?00000 01101011 0???? 111100010100 IMUL rv,rmv,ib +?00000 0111???? 0???? 100010010101 Jcond cb +?00000 10000001 0???? 011100000110 alu rmv,iv +?00000 10000011 0???? 111100000110 alu rmv,ib +?00000 100000?0 0???? 001100000110 alu rmb,ib +?00000 100001?? 0???? 101100010110 TEST rm,r/XCHG rm,r +?00000 100010?? 0???? 101100000110 MOV rm<->r +?00000 100011?? 0???? 101100000100 MOV segreg<->rm/LEA/POP rmv +?00000 10010??? 0???? 100000000001 XCHG eAX,rv +?00000 1001100? 0???? 100000010011 TEST ACC,imm +?00000 10011010 0???? 111111100101 CALL cd +?00000 1001110? 0???? 100000000101 PUSHF/POPF +?00000 10011110 0???? 100000000101 SAHF +?00000 10011?11 0???? 100000000101 WAIT/LAHF +?00000 101000?? 0???? 100110000111 MOV ACC<->[i] +?00000 10101000 0???? 100111010111 TEST AL,ib +?00000 10101001 0???? 110111010111 TEST eAX,iv +?00000 1010101? 0???? 100000000111 STOS +?00000 1010?1?? 0???? 100000000111 MOVS/CMPS/LODS/SCAS +?00000 10110??? 0???? 100111000011 MOV rb,ib +?00000 10111??? 0???? 110111000011 MOV rv,iv +?00000 1100000? 0???? 001100000110 rot rmv,ib +?00000 11000011 0???? 100000100101 RET +?00000 1100010? 0???? 101100000100 LES/LDS +?00000 11000110 0???? 001100000110 MOV rmb,ib +?00000 11000111 0???? 011100000110 MOV rmv,iv +?00000 11001000 0???? 101111000101 ENTER +?00000 11001100 0???? 100000100101 INT 3 +?00000 11001101 0???? 100111100101 INT ib +?00000 11001?11 0???? 100000100101 RETF/IRET +?00000 1100?010 0???? 010111100101 RET iw/RETF iw +?00000 110100?? 0???? 101000000110 rot +?00000 1101010? 0???? 100111010101 AAM ib/AAD ib +?00000 1101011? 0???? 100000000111 SALC/XLAT +?00000 11011??? 0???? 101011000100 ESC +?00000 1110000? 0???? 100010100101 LOOPE/LOOPNE +?00000 11100010 0???? 100010100101 LOOP +?00000 11100011 0???? 100010000101 JCXZ +?00000 111001?? 0???? 100111000111 IN ACC,ib/OUT ib,ACC +?00000 1110100? 0???? 011111100101 CALL cw/JMP cw +?00000 11101010 0???? 111111100101 JMP cd +?00000 11101011 0???? 100010100101 JMP cb +?00000 11110000 0???? 000000000100 LOCK +?00000 11110001 0???? 100000100101 ICEBP +?00000 1111001? 0???? 000000000100 REP/REPNE +?00000 11110110 0???? 110000000110 math rmb +?00000 11110111 0???? 010000000110 math rmv +?00000 111110?? 0???? 100000010101 CLC/STC/CLI/STI +?00000 1111111? 0???? 001000000110 misc +?00000 1111?10? 0???? 100000010101 HLT/CMC/CLD/STD +?00000 ?11011?? 0???? 100000000111 IN ACC,DX/OUT DX,ACC/INS Yb,DX/INS Yz,DX/OUTS DX,Xb/OUTS DX,Xz +?00000 000000?? 1???? 101100000100 SLDT/STR/LLDT/LTR/VERR/VERW/SGDT/SIDT/LGDT/LIDT/SMSW/LMSW +?00000 0000010? 1???? 100000000101 illegal? LOADALL286 +?00000 00000110 1???? 100000010101 CLTS +?00000 00000111 1???? 100000100101 LOADALL +?00000 000010?0 1???? 100000000101 illegal? +?00000 000100?? 1???? 101100000110 UMOV +?00000 00011000 1???? 100000000101 illegal? +?00000 000?1001 1???? 100000000101 illegal? +?00000 001000?1 1???? 101101000100 MOV Ry,Dy/MOV Dy,Ry +?00000 001001?1 1???? 100000000101 illegal? +?00000 00100??0 1???? 101101000100 MOV Ry,Cy/MOV Cy,Ry/MOV Ry,Ty/MOV Ty,Ry +?00000 0010100? 1???? 100000000101 illegal? +?00000 001100?? 1???? 100000000101 illegal? +?00000 00?10100 1???? 100000000101 illegal? +?00000 00?101?1 1???? 100000000101 illegal? +?00000 00?11010 1???? 100000000101 illegal? +?00000 00?1?110 1???? 100000000101 illegal? +?00000 00??110? 1???? 100000000101 illegal? +?00000 00??1?11 1???? 100000000101 illegal? +?00000 01000000 1???? 100000000101 illegal? +?00000 0100?001 1???? 100000000101 illegal? +?00000 0?001110 1???? 100000000101 illegal? +?00000 1000???? 1???? 011111010101 Jcond cv +?00000 1001?00? 1???? 101100010100 SETO/SETNO/SETS/SETNS +?00000 1001?100 1???? 101100010100 SETcond/SETcond +?00000 1001?1?1 1???? 101100010100 SETcond/SETcond/SETcond/SETcond +?00000 1001??10 1???? 101100010100 SETcond/SETcond/SETcond/SETcond +?00000 10100010 1???? 100000000101 illegal? +?00000 10100011 1???? 101100010100 BT Ev,Gv +?00000 1010011? 1???? 101100000100 XBTS/IBTS +?00000 10101?11 1???? 101100010100 BTS Ev,Gv IMUL Gv,Ev +?00000 1010?00? 1???? 100000001101 PUSH/POP FS/GS +?00000 1010?100 1???? 001100010100 BT Ev,Gv SHRD Ev,Gv,CL +?00000 1010?101 1???? 101100010100 SHLD Ev,Gv,CL SHRD Ev,Gv,CL +?00000 1011000? 1???? 100000000101 illegal? +?00000 10110010 1???? 101100000100 LSS +?00000 10111010 1???? 001100000100 BT/BTS/BTR/BTC Ev,Ib +?00000 1011?10? 1???? 101100000100 LFS/LGS/BSF/BSR +?00000 1011?11? 1???? 101100010110 MOVSX/MOVZX +?00000 10?1?011 1???? 101100010100 SETcond/SETcond BTR Ev,Gv BTC Ev,Gv +?00000 1100000? 1???? 100000000101 illegal? +?00000 ?100?010 1???? 100000000101 illegal? +?00000 ?1010000 1???? 100000000101 illegal? +?00000 ?101?001 1???? 100000000101 illegal? +?00000 ?10?1000 1???? 100000000101 illegal? +?00000 ?11000?0 1???? 100000000101 illegal? +?00000 ?1101000 1???? 100000000101 illegal? +?00000 ?110?001 1???? 100000000101 illegal? +?00000 ?111000? 1???? 100000000101 illegal? +?00000 ?1?001?0 1???? 100000000101 illegal? +?00000 ?1?10100 1???? 100000000101 illegal? +?00000 ?1?1??10 1???? 100000000101 illegal? +?00000 ?1??1100 1???? 100000000101 illegal? +?00000 ?1???101 1???? 100000000101 illegal? +?00000 ?1????11 1???? 100000000101 illegal? +?00000 ??101?10 1???? 100000000101 illegal? +?00000 ??11100? 1???? 100000000101 illegal? +?00000 11001001 ????? 100000000101 LEAVE/illegal? +?00000 11001110 ????? 100000000101 INTO/illegal? + +010000 0000???? ?00?1 100111010001 +010000 0000???? ?01?1 000110010101 +010000 0000???? ?10?1 000001010101 +010000 0000???? ?11?1 000111010101 +010000 0000???? ???00 100111010001 +010000 0000???? ???10 000110010001 +101000 0000???? ?00?1 100000010001 +101000 0000???? ?01?1 100110010101 +101000 0000???? ?10?1 100001010101 +101000 0000???? ?11?1 100111010101 +101000 0000???? ???00 100000010001 +101000 0000???? ???10 100110010001 +110000 0000???? ?00?1 110111010001 +110000 0000???? ?01?1 010110010101 +110000 0000???? ?10?1 010001010101 +110000 0000???? ?11?1 010111010101 +110000 0000???? ???00 110111010001 +110000 0000???? ???10 010110010001 +101000 0001???? ?00?1 100000110001 +101000 0001???? ?01?1 100110110101 +101000 0001???? ?10?1 100001110101 +101000 0001???? ?11?1 100111110101 +101000 0001???? ???00 100000110001 +101000 0001???? ???10 100110110001 +101000 0010???? ?00?1 100000110001 +101000 0010???? ?01?1 100110110101 +101000 0010???? ?10?1 100001110101 +101000 0010???? ?11?1 100111110101 +101000 0010???? ???00 100000110001 +101000 0010???? ???10 100110110001 +?10000 0010???? ?00?1 100000010001 +?10000 0010???? ?01?1 100110010101 +?10000 0010???? ?10?1 100001010101 +?10000 0010???? ?11?1 100111010101 +?10000 0010???? ???00 100000010001 +?10000 0010???? ???10 100110010001 +101000 0011???? ?00?1 100000010001 +101000 0011???? ?01?1 100110010101 +101000 0011???? ?10?1 100001010101 +101000 0011???? ?11?1 100111010101 +101000 0011???? ???00 100000010001 +101000 0011???? ???10 100110010001 +?10000 00?1???? ?00?1 100000010001 +?10000 00?1???? ?01?1 100110010101 +?10000 00?1???? ?10?1 100001010101 +?10000 00?1???? ?11?1 100111010101 +?10000 00?1???? ???00 100000010001 +?10000 00?1???? ???10 100110010001 +001000 00?????? ?00?1 100000010001 +001100 00?????? ?00?1 100000001001 +011000 00?????? ?00?1 100000001001 +011100 00?????? ?00?1 000111011001 +101100 00?????? ?00?1 100111011001 +111100 00?????? ?00?1 110111011001 +001000 00?????? ?01?1 100110010101 +001100 00?????? ?01?1 100110001101 +011000 00?????? ?01?1 100110001101 +011100 00?????? ?01?1 110110011101 +101100 00?????? ?01?1 000110011101 +111100 00?????? ?01?1 010110011101 +001000 00?????? ?10?1 100001010101 +001100 00?????? ?10?1 100001001101 +011000 00?????? ?10?1 100001001101 +011100 00?????? ?10?1 110001011101 +101100 00?????? ?10?1 000001011101 +111100 00?????? ?10?1 010001011101 +001000 00?????? ?11?1 100111010101 +001100 00?????? ?11?1 100111001101 +011000 00?????? ?11?1 100111001101 +011100 00?????? ?11?1 110111011101 +101100 00?????? ?11?1 000111011101 +111100 00?????? ?11?1 010111011101 +001000 00?????? ???00 100000010001 +001100 00?????? ???00 100000001001 +011000 00?????? ???00 100000001001 +011100 00?????? ???00 000111011001 +101100 00?????? ???00 100111011001 +111100 00?????? ???00 110111011001 +001000 00?????? ???10 100110010001 +001100 00?????? ???10 100110001001 +011000 00?????? ???10 100110001001 +011100 00?????? ???10 110110011001 +101100 00?????? ???10 000110011001 +111100 00?????? ???10 010110011001 +010000 0100???? ?0??? 000010010001 +010000 0100???? ?1??0 000010010001 +010000 0100???? ?1??1 000101010101 +101000 0100???? ?0??? 100010010001 +101000 0100???? ?1??0 100010010001 +101000 0100???? ?1??1 100101010101 +110000 0100???? ?0??? 010010010001 +110000 0100???? ?1??0 010010010001 +110000 0100???? ?1??1 010101010101 +101000 0101???? ?0??? 100010110001 +101000 0101???? ?1??0 100010110001 +101000 0101???? ?1??1 100101110101 +101000 0110???? ?0??? 100010110001 +101000 0110???? ?1??0 100010110001 +101000 0110???? ?1??1 100101110101 +?10000 0110???? ?0??? 100010010001 +?10000 0110???? ?1??0 100010010001 +?10000 0110???? ?1??1 100101010101 +101000 0111???? ?0??? 100010010001 +101000 0111???? ?1??0 100010010001 +101000 0111???? ?1??1 100101010101 +?10000 01?1???? ?0??? 100010010001 +?10000 01?1???? ?1??0 100010010001 +?10000 01?1???? ?1??1 100101010101 +001000 01?????? ?0??? 100010010001 +001000 01?????? ?1??0 100010010001 +001000 01?????? ?1??1 100101010101 +001100 01?????? ?0??? 100010001001 +001100 01?????? ?1??0 100010001001 +001100 01?????? ?1??1 100101001101 +011000 01?????? ?0??? 100010001001 +011000 01?????? ?1??0 100010001001 +011000 01?????? ?1??1 100101001101 +011100 01?????? ?0??? 110010011001 +011100 01?????? ?1??0 110010011001 +011100 01?????? ?1??1 110101011101 +101100 01?????? ?0??? 000010011001 +101100 01?????? ?1??0 000010011001 +101100 01?????? ?1??1 000101011101 +111100 01?????? ?0??? 010010011001 +111100 01?????? ?1??0 010010011001 +111100 01?????? ?1??1 010101011101 +010000 1000???? ?0??? 000110010001 +010000 1000???? ?1??0 000110010001 +010000 1000???? ?1??1 000011010101 +101000 1000???? ?0??? 100110010001 +101000 1000???? ?1??0 100110010001 +101000 1000???? ?1??1 100011010101 +110000 1000???? ?0??? 010110010001 +110000 1000???? ?1??0 010110010001 +110000 1000???? ?1??1 010011010101 +101000 1001???? ?0??? 100110110001 +101000 1001???? ?1??0 100110110001 +101000 1001???? ?1??1 100011110101 +101000 1010???? ?0??? 100110110001 +101000 1010???? ?1??0 100110110001 +101000 1010???? ?1??1 100011110101 +?10000 1010???? ?0??? 100110010001 +?10000 1010???? ?1??0 100110010001 +?10000 1010???? ?1??1 100011010101 +101000 1011???? ?0??? 100110010001 +101000 1011???? ?1??0 100110010001 +101000 1011???? ?1??1 100011010101 +?10000 10?1???? ?0??? 100110010001 +?10000 10?1???? ?1??0 100110010001 +?10000 10?1???? ?1??1 100011010101 +001000 10?????? ?0??? 100110010001 +001000 10?????? ?1??0 100110010001 +001000 10?????? ?1??1 100011010101 +001100 10?????? ?0??? 100110001001 +001100 10?????? ?1??0 100110001001 +001100 10?????? ?1??1 100011001101 +011000 10?????? ?0??? 100110001001 +011000 10?????? ?1??0 100110001001 +011000 10?????? ?1??1 100011001101 +011100 10?????? ?0??? 110110011001 +011100 10?????? ?1??0 110110011001 +011100 10?????? ?1??1 110011011101 +101100 10?????? ?0??? 000110011001 +101100 10?????? ?1??0 000110011001 +101100 10?????? ?1??1 000011011101 +111100 10?????? ?0??? 010110011001 +111100 10?????? ?1??0 010110011001 +111100 10?????? ?1??1 010011011101 +010000 1100???? ????? 100111010001 +101000 1100???? ????? 100000010001 +110000 1100???? ????? 110111010001 +101000 1101???? ????? 100000110001 +101000 1110???? ????? 100000110001 +?10000 1110???? ????? 100000010001 +101000 1111???? ????? 100000010001 +?10000 11?1???? ????? 100000010001 +001000 11?????? ????? 100000010001 +001100 11?????? ????? 100000001001 +011000 11?????? ????? 100000001001 +011100 11?????? ????? 000111011001 +101100 11?????? ????? 100111011001 +111100 11?????? ????? 110111011001 +000001 ???????? ??0?? 100000000000 +000001 ???????? ??1?? 100110000000 +000010 ???????? ????? 100000000100 +000011 ???????? ????? 100110000000 +000101 ???????? ????? 100010000000 +001001 ???????? ????? 100000000100 +001101 ???????? ????? 100000001001 +001111 ???????? ????? 100010000100 +00?110 ???????? ????? 100000000100 +010001 ???????? ??0?? 000111000000 +010001 ???????? ??1?? 110110000000 +010011 ???????? ????? 110110000000 +010101 ???????? ????? 110010000000 +010?10 ???????? ????? 000111000100 +011011 ???????? ????? 100000000100 +011111 ???????? ????? 001111000100 +011?01 ???????? ????? 100000000100 +011?10 ???????? ????? 100000000100 +100001 ???????? ??0?? 100111000000 +100001 ???????? ??1?? 000110000000 +100011 ???????? ????? 000110000000 +100101 ???????? ????? 000010000000 +100?10 ???????? ????? 100111000100 +10111? ???????? ????? 100000000100 +110001 ???????? ??0?? 110111000000 +110001 ???????? ??1?? 010110000000 +110011 ???????? ????? 010110000000 +110101 ???????? ????? 010010000000 +110?10 ???????? ????? 110111000100 +111000 ???????? ????? 100000000100 +111?1? ???????? ????? 100000000100 +1?1?01 ???????? ????? 100000000100 +?01010 ???????? ????? 100000000100 +?01011 ???????? ????? 111000000100 +??0100 ???????? ????? 100000000100 +??0111 ???????? ????? 100000000100 + diff --git a/80386/small_pla.txt b/80386/small_pla.txt new file mode 100644 index 0000000..d0bd524 --- /dev/null +++ b/80386/small_pla.txt @@ -0,0 +1,139 @@ +abcdefg +0101001 0011011 100000000001 801 OVERLONG_INST +11010?1 0011011 100000101101 82d HARDWARE_IRQ +?0010?1 0011011 100000110110 836 NMI +??011?1 0011011 100101010011 953 ICE_PIN +??11??1 0011011 100101000001 941 BREAKPOINT + +???0??1 0011011 100100111111 93f SINGLE_STEP Trap flag +??????* 0011010 100000100100 824 DIVIDE_ERROR +??????? 1011010 100011101001 8e9 PAGE_FAULT +??????? 0010110 100001010111 857 GENERAL_FAULT5 +??????? 0100010 100000111111 83f DOUBLE_FAULT +?????1? 0000000 100000111001 839 TRIPLE_FAULT + +abcdef h i +010100 0 0 0011011 100000000001 801 OVERLONG_INST +11010? 0 0 0011011 100000101101 82d HARDWARE_IRQ +?0010? 0 0 0011011 100000110110 836 NMI +??011? 0 0 0011011 100101010011 953 ICE_PIN +??11?? 0 0 0011011 100101000001 941 BREAKPOINT + +???0?? 0 0 0011011 100100111111 93f SINGLE_STEP Trap flag +?????? 1 0 0011010 100000100100 824 DIVIDE_ERROR +?????? 0 1 1011010 100011101001 8e9 PAGE_FAULT +?????? 0 ? 0010110 100001010111 857 GENERAL_FAULT5 +?????? 0 ? 0100010 100000111111 83f DOUBLE_FAULT +?????1 0 ? 0000000 100000111001 839 TRIPLE_FAULT + +abcdef hj k +010100 01 ? 0011011 100000000001 801 OVERLONG_INST +11010? 01 ? 0011011 100000101101 82d HARDWARE_IRQ +?0010? 01 ? 0011011 100000110110 836 NMI +??011? 01 ? 0011011 100101010011 953 ICE_PIN Enter ICE mode via ICE# pin like SMI# pin? +??11?? 01 ? 0011011 100101000001 941 BREAKPOINT Like BREAKPOINT_SIGNAL but without BS - comes in via small pla when DR0-DR3 are hit? + +???0?? 01 ? 0011011 100100111111 93f SINGLE_STEP Trap flag +?????? 11 ? 0011010 100000100100 824 DIVIDE_ERROR +?????? 00 0 1011010 100011101001 8e9 PAGE_FAULT +?????? 00 ? 0010110 100001010111 857 GENERAL_FAULT5 +?????? 00 1 0100010 100000111111 83f DOUBLE_FAULT +?????1 00 ? 0000000 100000111001 839 TRIPLE_FAULT + + + +Missing - some handled by GENERAL_FAULT5 and some by OVERLONG_INST by process of elimination? (probably all by GENERAL_FAULT5 given priority) + Limit exceeded + Attempt to read unreadable segment + Attempt to write unwriteable segment + + + +7F9 DEF UV X | 801 {-4B-} 2 04 r PUSHFd 56 +7F7 C EF UV X | 803 {-4B-} 0 03 CLI/STI 52 +7FD AB D F UV X | 807 {-4B-} 0 37 r INT ib +7FF AB D F UV X | 809 {-4B-} 3 22 r IRETd 10 +7FB ABC UV X | 802 {-4B-} 3 05 r POPFd 7 + +27F ABC EF UV X | 283 {-4B-} 0 09 p INS +2A7 ABC EF UV X | 2AB {-4B-} 0 08 p OUTS 4 +272 ABCD UV X | 275 {-4B-} 0 06 p IN A,ib +29B ABCD UV X | 29E {-4B-} 0 04 p OUT ib,A 3 +279 ABCD F UV X | 27B {-4B-} 0 07 p IN A,DX +28A ABCD F UV X | 28C {-4B-} 0 11 p REP INS +2A1 ABCD F UV X | 2A3 {-4B-} 0 05 p OUT DX,A +2B1 ABCD F UV X | 2B3 {-4B-} 0 10 p REP OUTS 2 + + +7 unique operands at 13 sites leading to 11 targets + + + ba9876 012345 +10011011010010011011 100000 100000 801 OVERLONG_INST +01011011000010011011 100000 101101 82d HARDWARE_IRQ +00101011000010011011 100000 011011 836 NMI +00001010100010011011 100101 110010 953 ICE_PIN +00000110000010011011 100101 100000 941 BREAKPOINT + +00000000000010011011 100100 111111 93f SINGLE_STEP +00000000000110011010 100000 001001 824 DIVIDE_ERROR +00000000000001011010 100011 100101 8e9 INTERRUPT_X +00000000000000010110 100001 111010 857 GENERAL_FAULT5 +00000000000000100010 100000 111111 83f DOUBLE_FAULT +00000000001000000000 100000 100111 839 TRIPLE_FAULT + +L L R R ? ? R L R + _ _ _ _ _ _ _ _ _ _ _ +BB CC EE F DD A K G HH JJ II K G +10 01 10 1 10 1 0 0 10 01 10 1 1 100000 100000 801 OVERLONG_INST A ? lowest priority +01 01 10 1 10 0 0 0 10 01 10 1 1 100000 101101 82d HARDWARE_IRQ B L INTR is active high +00 10 10 1 10 0 0 0 10 01 10 1 1 100000 011011 836 NMI C L NMI is active high +00 00 10 1 01 0 0 0 10 01 10 1 1 100101 110010 953 ICE_PIN D R +00 00 01 1 00 0 0 0 10 01 10 1 1 100101 100000 941 BREAKPOINT E R + +00 00 00 0 00 0 0 0 10 01 10 1 1 100100 111111 93f SINGLE_STEP F ? +00 00 00 0 00 0 0 1 10 01 10 1 0 100000 001001 824 DIVIDE_ERROR G ? +00 00 00 0 00 0 0 0 01 01 10 1 0 100011 100101 8e9 PAGE_FAULT H R #PF +00 00 00 0 00 0 0 0 00 01 01 1 0 100001 111010 857 ACCESS_VIOLATI I R +00 00 00 0 00 0 0 0 00 10 00 1 0 100000 111111 83f DOUBLE_FAULT J L #DF +00 00 00 0 00 0 1 0 00 00 00 0 0 100000 100111 839 TRIPLE_FAULT K ? highest priority + +Column A would be all 0s so is omitted +Column F would be 00000100000 - perhaps is performed by putting the input directly into the row activation for some reason? +Columns K and G are split up from their complements, so we can't tell which one is L and which is R + + +Table 9-2 in i386.pdf: + +HIGHEST Faults except debug faults GHIJK + Trap instructions INTO, INT n, INT 3 + Debug traps for this instruction EF + Debug faults for next instruction EF + NMI interrupt C +LOWEST INTR interrupt B + +Table 7-2. Priority Among Concurrent Events + +1 (Highest) Hardware Reset and Machine Checks + - RESET n/a + - Machine Check (#MC) 1? TRIPLE FAULT +2 Trap on Task Switch + - T flag in TSS is set (#DB) not via small pla +3 External Hardware Interventions + - FLUSH n/a + - STOPCLK n/a + - SMI 8 ICE_PIN + - INIT n/a +4 Traps on the Previous Instruction + - Trap-class Debug Exceptions (#DB due to TF flag set or data/I-O breakpoint) 6 SINGLE_STEP 7 BREAKPOINT +5 Nonmaskable Interrupts (NMI) 1 9 NMI +6 Maskable Hardware Interrupts 1 10 HARDWARE_IRQ +7 Fault-class Debug Exceptions (#DB due to instruction breakpoint) +8 Faults from Fetching Next Instruction + - Code-Segment Limit Violation (#GP) 3? + - Code Page Fault (#PF) 4 +9 (Lowest) Faults from Decoding the Next Instruction + - Control protection exception due to missing ENDBRANCH at target of an indirect call or jump (#CP) n/a + - Instruction length > 15 bytes (#GP) 11 OVERLONG_INST + - Invalid Opcode (#UD) not via small pla + - Coprocessor Not Available (#NM) not via small pla diff --git a/80386/tests.txt b/80386/tests.txt new file mode 100644 index 0000000..15d0965 --- /dev/null +++ b/80386/tests.txt @@ -0,0 +1,541 @@ +<00> = TST_SEL_NONSS +MOV ES/DS/FS/GS,rmw POP ES/DS/FS/GS {-6E-} +????1?????000000 000001001001101010 592 Y NULL_SELECTOR e +????0?????000000 010000000000000000 000 n !e + +<01> = TST_SEL_CS +JMP_FAR_PM CALLGATE* CALL_FAR_PM TASK_FINAL_PM INTGATE*/TRAPGATE* {-6E-} +????0?????000001 010000000000000000 000 n !e +????1?????000001 000010111010000111 85d y #GP/#TS(I0,E0) e + +<02> = TST_SEL_RET +RETF_HELPER {-6E-} +01??0?????000010 010000000000000000 000 n Bit l is 1 if the privilege check passed SAME-LEVEL RPL == CPL ? +11??0?????000010 000000000000000000 000 n SAME-LEVEL RPL == CPL ? +00??0?????000010 010001100001011010 686 Y RETF_OUTER_LEV OUTER-PRIVILEGE-LEVEL RPL > CPL +10??0?????000010 000010111010000111 85d y #GP/#TS(I0,E0) RPL < CPL ? +????1?????000010 000010111010000111 85d y #GP/#TS(I0,E0) RPL < CPL ? + +<03> = TST_SEL_RET_OL +<02> {-6A-} +?1??0?????000011 000000000000000000 000 n +?0??0?????000011 000010111010000111 85d y #GP/#TS(I0,E0) selector RPL != CPL (?) +????1?????000011 000010111010000111 85d y #GP/#TS(I0,E0) null selector + +<04> = TST_PORTIO_BIT +PORTIO_PROTCHK* {-6A-} +?1??1?????000100 000000000000000000 000 n +?0??1?????000100 000011011010000111 85b y #GP(0) some kind of privilege level check? +????0?????000100 000011011010000111 85b y #GP(0) non-null (but does this test the lowest two bits?) + +<05> = TST_SEL_ARPL +ARPL {-6A-} +10????????000101 001000000000000000 000 n Bit m is 1 if b==0 +11????????000101 000000000000000000 000 n +0?????????000101 000011001101011010 6b3 Y ARPL_FAILED + +<06> = TST_SEL_GDT +IRETd_V86 LTR {-6A-} +????1?????000110 000010111010000111 85d y #GP/#TS(I0,E0) null selector +????0??1??000110 000010111010000111 85d y #GP/#TS(I0,E0) selector points to LDT +????0??0??000110 000000000000000000 000 n + +<07> = TST_SEL_LLDT +LLDT {-6A-} +????1??0??000111 000010111011011010 6dd Y LLDT_TEST_PASS null selector +????0??1??000111 000010111010000111 85d y #GP/#TS(I0,E0) selector points to LDT +????1??1??000111 000010111011011111 edd n == LLDT_TEST_PASS | #GP/#TS(I0,E0) null selector, selector points to LDT? (logicially impossible since "null selector" implies TI == 0) +????0??0??000111 000000000000000000 000 n + +<08> = TST_SEL_LLVV +LAR_LSL_VERRW {-6A-} +????1?????001000 000001110110000110 86e y LAR_LSL_VERRW_NULL_SELECTOR null selector +????0?????001000 010000000000000000 000 n + +<09> = TST_SEL_MOREPR +<17> IRETd_HELPER5 {-6A-} +?1??0?????001001 000000000000000000 000 n +?0??0?????001001 000010111010000111 85d y #GP/#TS(I0,E0) +????1?????001001 000010111010000111 85d y #GP/#TS(I0,E0) null selector + +<0A> = TST_SEL_TASKGT +<22><13><16><21> {-6A-} +????0??0??001010 010000000000000000 000 n +????0??1??001010 000010111010000111 85d y #GP/#TS(I0,E0) selector points to LDT +????1?????001010 000010111010000111 85d y #GP/#TS(I0,E0) null selector + +<0B> = TST_SEL_TASKFI +IRETd_HELPER5 {-6A-} +????0?????001011 010000000000000000 000 n +????1?????001011 000010100111111010 7e5 Y NULL_SELECTOR2 RETURNs null selector + +<0C> = TST_SEL_SS +MOV SS,rmw PM_LD_SS PM_LSS {-6E-} +?1??0?????001100 010000000000000000 000 n +?0??0?????001100 010010111010000111 85d y #GP/#TS(I0,E0) +????1?????001100 000010111010000111 85d y #GP/#TS(I0,E0) + +<0D> = TST_SEL_TR_TSF +IRETd_HELPER5 {-6A-} +????0??0??001101 000000000000000000 000 n +????1??0??001101 000010100111111010 7e5 Y NULL_SELECTOR2 RETURNs null selector +????0??1??001101 000010111010000111 85d y #GP/#TS(I0,E0) selector points to LDT +????1??1??001101 000010111111111111 ffd n == NULL_SELECTOR2 | #GP/#TS(I0,E0) null selector, selector points to LDT (logicially impossible since "null selector" implies TI == 0) + +unused +??????????001110 000000000000000000 000 n + +unused +??????????001111 000000000000000000 000 n + +<10> = TST_DES_SIMPLE +MOV ES/DS/FS/GS,rmw {-61-} POP ES/DS/FS/GS {-61-} MOV ES/DS/FS/GS,rmw {-61-} PM_LES {-61-} PM_LDS {-61-} PM_LFS_LGS {-61-} LSSFSGS_HELPER {-68-} LOAD_SEGR_HELP {-68-} <02> {-68-} IRETd_HELPER5 {-61-} +The presence of RETURN suggests that {-61-} is a CALL (P1CALL) - or is it returning from a CALL that happens afterwards? +?????0????010000 000000000000000000 000 n system segment - #GP(selector) +?????11?0?010000 000000000000000000 000 n non-readable code segment - #GP(selector) +1????10???010000 000000000000000000 000 n data segment AND ((RPL > DPL) or (CPL > DPL)) - #GP(selector) +1????1101?010000 000000000000000000 000 n non-conforming code segment AND ((RPL > DPL) or (CPL > DPL)) - #GP(selector) +0???010???010000 000000001110000111 870 y #NP(I0,E0) data segment a=0 segment not marked present - #NP(selector) +0???01101?010000 000000001110000111 870 y #NP(I0,E0) non-conforming code segment a=0 segment not marked present - #NP(selector) +????01111?010000 000000001110000111 870 y #NP(I0,E0) conforming code segment segment not marked present - #NP(selector) +0???110???010000 000110101011101010 5d5 Y PROT_TESTS_PASSED data segment a=0 segment marked present RETURNs +0???11101?010000 000110101011101010 5d5 Y PROT_TESTS_PASSED non-conforming code segment a=0 segment marked present RETURNs +????11111?010000 000110101011101010 5d5 Y PROT_TESTS_PASSED conforming code segment segment marked present RETURNs + +----------- e = Present bit (15) + +IF DS, ES, FS, or GS is loaded with non-NULL selector https://www.felixcloutier.com/x86/mov +THEN + IF segment selector index is outside descriptor table limits + OR segment is not a data or readable code segment + OR ((segment is a data or nonconforming code segment) AND ((RPL > DPL) or (CPL > DPL))) + THEN #GP(selector); FI; 000 + IF segment not marked present + THEN #NP(selector); 870 SEGMENT_NOT_P1 + ELSE + SegmentRegister := segment selector; 5d5 PROT_TESTS_PASSED + SegmentRegister := segment descriptor; FI; +FI; + +<11> = TST_DES_SS +MOV SS,rmw POP SS PM_LSS IRETd_HELPER5 {-67-} +The presence of RETURN suggests that {-67-} is a CALL (P7CALL) - or is it returning from a CALL that happens afterwards? +?????0????010001 000000000000000000 000 n system segment - #GP(selector) +?????11???010001 000000000000000000 000 n code segment - #GP(selector) +?????10?0?010001 000000000000000000 000 n not writeable - #GP(selector) +1????10?1?010001 000000000000000000 000 n ((RPL > DPL) or (CPL > DPL)) - #GP(selector) +00???10?1?010001 000000000000000000 000 n RPL != CPL - #GP(selector) ? i386.pdf also says "DPL in the AR byte must equal CPL else #GP(selector);" https://www.felixcloutier.com/x86/mov does not say this +01??010?1?010001 000001010110000111 86a Y #SS(I0,E0) segment not present - #SS(selector) +01??110?1?010001 100110101011101010 5d5 Y PROT_TESTS_PASSED RETURNs + | +----------- e = Present bit (15) + +-------------- b = RPL == CPL ( or: RPL == CPL && DPL == CPL ? ) + +IF SS is loaded + THEN + IF segment selector is NULL + THEN #GP(0); FI; + IF segment selector index is outside descriptor table limits + OR segment selector's RPL =? CPL + OR segment is not a writable data segment + OR DPL =? CPL + THEN #GP(selector); FI; 000 + IF segment not marked present + THEN #SS(selector); 86a #SS(I0,E0) + ELSE + SS := segment selector; 5d5 PROT_TESTS_PASSED RETURNs + SS := segment descriptor; FI; +FI; + +<12> = TST_DES_JMP +JMP_FAR_PM {-67-} +?????0????010010 000011001101101010 5b3 Y JUMP_FAR_PM_GATE system segment +?????10???010010 000000000000000000 000 n data segments +1????110??010010 000000000000000000 000 n priv check failed +00???110??010010 000000000000000000 000 n priv check failed +011??110??010010 000000000000000000 000 n priv check failed +010?0110??010010 000000001110000111 870 y #NP(I0,E0) non-conforming code segment - not present +0???0111??010010 000000001110000111 870 y #NP(I0,E0) conforming code segment - not present +010?1110??010010 000110101011101010 5d5 Y PROT_TESTS_PASSED non-conforming code segment RETURNs +0???1111??010010 000110101011101010 5d5 Y PROT_TESTS_PASSED conforming code segment RETURNs +1????111??010010 000000000000000000 000 n conforming code segment - priv check failed? + +<13> = TST_DES_JGATE +JUMP_FAR_PM_GATE {-69-} +0????0?000010011 000000000000000000 000 n 0/8 Invalid +0????00010010011 000000000000000000 000 n 2 LDT +0????0?011010011 000000000000000000 000 n 3/B Busy 80286/80386 TSS +0????0?11?010011 000000000000000000 000 n 6/7/E/F 80286/80386 trap/interrupt gate +0????01010010011 000000000000000000 000 n A Invalid +0????01101010011 000000000000000000 000 n D Invalid +0????1????010011 000000000000000000 000 n needs to be system segment +1?????????010011 000000000000000000 000 n priv check failed +0???100100010011 000010111101101010 5bd Y CALLGATE286 4 80286 call gate +0???101100010011 000001111101101010 5be y CALLGATE386 C 80386 call gate +0???100101010011 000000111000111010 71c y TASKGATE 5 80286/80386 task gate +0???10?001010011 000011000010111010 743 Y AVAIL_TSS_PR 1/9 Available 80286/80386 TSS +0???00?001010011 000000010111111011 7e8 Y AVAIL_TSS_NP 1/9 Available 80286/80386 TSS +0???00?100010011 000000001110000111 870 y #NP(I0,E0) 4/C 80286/80386 call gate +0???000101010011 000000001110000111 870 y #NP(I0,E0) 5 80286/80386 task gate + +<14> = TST_DES_JGDEST +<12> IRETd_HELPER5 {-67-} +?????0????010100 000000000000000000 000 n system segment +?????10???010100 000000000000000000 000 n data segment +1????11???010100 000000000000000000 000 n priv check failed? +00???110??010100 000000000000000000 000 n priv check failed +01??0110??010100 000000001110000111 870 y #NP(I0,E0) not conforming, not present +0???0111??010100 000000001110000111 870 y #NP(I0,E0) conforming, not present +01??1110??010100 000101011011101010 5da Y PROT_TESTS_PASSED2 not conforming RETURNs +0???1111??010100 000101011011101010 5da Y PROT_TESTS_PASSED2 conforming RETURNs + +<15> = TST_DES_CALL +CALL_FAR_HELP {-67-} +?????0????010101 000000011101101010 5b8 Y CALL_FAR_PM_GATE system segment +?????10???010101 000000000000000000 000 n data segment +1????11???010101 000000000000000000 000 n priv check failed? +00???110??010101 000000000000000000 000 n non-conforming code segment priv check failed? +011??110??010101 000000000000000000 000 n non-conforming code segment priv check failed? +010?0110??010101 000000001110000111 870 y #NP(I0,E0) non-conforming, absent +0???0111??010101 000000001110000111 870 y #NP(I0,E0) conforming, absent +010?1110??010101 000110101011101010 5d5 Y PROT_TESTS_PASSED non-conforming RETURNs +0???1111??010101 000110101011101010 5d5 Y PROT_TESTS_PASSED conforming RETURNs + +<16> = TST_DES_CGATE +<15> {-69-} +?????1????010110 000000000000000000 000 n only system segments allowed +1????0????010110 000000000000000000 000 n priv check failed +0????0?000010110 000000000000000000 000 n 0/8 Invalid +0????00010010110 000000000000000000 000 n 2 LDT +0????0?11?010110 000000000000000000 000 n 6/7/E/F 80286/80386 trap/interrupt gate +0????0?011010110 000000000000000000 000 n 3/B Busy 80286 TSS +0????01010010110 000000000000000000 000 n A Invalid +0????01101010110 000000000000000000 000 n D Invalid +0???100100010110 000010111101101010 5bd Y CALLGATE286 4 80286 call gate +0???101100010110 000001111101101010 5be y CALLGATE386 C 80386 call gate +0???100101010110 000000111000111010 71c y TASKGATE 5 80286/80386 task gate +0???10?001010110 000011000010111010 743 Y AVAIL_TSS_PR 1/9 Available 80286/80386 TSS present +0???00?001010110 000000010111111011 7e8 Y AVAIL_TSS_NP 1/9 Available 80286/80386 TSS not present +0???00?100010110 000000001110000111 870 y #NP(I0,E0) 4/C 80286/80386 call gate not present +0???000101010110 000000001110000111 870 y #NP(I0,E0) 5 80286/80386 task gate not present + +<17> = TST_DES_CGDEST +<15> INT_HELPER {-67-} +?????0????010111 000000000000000000 000 n system segment +?????10???010111 000000000000000000 000 n data segment +1????11???010111 000000000000000000 000 n priv check failed? +0???011???010111 000000001110000111 870 y #NP(I0,E0) absent +01??1110??010111 000101011011101010 5da Y PROT_TESTS_PASSED2 non-conforming, passed check RETURNs +0???1111??010111 000101011011101010 5da Y PROT_TESTS_PASSED2 conforming, no check needed RETURNs +00??1110??010111 110111011111101010 5fb Y MORE_PRIVILEGE non-conforming, check failed? + +<18> = TST_DES_RETF +RETF_PM {-63-} +?????0????011000 000000000000000000 000 n system segment +?????10???011000 000000000000000000 000 n data segment +1????11???011000 000000000000000000 000 n priv check failed? +00???110??011000 000000000000000000 000 n non-conforming priv check failed? +00??0111??011000 000000001110000111 870 y #NP(I0,E0) absent conforming +01??011???011000 000000001110000111 870 y #NP(I0,E0) absent non-conforming but priv check passed? +00??1111??011000 000110101011101010 5d5 Y PROT_TESTS_PASSED present conforming RETURNs +01??111???011000 000110101011101010 5d5 Y PROT_TESTS_PASSED present non-conforming but priv check passed? RETURNs + +<19> = TST_DES_RTOLSS +RETF_OUTER_LEV {-63-} +?????0????011001 000000000000000000 000 n system segment +?????11???011001 000000000000000000 000 n code segment +1????10???011001 000000000000000000 000 n priv check failed? +00???10???011001 000000000000000000 000 n priv check failed? +01???10?0?011001 000000000000000000 000 n data segment not writeable? +01??010?1?011001 000001010110000111 86a Y #SS(I0,E0) not present +01??110?1?011001 000110101011101010 5d5 Y PROT_TESTS_PASSED RETURNs + +<1A> = TST_DES_LDTTSK +IRETd_HELPER5 {-61-} +????000010011010 000010111010000111 85d y #GP/#TS(I0,E0) LDT absent +????100010011010 000010101011101010 5d5 Y PROT_TESTS_PASSED RETURNs LDT present +?????0000?011010 000000000000000000 000 n 0-1 +?????00011011010 000000000000000000 000 n 3 +?????001??011010 000000000000000000 000 n 4-7 +?????01???011010 000000000000000000 000 n 8-f +?????1????011010 000000000000000000 000 n user segment + +<1B> = TST_DES_LDT same as TST_LDT1 except for destination when LDT is absent +LLDT IRETd_HELPER5 {-61-} +????000010011011 000000001110000111 870 y #NP(I0,E0) LDT absent +????100010011011 000010101011101010 5d5 Y PROT_TESTS_PASSED RETURNs LDT present +?????0000?011011 000000000000000000 000 n system segment 0-1 +?????00011011011 000000000000000000 000 n system segment 3 +?????001??011011 000000000000000000 000 n system segment 4-7 +?????01???011011 000000000000000000 000 n system segment 8-f +?????1????011011 000000000000000000 000 n user segment + +<1C> = TST_DES_MOREPR +<17> {-63-} +01??010?1?011100 000001010110000111 86a Y #SS(I0,E0) +01??110?1?011100 000101011011101010 5da Y PROT_TESTS_PASSED2 RETURNs +?????0????011100 000000000000000000 000 n system segment +?????11???011100 000000000000000000 000 n code segement +?????10?0?011100 000000000000000000 000 n not writeable +1????10?1?011100 000000000000000000 000 n unpriv? +00???10?1?011100 000000000000000000 000 n unpriv? + +<1D> = TST_DES_TSSTSG +<13><16><21><22> {-61-} +?????0?000011101 000000000000000000 000 n 0, 8 +????00?001011101 000000001110000111 870 y #NP(I0,E0) 1, 9 Available 80286/80386 TSS absent +????10?001011101 000011111000111010 71f Y AVAIL_TSS 1, 9 Available 80286/80386 TSS present +?????0?01?011101 000000000000000000 000 n 2-3, a-b +?????0?1??011101 000000000000000000 000 n 4-7, c-f +?????1????011101 000000000000000000 000 n user segment + +<1E> = TST_DES_TSSTSR +IRETd_V86 {-61-} +?????0?00?011110 000000000000000000 000 n 0-1, 8-9 +?????0?010011110 000000000000000000 000 n 2/a +????00?011011110 000000001110000111 870 y #NP(I0,E0) 3/b Busy 80286/80386 TSS absent +????10?011011110 000011001011101010 5d3 Y PRESENT_TSS RETURNs 3/b Busy 80286/80386 TSS present +?????0?1??011110 000000000000000000 000 n 4-7, c-f +?????1????011110 000000000000000000 000 n user segment + +<1F> = TST_DES_TSSLTR +LTR {-61-} +????00?001011111 000000001110000111 870 y #NP(I0,E0) 1/9 Available 80286/80386 TSS +????10?001011111 000011001011101010 5d3 Y PRESENT_TSS RETURNs 1/9 Available 80286/80386 TSS +?????1????011111 000000000000000000 000 n user segment +?????0?1??011111 000000000000000000 000 n 4-7, c-f +?????0?01?011111 000000000000000000 000 n 2-3, a-b +?????0?000011111 000000000000000000 000 n 0/8 + +<20> = TST_DES_GRANUL +LSL_HELPER - always jumps {-6F-} +????1?????100000 000010101111011010 6f5 y LSL_GRANULARITY_COARSE +????0?????100000 000010111111011010 6fd y LSL_GRANULARITY_FINE + +----------- e = 23 G = If clear, the limit is in units of bytes, with a maximum of 2^20 bytes. If set, the limit is in units of 4096-byte pages, for a maximum of 2^32 bytes. + +<21> = TST_DES_INT_SW +INT_HELPER {-6F-} used for CALL_FAR_PM_GATE and INTERRUPT_X (hardware IRQ, NMI, faults) +?????1????100001 000000000000000000 000 n user segment +1????0????100001 000000000000000000 000 n priv check failed +0????0?000100001 000000000000000000 000 n 0/8 Invalid +0????0?0?1100001 000000000000000000 000 n 1/3/9/B Available/Busy 80286/80386 TSS +0????00010100001 000000000000000000 000 n 2 LDT +0????0?100100001 000000000000000000 000 n 4/C 80286/80386 call gate +0????01010100001 000000000000000000 000 n A Invalid +0????01101100001 000000000000000000 000 n D Invalid +0???000101100001 000010001110000111 871 y #NP(I1,E0) 5 80286/80386 task gate +0???100101100001 000000111000111010 71c y TASKGATE 5 80286/80386 task gate +0???000110100001 000010001110000111 871 y #NP(I1,E0) 6 80286 interrupt gate +0???100110100001 000001000011000110 8c2 Y INTGATE286 6 80286 interrupt gate +0???000111100001 000010001110000111 871 y #NP(I1,E0) 7 80286 trap gate +0???100111100001 000011000011000110 8c3 y TRAPGATE286 7 80286 trap gate +0???001110100001 000010001110000111 871 y #NP(I1,E0) E 80386 interrupt gate +0???101110100001 000011010011000110 8cb Y INTGATE386 E 80386 interrupt gate +0???001111100001 000010001110000111 871 y #NP(I1,E0) F 80386 trap gate +0???101111100001 000000110011000110 8cc y TRAPGATE386 F 80386 trap gate + +<22> = TST_DES_INT_HW +INT_HELPER {-6F-} used for JMP_FAR_PM_GATE +?????1????100010 000000000000000000 000 n user segment +?????0?000100010 000000000000000000 000 n 0/8 Invalid +?????0?0?1100010 000000000000000000 000 n 1/3/9/B Available/Busy 80286/80386 TSS +?????00010100010 000000000000000000 000 n 2 LDT +?????0?100100010 000000000000000000 000 n 4/C 80286/80386 call gate +?????01010100010 000000000000000000 000 n A Invalid +?????01101100010 000000000000000000 000 n D Invalid +????000101100010 000010001110000111 871 y #NP(I1,E0) 5 80286/80386 task gate +????100101100010 000000111000111010 71c y TASKGATE 5 80286/80386 task gate +????000110100010 000010001110000111 871 y #NP(I1,E0) 6 80286 interrupt gate +????100110100010 000001000011000110 8c2 Y INTGATE286 6 80286 interrupt gate +????000111100010 000010001110000111 871 y #NP(I1,E0) 7 80286 trap gate +????100111100010 000011000011000110 8c3 y TRAPGATE286 7 80286 trap gate +????001110100010 000010001110000111 871 y #NP(I1,E0) E 80386 interrupt gate +????101110100010 000011010011000110 8cb Y INTGATE386 E 80386 interrupt gate +????001111100010 000010001110000111 871 y #NP(I1,E0) F 80386 trap gate +????101111100010 000000110011000110 8cc y TRAPGATE386 F 80386 trap gate + +unused +??????????100011 000000000000000000 000 n + +<24> = TST_ACCESS_VIO This comes from the small PLA. +ACCESS_VIOLATI {-6B-} +?????00000100100 000011011010000110 85b y #GP(0) 0 DES_ES +?????00001100100 000011011010000110 85b y #GP(0) 1 DES_CS +?????00010100100 000001000110000110 862 Y #SS(0) 2 DES_SS +?????00011100100 000011011010000110 85b y #GP(0) 3 DES_DS +?????00100100100 000011011010000110 85b y #GP(0) 4 DES_FS +?????00101100100 000011011010000110 85b y #GP(0) 5 DES_GS +?????00110100100 000001111010000110 85e y #GP/#TS(SIGMA) 6 DESLDT +?????00111100100 000001111010000110 85e y #GP/#TS(SIGMA) 7 DESGDT +?????01000100100 000001100110000110 866 y #GP(SIGMA | 2) 8 DESIDT +?????01001100100 000001111010000110 85e y #GP/#TS(SIGMA) 9 DES_TR +?????0101?100100 000000000000000000 000 n 10-11 +?????011??100100 000000000000000000 000 n 12-15 +?????10???100100 000000000000000000 000 n 16-23 +?????11000100100 000011000110000110 863 y #SS(SIGMA) 24 DESCSW +?????11001100100 000011011010000110 85b y #GP(0) 25 DESCOD +?????11010100100 000001000110000110 862 Y #SS(0) 26 DESSTK +?????11011100100 000000000000000000 000 n 27 +?????111??100100 000000000000000000 000 n 28-31 + +<25> = TST_DES_RTOLOS +<02> RETF_HELPER_DS RETF_HELPER_FS RETF_HELPER_GS {-6F-} +0?????????100101 000000000000000000 000 n valid for outer level To be valid, the register setting must satisfy the following properties: +11????????100101 000000000000000000 000 n valid for outer level Selector index must be within descriptor table limits; +10????11??100101 000000000000000000 000 n valid for outer level Descriptor AR byte must indicate data or readable code segment; conforming code segment +10????0???100101 000000010101011010 6a8 Y ZERO_SLCTR_AR RETURNs not valid for outer level IF segment is data or non-conforming code, THEN data segment +10????10??100101 000000010101011010 6a8 Y ZERO_SLCTR_AR RETURNs not valid for outer level DPL must be ò CPL, or DPL must be ò RPL; non-conforming code segment + +<26> = TST_SEL_LES +PM_LES {-6E-} +????0?????100110 010000000000000000 000 n +????1?????100110 000001001001101010 592 Y NULL_SELECTOR RETURN + +<27> = TST_SEL_LDS +PM_LDS {-6E-} +????0?????100111 010000000000000000 000 n +????1?????100111 000001001001101010 592 Y NULL_SELECTOR RETURN + +<28> = TST_SEL_LFSLGS +PM_LFS_LGS {-6E-} +????0?????101000 010000000000000000 000 n +????1?????101000 000001001001101010 592 Y NULL_SELECTOR RETURN + +unused +??????????101001 000000000000000000 000 n + +<2A> = JMP_GFAULT_INT +INT_HELPER - unconditional jump to #GP(I1,E0) {-6B-} +??????????101010 000010100110000111 865 y #GP(I1,E0) + +<2B> = READ_RPL +PORTIO_PROTCHK* ARPL IRETd_HELPER4 - never jumps? {-6B-}/{-6A-}/{-6F-} +??????????101011 010000000000000000 000 n + +<2C> = WRITE_RPL +<17> - never jumps? {-6B-} output the privilege level in the low two bits of PROTUN? +??????????101100 001000000000000000 000 n + +<2D> = SET_RPL_TO_CPL +JUMP_FAR_PM CALL_FAR_PM TRAP_INT_GATE - never jumps? {-6B-} set CS.Selector.RPL = CPL? +??????????101101 101000000000000000 000 n + +<2E> = COPY_STACK_DPL +<17> IRETd_V86 <02> IRETd_HELPER5 EXCEPTION LOADALL386 DR_ICEBP_HELP2 - never jumps? {-6B-}/{-6F-} +??????????101110 100100000000000000 000 n + +<2F> = SET_FAULT +MOV CR0,rd <12> <15> LOAD_SEG_HELP2 CALL_FAR_HELP small pla 010100 01 ? 0011011 unused? - never jumps? {-6B-} Set a "fault" flag? +??????????101111 000000000000000001 000 n + +<30> = TST_DES_LAR +LAR LAR_LSL_VERRW* {-61-}/{-68-} +0????0?000110000 000000000000000000 000 n 0/8 Invalid +0????0?0?1110000 000001011000111010 71a Y LAR_VERRW_SUCCEEDED 1/9 Available 80286/80386 TSS 3/B Busy 80286/80386 TSS +0????00010110000 000001011000111010 71a Y LAR_VERRW_SUCCEEDED 2 LDT +0????0?100110000 000001011000111010 71a Y LAR_VERRW_SUCCEEDED 4/C 80286/80386 call gate +0????00101110000 000001011000111010 71a Y LAR_VERRW_SUCCEEDED 5 80286/80386 task gate +0????0?11?110000 000000000000000000 000 n 6/7/E/F 80286/80386 trap/interrupt gate i386.pdf says this is valid but https://www.felixcloutier.com/x86/lar agrees with microcode +0????01010110000 000000000000000000 000 n A Invalid +0????01101110000 000000000000000000 000 n D Invalid +0????1????110000 000001011000111010 71a Y LAR_VERRW_SUCCEEDED All code/data segments are valid with a=0 +1????0????110000 000000000000000000 000 n with a=1 system segements are not valid +1????10???110000 000000000000000000 000 n with a=1 data segments are not valid +1????110??110000 000000000000000000 000 n with a=1 non-conforming code segments are not valid +1????111??110000 000001011000111010 71a Y LAR_VERRW_SUCCEEDED with a=1 only code segments with conforming bit set are valid + +<31> = TST_DES_LSL +LSL {-61-} +0????0?000110001 000000000000000000 000 n 0/8 Invalid i386.pdf says 8 is valid but https://www.felixcloutier.com/x86/lsl agrees with microcode +0????0?0?1110001 000001110111011010 6ee Y LSL_HELPER 1/3/9/B Available/Busy 80286/80386 TSS +0????00010110001 000001110111011010 6ee Y LSL_HELPER 2 LDT +0????0?100110001 000000000000000000 000 n 4/C 80286 call gate +0????00101110001 000000000000000000 000 n 5 80286/80386 task gate +0????0?11?110001 000000000000000000 000 n 6/7/E/F 80286/80386 trap/interrupt gate +0????01010110001 000000000000000000 000 n A Invalid +0????01101110001 000000000000000000 000 n D Invalid +0????1????110001 000001110111011010 6ee Y LSL_HELPER All code/data segments are valid with a=0 +1????0????110001 000000000000000000 000 n with a=1 system segments are not valid +1????10???110001 000000000000000000 000 n with a=1 data segments are not valid +1????110??110001 000000000000000000 000 n with a=1 non-conforming code segments are not valid +1????111??110001 000001110111011010 6ee Y LSL_HELPER with a=1 only code segments with conforming bit set are valid + +<32> = TST_DES_VERR +VERR {-61-} +?????0????110010 000000000000000000 000 n system segments fail +?????11?0?110010 000000000000000000 000 n code segment, not readable +0????10???110010 000001011000111010 71a Y LAR_VERRW_SUCCEEDED data segments are always readable, DPL/CPL check ok +1????10???110010 000000000000000000 000 n data segments are always readable, DPL/CPL check failed +0????1101?110010 000001011000111010 71a Y LAR_VERRW_SUCCEEDED readable non-conforming code segment, DPL/CPL check ok +1????1101?110010 000000000000000000 000 n readable non-conforming code segment, DPL/CPL check failed +?????1111?110010 000001011000111010 71a Y LAR_VERRW_SUCCEEDED conforming code segment, readable + +<33> = TST_DES_VERW +VERW {-61-} +?????0????110011 000000000000000000 000 n system segments always fail +?????11???110011 000000000000000000 000 n code segments are never writeable +1????10???110011 000000000000000000 000 n CPL/DPL check failed +0????10?0?110011 000000000000000000 000 n data segment not writeable +0????10?1?110011 000001011000111010 71a Y LAR_VERRW_SUCCEEDED data segment writeable + +<34> = FPU_WAIT +WAIT {-6B-} +??????1?1?110100 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION MP && TS +??????0?1?110100 000000000000000000 000 n MP && !TS +????????0?110100 000000000000000000 000 n !MP + +unused +??????????110101 000000000000000000 000 n + +unused +??????????110110 000000000000000000 000 n + +unused +??????????110111 000000000000000000 000 n + +<38> = FPU_OTHER (FP instructions that don't do loads or stores, that do big stores, or that load single words +FENI/FDISI/FCLEX/FINIT/FSETPM/FRSTPM FSTSW AX/FNSTDW/FNSTSG FSTENV m FSAVE m FLDENV m FRSTOR m various fp instructions FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FILD mw FIST/FISTP mw {-6B-} +??????00??111000 000000000000000000 000 n !TS && !EM +??????01??111000 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION !TS && EM +??????1???111000 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION TS + +<39> = FPU_LOAD_3264 (FP instructions that load 32-bit or 64-bit quantities from RAM) +FADD/FMUL/FCOM/FCOMP/FSUB/FSUBR/FDIV/FDIVR/FIADD/FIMUL/FICOM/FICOMP/FISUB/FISUBR/FIDIV/FIDIVR/FLD/FILD md FLD/FILD/FADD/FMUL/FCOM/FCOMP/FSUBR/FSUB/FDIVR/FDIV mq - always jumps {-6B-} +?????000??111001 000000010111001010 4e8 y FPU_LD3264_287 !TS && !EM && !ET +?????100??111001 000000111000101010 51c Y FPU_LD3264_387 !TS && !EM && ET +??????01??111001 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION !TS && EM +??????1???111001 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION TS + +unused +??????????111010 000000000000000000 000 n + +<3B> = FPU_LOAD_80 (FP instructions that load 80-bit quantities from RAM) +FBLD/FLD mt - always jumps {-6B-} +?????000??111011 000011100111001010 4e7 Y FPU_LD80_287 !TS && !EM && !ET +?????100??111011 000001110111001010 4ee Y FPU_LD80_387 !TS && !EM && ET +??????01??111011 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION !TS && EM +??????1???111011 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION TS + +<3C> = FPU_STORE_3264 (FP instructions that store 32-bit or 64-bit quantities to RAM) +FST/FSTP/FIST/FISTP md FST/FSTP/FISTP mq - always jumps {-6B-} +?????000??111100 000001110010101010 54e y FPU_ST3264_287 !TS && !EM && !ET +?????100??111100 000010101010101010 555 y FPU_ST3264_387 !TS && !EM && ET +??????01??111100 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION !TS && EM +??????1???111100 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION TS + +<3D> = FPU_STORE_80 (FP instructions that store 80-bit quantities to RAM) +FBSTP/FSTP mt {-6B-} +?????000??111101 000010110010101010 54d Y FPU_ST80_287 !TS && !EM && !ET +?????100??111101 000000101010101010 554 Y FPU_ST80_387 !TS && !EM && ET +??????01??111101 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION !TS && EM +??????1???111101 000001101100101010 536 Y COPROCESSOR_NOT_AVAILABLE_EXCEPTION TS + +<3E> = FPU_FSAVE +FSAVE m FSAVE_HELPER {-6B-} +?????1????111110 000010010010001010 449 Y FSAVE_387 ET +?????0????111110 000010001010001010 451 Y FSAVE_287 !ET + +<3F> = FPU_FRSTOR +FRSTOR FRSTOR_HELPER {-6B-} +?????1????111111 000010101101001010 4b5 Y FRSTOR_387 ET +?????0????111111 000011011101001010 4bb Y FRSTOR_287 !ET + + diff --git a/README.md b/README.md index dbac06f..d2a87f2 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ Microcode resources for various x86 CPUs Microcode for the NEC V20 and V30 CPUs. -## /8087 +## /8087 -Microcode for the Intel 8087 FPU. \ No newline at end of file +Microcode for the Intel 8087 FPU. + +## /80386 + +Microcode for the Intel 80386 CPU.