1.简介
MIX是The Art of Computer Programming书中所用的汇编语言。
寄存器:有9个寄存器,A、X、J、I1、I2、I3、I4、I5、I6。I1~I6为变址寄存器。参见后面的图3。
MIX中一个字由5个字节和一位符号位组成。
MIX中的字符包括A-Z的大写字母,0-9的数字和部分特殊符号。
指令格式(这里是说机器指令):

|     0     |     1     |      2    |      3       |      4    |       5      |

|            地     址             |    index  |   mod   |     操作码  |

这是定长指令格式,所有指令都是6字节,其中第字节为符号,
0 1 2号字节共同组成地址。
我觉得不用太关心机器指令,不过书上说了很多。
在实例1中具体说明。
2.实例讲解
实例1,代码在第一卷1.3.2节140页,算法在1.2.10节93页。

代码:
X        EQU    1000
         ORIG    3000

START     STJ    EXIT
INIT    ENT3    0,1
        JMP    CHANGEM
LOOP    CMPA    X,3
        JGE    *+3
CHANGEM   ENT2    0,3
   LDA    X,3
   DEC3    1
   J3P    LOOP
EXIT   JMP    *
   END    START
第一个例子,我尽量说详细。这是一个求最大值的例子,求数组x[1]...x[n]的最大值m,储存到寄存器A
先说初始化,书上省略了的,寄存器I1为数组长度n。寄存器I3用于存k,寄存器I2存j。
n是提前给了初值的,k和j是运行的时候再初始化的。
ORIG    3000
表示程序是从3000的地址开始运行的,
X        EQU    1000
表示数据是从1000号单元开始存放的,这里省略了数据的初始化。
即提前在1000、1001、1002...1000+N号单元存放了一组数据,这个程序是要找出其中的最大值。
STJ  EXIT
STJ就是store  rJ,即储存寄存器J到EXIT所在的地址,J即jump,是一个跳转用的寄存器,
EXIT是个标签,怎么能存到标签呢,实际是存到那个机器指令的地址字段,如图1:

这张图是一个模拟器的,到后面会说。
执行到JMP *的时候就会跳转到寄存器J的地址。
这是子程序的开头所以要那么做,
在intel汇编里面一般是利用栈实现的:
在子程序开头
push ebp
mov ebp,esp
然后在子程序结尾进行相反的操作。
MIX是用寄存器J实现的。
ENT3    0,1,
ENT3就是enter3,就是存入寄存器3,把什么存进去呢,
1是寄存器I1,
0是机器码的mod,
所以ENT3    0,1是把I1赋值给I3
这个0其实没多大用,但如果写ENT3      1意思是I3赋值为1,所以必须要那个mod
我们刚才说了初始化寄存器I1为数组长度n,I3寄存器为变量k
那么ENT3    0,1就是k=n
 JMP    CHANGEM 就是一个无条件跳转,大家应该都懂的
ENT2    0,3
就是把寄存器I3赋值给寄存器I3,I2为变量j,
那么 ENT2    0,3就相当与j=k
 LDA    X,3
显然是load to A,把什么存到寄存器A呢,
3是寄存器I3,前面说过,I1~I6是变址寄存器,
所以是A=X[I3]   把I3当作数组下标,I3就是k,A为最大值m
所以 LDA    X,3就是m=X[k]
 DEC3    1
这句就是I3寄存器的值减1,DEC不难理解,这里单独的数字就不是寄存器I1了。
 J3P    LOOP
jump if I3 positive,如果I3为正数,跳到LOOP
 CMPA    X,3
CMPA是与寄存器A比较,X,3为X[I3],即比较m与X[k]
 JGE    *+3
*是当前指令的地址,跳转到3条指令后
实例2以第三卷的5.2.1节直接插入排序。大家应该都会80x86汇编,我就仿照MIX的代码用x86汇编写一个做对照。
先看C语言的代码复习一下插入排序的原理:
代码:
#include <stdio.h>
#define N 6

int main()
{
  int a[N]={3,2,1,6,5,4};
  int i,j,temp;
  for(j=1;j<N;j++)
  {
    temp=a[j];
    i=j-1;
    while(temp<a[i]&&i>=0)
    {
      a[i+1]=a[i];
      i--;
    }
    a[i+1]=temp;
  }
  for(i=0;i<N;i++)
    printf("%d\t",a[i]);
  return 0;
}
汇编是这样的:
代码:
.386
.model flat, stdcall
option casemap :none
include    windows.inc
include    kernel32.inc
includelib  kernel32.lib
include    user32.inc
includelib  user32.lib

.data
arr    db  3,2,1,6,5,4  ;数组
count  equ  $-arr     ;数组长度
szBuffer  db  100  dup(0)
szFormat  db  "排序后数组为:%d,%d,%d,%d,%d,%d",0
szTitle    db  "直接插入排序",0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
start:
  mov si,1    ;j=1
S2:
  mov al,arr[si]  ;temp=a[j]
  mov di,si    ;i=j-1
  dec di      ;
S3:
  cmp al,arr[di]  ;cmp temp,a[i]
  jge S5
  mov ah,arr[di]  ;a[i+1]=a[i]
  mov arr[di+1],ah
  dec di      ;i--
  cmp di,0    ;
  jge S3
S5:
  inc di      ;这两行相当于mov arr[di+1],al,但那样有bug
  mov arr[di],al
  inc si
  cmp si,count
  jl S2
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;输出
  xor eax,eax
  mov si,count-1
S6:
  mov al, arr[si] ;逆序压栈
  push eax
  dec si
  cmp si,0
  jge S6
  invoke  wsprintf,addr szBuffer,addr szFormat
  invoke MessageBox,NULL,addr szBuffer,addr szTitle,MB_OK
  invoke  ExitProcess,NULL
  end  start
我用masm32编译运行成功。
完整的MIX的代码我就不给了,在书上65-66页。基本上是一条汇编对应一条MIX指令,大家可以自己对照着看。 

3.模拟器
代码总是要能亲自运行一下才好。
原书作者认为intel的汇编为了保证兼容性而太过复杂,效率不高,所以自己发明了MIX汇编。
可是mix的机器是不存在的,所以只能用模拟器来运行。
模拟器可以在http://www.gnu.org/software/mdk/mdk.html下载,只能在linux下安装。
安装过程很简单,就是打开终端依次输
     ./configure
     make
     sudo make install
这三个命令就可以了。
然后弄emacs的语法加亮,这一步跳过,主要是为了好看。
输入emacs ~/.emacs
打开emacs的配置文件,然后输入以下内容:
(setq load-path (cons "/usr/local/share/mdk" load-path))
(autoload 'mixal-mode "mixal-mode" t)
(add-to-list 'auto-mode-alist '("\\.mixal\\'" . mixal-mode))
(autoload 'mixvm "mixvm" "mixvm/gud interaction" t)
如图2,不要忘了括号,按Ctrl+X、Ctrl+S保存

下面来看一个简单的例子,所谓的helloworld
代码:
*标签  指令(instuction)  操作符(operand)    注释
*
TERM  EQU  19         控制台(terminal)
  ORIG  2000         基地址
START   OUT  MSG(TERM)    在TERM(即控制台)输出MSG
  HLT
MSG   ALF  "HEllO"
  ALF  ",PEDI"
  ALF  "Y.   "
  END  START
保存为hello.mixal
编译: mixasm hello
编译后为hello.mix
执行:[l@localhost mix-1.2.6]$ mixvm -r hello
Program loaded. Start address: 2000
Running ...
HELLO,PEDIY.                                                          
... done
调试:mixvm hello
或者用图形化界面调试更直观 gmixvm
如图3

点File->Load加载hello.mix

最左边一列是地址,第二列是机器指令。
对hello.mixal再解释一下:
每一行从左到右依次为 标签  指令(instuction)  操作符(operand)    注释,
用TAB对齐,比如没有标签第一列就必须留空,因为不对齐就编译不过,这跟其他语言是不一样的,为了让大家看清对齐的格式,我再放张图。

ORIG 2000是 定义基地址,类似于windows pe程序里常见的0x00400000,2000是随便写的,也可以指定其他值。
HLT就是就是停止。
前面说过,MIX只有大写字母和部分符号,如果在程序里写小写的hello,结果输出还会是大写的,如果用!等一些不支持符号就不能编译。
用ALF定义字符串,
因为MIX的机器指令是定长的,所以不能直接
ALF   “HELLO,PEDIY.”
指令除了符号位只有5个字节,那么只能存5个字符,
于是有了以上古怪的写法。