1//
2//    Copyright (C) 1987-2015 by Jeffery P. Hansen
3//
4//    This program is free software; you can redistribute it and/or modify
5//    it under the terms of the GNU General Public License as published by
6//    the Free Software Foundation; either version 2 of the License, or
7//    (at your option) any later version.
8//
9//    This program is distributed in the hope that it will be useful,
10//    but WITHOUT ANY WARRANTY; without even the implied warranty of
11//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12//    GNU General Public License for more details.
13//
14//    You should have received a copy of the GNU General Public License along
15//    with this program; if not, write to the Free Software Foundation, Inc.,
16//    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17//
18//    Last edit by hansen on Fri Dec  1 14:34:44 2000
19//
20
21// Microcode memory bank declarations
22
23microcode bank[31:0] iunit.m1;
24microcode bank[63:32] iunit.m2;
25map bank[7:0] iunit.map;
26
27macrocode bank[7:0] memory.m1;
28
29// Microcode field declarations
30
31//
32// Microcode branching.  mpcop specifies the basic operation.
33//
34field mpcop[1:0]={
35	 next=0,	// Increment mpc
36	 reinit=1,	// Restart CPU
37	 jmap=2,	// Jump from map value
38	 jump=3		// Jump from condition
39};
40
41//
42// Specifies the condition on which to jump if mpcop is "jump".
43//
44field mpccond[12:10]={
45	jne=0,		// Jump if not equal
46	jcarry=1,	// Jump on carry
47	jeq=2,		// Jump if equal
48	jlt=3,		// Jump if less than
49	jgt=4,		// Jump if greater than
50	jle=5,		// Jump if less than or equal
51	jge=6,		// Jump if greater than or equal
52	jmp=7		// Jump always
53};
54
55//
56// Address to jump to if mpcop is "jump" and condition specified
57// by mpccond is true.  This field can not be used at the same
58// time as the idata field.
59//
60field mpcaddr[9:2];
61
62//
63// Specifies 8 bits of data to be used by the EUNIT.  This field
64// can not be used on jump microinstructions.
65//
66field idata[9:2];
67
68//
69// Specifies the A and B operands of the ALU.
70//
71//	qreg		Use Q register
72//	din		Use data in
73//	idata		Use idata field from microinstruction
74//	reg		Use register file
75//
76field aop[15:14]={qreg=0, din=1, idata=2, reg=3};
77field bop[17:16]={qreg=0, din=1, idata=2, reg=3};
78
79field ~ldir[13];	// Load instruction register
80field cin[18];		// Carry in
81field ~clq[19];		// Clear Q register
82field ~ldq[20];		// 16-bit load of Q register
83field ~lddata[21];	// Load EUNIT data from external bus
84field ~ldopr[22];	// Load operand register
85field ~wa[23];		// Write register file on SA
86field sa[27:24];	// Register address A
87field sb[31:28];	// Register address B
88
89//
90// These fields specify the ALU function.
91//
92field ALU_FUNC[36:32];
93field ALU_SHOP[33:32]={arshift=0, lshift=1, rshift=2, roll=3};
94field ALU_BCOMP[32];
95field ALU_AZERO[33];
96field ALU_OP[36:34]={shift=0,xor=1,and=2,or=3,mul=4,add=5,mod=6,div=7};
97
98field ~incpc[37];	// Increment PC
99field ~ldmar[38];	// Load MAR
100field ~ldmdr[39];	// Load MDR
101field ~ldpc[40];	// Load PC
102field ~rd[41];		// Read main memory
103field ~rdmdr[42];	// Read MDR onto external data bus
104field ~wrt[43];		// Write main memory
105field spc[44];		// Address main memory from PC
106field ~isa[45];		// Use sa address from macro instruction
107field ~isb[46];		// Use sb address from macro instruction
108field ~ifunc[47];	// Use function code from macro instruction
109field ~icond[48];	// Use branch condition from macro instruction
110field ~ldql[49];	// 8-bit load of lower half of Q register
111field ~ldqh[50];	// 8-bit load of upper half of Q register
112field ~dout[51];	// Output EUNIT data to external bus
113field ~ldcc[52];	// Load condition code register
114field ~ldhmdr[53];	// Load mdr from high byte of data bus
115field ~rdpc[54];	// Read PC onto external bus
116field ~incmar[55];	// Increment mar (can't use with incpc)
117
118field extra[63:56];	// Extra bits
119
120//////////////////////////////////////////////////////////////////////
121//
122// +-+-+-+-+-+-+-+-+
123// |7|6|5|4|3|2|1|0|
124// +-+-+-+-+-+-+-+-+
125//
126// Basic instruction types are encoded by the high two bits of the
127// first byte of the instruction.  For certain types (e.g., ALU
128// types) some bits are masked when forming the map address.  Bits
129// contributing to the map vector are marked with a *.
130//
131// Move Instruction
132// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
133// |1 1 1 s|a a|b b|   | reg1  |  reg2 |
134// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
135//  * * * * * * * *
136//
137//  s  = size (1 = byte, 0 = word)
138//  aa = operand mode 1
139//  bb = operand mode 2
140//
141// Single operand instruction (push, pop, call, etc.)
142// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
143// |1 0|0| op  |b b|   | reg1  |0 0 0 0|
144// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
145//  * * * * * * * *
146//
147//
148// Branch instruction (jmp, jne, etc.)
149// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
150// |1 0|1|cond |b b|   | reg1  |0 0 0 0|
151// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
152//  * * *       * *
153//
154//
155// ALU Instruction
156// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
157// |0 1|  func   |b|   | reg1  |  reg2 |
158// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
159//  * *           *
160//
161//  func = ALU function
162//  a = operand mode
163//
164// Other instructions
165// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
166// |0 0|   op    |b|   | reg1  |  reg2 |
167// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
168//  * * * * * * * *
169//
170//
171
172registers R0=0, R1=1, R2=2, R3=3, R4=4, R5=5, R6=6, R7=7, R8=8, R9=9, R10=10, R11=11, R12=12, R13=13, FP=14, SP=15;
173
174operands basic {
175    %1,%2 = { +0[0] = 0; +1[7:4]=%1; +1[3:0]=%2; };
176    %1,#2 = { +0[0] = 1; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
177};
178
179operands runiop {
180    %1     = { +0[1:0] = 0; +1[7:4]=%1; +1[3:0]=0; };
181    #1     = { +0[1:0] = 1; +1=0; +2=#1[7:0]; +3=#1[15:8]; };
182    (%1)   = { +0[1:0] = 2; +1[7:4]=%1; +1[3:0]=0; };
183    #2(%1) = { +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
184};
185
186operands wuniop {
187    %1     = { +0[1:0] = 0; +1[7:4]=%1; +1[3:0]=0; };
188    (%1)   = { +0[1:0] = 2; +1[7:4]=%1; +1[3:0]=0; };
189    #2(%1) = { +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
190};
191
192//
193// Operands for move instructions
194//
195operands movoprs {
196    %1,%2         = { +0[3:2] = 0; +0[1:0] = 0; +1[7:4]=%1; +1[3:0]=%2; };
197    %1,#2         = { +0[3:2] = 0; +0[1:0] = 1; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
198    %1,(%2)       = { +0[3:2] = 0; +0[1:0] = 2; +1[7:4]=%1; +1[3:0]=%2; };
199    %1,#3(%2)     = { +0[3:2] = 0; +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=%2; +2=#3[7:0]; +3=#3[15:8]; };
200    %1,(#2)       = { +0[3:2] = 0; +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
201
202
203    (%1),%2       = { +0[3:2] = 2; +0[1:0] = 0; +1[7:4]=%1; +1[3:0]=%2; };
204    (%1),#2       = { +0[3:2] = 2; +0[1:0] = 1; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
205    (%1),(%2)     = { +0[3:2] = 2; +0[1:0] = 2; +1[7:4]=%1; +1[3:0]=%2; };
206    (%1),#3(%2)   = { +0[3:2] = 2; +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=%2; +2=#3[7:0]; +3=#3[15:8]; };
207    (%1),(#2)     = { +0[3:2] = 2; +0[1:0] = 3; +1[7:4]=%1; +1[3:0]=0; +2=#2[7:0]; +3=#2[15:8]; };
208
209    #1(%2),%3     = { +0[3:2] = 3; +0[1:0] = 0; +1[7:4]=%2; +1[3:0]=%3; +2=#1[7:0]; +3=#1[15:8]; };
210    #1(%2),#3     = { +0[3:2] = 3; +0[1:0] = 1; +1[7:4]=%2; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#3[7:0]; +5=#3[15:8]; };
211    #1(%2),(%3)   = { +0[3:2] = 3; +0[1:0] = 2; +1[7:4]=%2; +1[3:0]=%3; +2=#1[7:0]; +3=#1[15:8]; };
212    #1(%2),#4(%3) = { +0[3:2] = 3; +0[1:0] = 3; +1[7:4]=%2; +1[3:0]=%3; +2=#1[7:0]; +3=#1[15:8]; +4=#4[7:0]; +5=#4[15:8]; };
213    #1(%2),(#3) = { +0[3:2] = 3; +0[1:0] = 3; +1[7:4]=%2; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#3[7:0]; +5=#3[15:8]; };
214
215    (#1),%2     = { +0[3:2] = 3; +0[1:0] = 0; +1[7:4]=0; +1[3:0]=%2; +2=#1[7:0]; +3=#1[15:8]; };
216    (#1),#2     = { +0[3:2] = 3; +0[1:0] = 1; +1[7:4]=0; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#2[7:0]; +5=#2[15:8]; };
217    (#1),(%2)   = { +0[3:2] = 3; +0[1:0] = 2; +1[7:4]=0; +1[3:0]=%2; +2=#1[7:0]; +3=#1[15:8]; };
218    (#1),#3(%2) = { +0[3:2] = 3; +0[1:0] = 3; +1[7:4]=0; +1[3:0]=%2; +2=#1[7:0]; +3=#1[15:8]; +4=#3[7:0]; +5=#3[15:8]; };
219    (#1),(#2)   = { +0[3:2] = 3; +0[1:0] = 3; +1[7:4]=0; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#2[7:0]; +5=#2[15:8]; };
220};
221
222//
223// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
224// |0 0|1 1 1 1 1|0|   |0 0 0 0|0 0 0 0|
225// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
226//
227op nop {
228  map nop : 0x3e;
229  +0=0x3e;
230  operands {
231    - = { +1=0; };
232  };
233};
234
235//
236// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
237// |0 0|0 0 0 0 0|0|   |0 0 0 0|0 0 0 0|
238// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
239//
240op halt {
241  map halt : 0x0;
242  +0=0;
243  operands {
244    - = { +1=0; };
245  };
246};
247
248//
249// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
250// |0 0|0 0 0 0 1|0|   | reg1  |  reg2 |
251// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
252//
253op cmp {
254  map cmp_rr : 0x2;
255  map cmp_ri : 0x3;
256  +0[7:1]=0x1;
257  operands basic;
258};
259
260// Generic branch operation
261// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
262// |1 0|1|x x x|b b|   |0 0 0 0| reg1  |
263// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
264//
265// Example:
266//    br  #7, loop
267//
268// Jump always to loop.  7 is a code indicating the condition always.
269//
270op jp {
271  map br_r : 0xa0;
272  map br_i : 0xa1;
273  map br_d : 0xa2;
274  map br_x : 0xa3;
275  +0[7:5] = 0x5;
276  operands {
277    #1,%2     = { +0[1:0] = 0; +0[4:2] = #1; +1[7:4]=%2; +1[3:0]=0; };
278    #1,#2     = { +0[1:0] = 1; +0[4:2] = #1; +1=0; +2=#2[7:0]; +3=#2[15:8]; };
279    #1,(%2)   = { +0[1:0] = 2; +0[4:2] = #1; +1[7:4]=%2; +1[3:0]=0; };
280    #1,#3(%2) = { +0[1:0] = 3; +0[4:2] = #1; +1[7:4]=%2; +1[3:0]=0; +2=#3[7:0]; +3=#3[15:8]; };
281  };
282};
283
284op jne {
285  +0[7:5] = 0x5;
286  +0[4:2] = 0x0;
287  operands runiop;
288};
289
290op jcarry {
291  +0[7:5] = 0x5;
292  +0[4:2] = 0x1;
293  operands runiop;
294};
295
296op jeq {
297  +0[7:5] = 0x5;
298  +0[4:2] = 0x2;
299  operands runiop;
300};
301
302op jlt {
303  +0[7:5] = 0x5;
304  +0[4:2] = 0x3;
305  operands runiop;
306};
307
308op jgt {
309  +0[7:5] = 0x5;
310  +0[4:2] = 0x4;
311  operands runiop;
312};
313
314op jle {
315  +0[7:5] = 0x5;
316  +0[4:2] = 0x5;
317  operands runiop;
318};
319
320op jge {
321  +0[7:5] = 0x5;
322  +0[4:2] = 0x6;
323  operands runiop;
324};
325
326op jmp {
327  +0[7:5] = 0x5;
328  +0[4:2] = 0x7;
329  operands runiop;
330};
331
332
333// Generic ALU operation
334//
335// Note this is not a real instruction but is here for illustrative
336// purposes only.  Map entries must be made for each function code
337// to use this instruction for real.
338//
339// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
340// |0 1|x x x x x|b|   | reg1  |  reg2 |
341// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
342//
343// Example:
344//    alu #0x14, R1, R2
345//
346// Does ALU operation 0x14 (addition) on R1 and R2, storing result in R1.
347//
348//op alu {
349//  map alu_rr : 0x40;
350//  map alu_ri : 0x41;
351// +0[7:6] = 0x1;
352//  operands {
353//    #1,%2,%3 = { +0[0] = 0; +0[5:1]=#1; +1[7:4]=%2; +1[3:0]=%3; };
354//    #1,%2,#3 = { +0[0] = 1; +0[5:1]=#1; +1[7:4]=0; +1[3:0]=%2; +2=#3[7:0]; +3=#3[15:8]; };
355//  };
356//};
357
358//
359// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
360// |0 1|1 0 1 0 0|b|   | reg1  |  reg2 |
361// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
362//
363op add {
364  map alu_rr : 0x68;
365  map alu_ri : 0x69;
366 +0[7:0]=0x68;
367  operands basic;
368};
369
370//
371// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
372// |0 1|1 0 1 0 1|b|   | reg1  |  reg2 |
373// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
374//
375op sub {
376  map alu_rr : 0x6a;
377  map alu_ri : 0x6b;
378 +0[7:0]=0x6a;
379  operands basic;
380};
381
382//
383// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
384// |0 1|1 0 0 0 0|b|   | reg1  |  reg2 |
385// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
386//
387op mul {
388  map xalu_rr : 0x60;
389  map xalu_ri : 0x61;
390 +0[7:0]=0x60;
391  operands basic;
392};
393
394//
395// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
396// |0 1|1 1 1 0 0|b|   | reg1  |  reg2 |
397// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
398//
399op div {
400  map xalu_rr : 0x78;
401  map xalu_ri : 0x79;
402 +0[7:0]=0x78;
403  operands basic;
404};
405
406
407//
408// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
409// |0 1|1 1 0 0 0|b|   | reg1  |  reg2 |
410// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
411//
412op mod {
413  map xalu_rr : 0x70;
414  map xalu_ri : 0x71;
415 +0[7:0]=0x70;
416  operands basic;
417};
418
419
420//
421// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
422// |0 1|0 1 0 0 0|b|   | reg1  |  reg2 |
423// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
424//
425op and {
426  map alu_rr : 0x50;
427  map alu_ri : 0x51;
428 +0[7:0]=0x50;
429  operands basic;
430};
431
432
433// Call subroutine
434// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
435// |1 0|0|0 0 0|b b|   | reg1  |0 0 0 0|
436// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
437//
438// Example:
439//
440//   call	foo, #8
441//
442// This will perform the following actions:
443//   sp = sp - 2
444//   [sp] = pc
445//   sp = sp - 2
446//   [sp] = fp
447//   fp = sp
448//   sp = sp+8
449//   pc = foo
450//
451op call {
452  map call_ri : 0x80;
453  map call_ii : 0x81;
454  map call_di : 0x82;
455  map call_xi : 0x83;
456  +0[7:4] = 0x8;
457  operands {
458    #1,%2     = { +0[1:0] = 0; +1[7:4]=%2; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; };
459    #1,#2     = { +0[1:0] = 1; +1=0; +2=#1[7:0]; +3=#1[15:8]; +4=#2[7:0]; +5=#2[15:8]; };
460    #1,(%2)   = { +0[1:0] = 2; +1[7:4]=%2; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; };
461    #1,#2(%3) = { +0[1:0] = 3; +1[7:4]=%3; +1[3:0]=0; +2=#1[7:0]; +3=#1[15:8]; +4=#2[7:0]; +5=#2[15:8]; };
462
463    #1        = { +0[1:0] = 1; +1=0; +2=0; +3=0; +4=#1[7:0]; +5=#1[15:8]; };
464  };
465};
466
467// Return from subroutine
468// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
469// |0 0|0 0 0 1 0|0|   |0 0 0 0|0 0 0 0|
470// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
471//
472// Example:
473//
474//    ret
475//
476// This will perform the following actions:
477//    sp = fp
478//    fp = [sp]
479//    sp = sp + 2
480//    pc = [sp]
481//    sp = sp + 2
482//
483//
484op ret {
485  map ret : 0x4;
486  +0=4;
487  operands {
488    - = { +1=0; };
489  };
490};
491
492// Push a word on the stack
493// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+
494// |1 0|0|0 0 1|b b|   | reg1  |0 0 0 0|
495// +-+-+-+-+-+-+-+-+   +-+-+-+-+-+-+-+-+  ...
496//
497// Example:
498//
499//    pushw	R1
500//
501op pushw {
502  map pushw_r : 0x84;
503  map pushw_i : 0x85;
504  map pushw_d : 0x86;
505  map pushw_x : 0x87;
506  +0[7:2]=0x21;
507  operands runiop;
508};
509
510
511op movb {
512  map movb_rr : 0xf0;
513  map movb_ri : 0xf1;
514  map movb_rd : 0xf2;
515  map movb_rx : 0xf3;
516
517  map movb_dr : 0xf8;
518  map movb_di : 0xf9;
519  map movb_dd : 0xfa;
520  map movb_dx : 0xfb;
521
522  map movb_xr : 0xfc;
523  map movb_xi : 0xfd;
524  map movb_xd : 0xfe;
525  map movb_xx : 0xff;
526
527  +0[7:4]=0xf;
528  operands movoprs;
529};
530
531op movw {
532  map movw_rr : 0xe0;
533  map movw_ri : 0xe1;
534  map movw_rd : 0xe2;
535  map movw_rx : 0xe3;
536
537  map movw_dr : 0xe8;
538  map movw_di : 0xe9;
539  map movw_dd : 0xea;
540  map movw_dx : 0xeb;
541
542  map movw_xr : 0xec;
543  map movw_xi : 0xed;
544  map movw_xd : 0xee;
545  map movw_xx : 0xef;
546
547  +0[7:4]=0xe;
548  operands movoprs;
549};
550
551/////////////////////////////////////////////////////////////////////////////
552//
553// The microcode for the Menagerie CPU begins here.
554//
555// The CPU begins executing microinstuctions at address 0.  The instructions
556// in the start block are executed only once.  The next block consists of
557// the instuction fetch sequnce.  The multiple labels account for partial
558// fetches that are done by some of the macrocode routines.
559//
560// For macro instructions which have no operands or have only only one operand,
561// there is usually a plain label for that instruction.  For example the
562// microinstruction labeled 'ret' implements the 'ret' macroinstruction.  This
563// mapping is defined by the 'map ret : 0x4;' line in the operand declaration
564// for the ret macroinstruction.
565//
566// For macro instructions with multiple addressing modes, labels are generally
567// of the form 'op_??' where each character after the '_' denotes an addressing
568// mode for an operand.  By convension, the characters:
569//
570//     r	register direct
571//     i	immediate
572//     d	register indirect
573//     x	indexed
574//
575// are used.
576//
577begin microcode @ 0
578start:	clq;								// Q <- 0
579	idata=0x1 ALU_AZERO ALU_OP=add bop=idata ldqh;			// Q.H <- 1
580	ALU_AZERO ALU_OP=add bop=qreg dout ldpc;			// PC <- Q
581	mpcop=jump mpccond=jmp mpcaddr=fetch;				// jump to 'fetch'
582	mpcop=next;
583
584fetch: 	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
585fetch1: incpc spc rd ldmdr rdmdr ldir;					// mdr <- [PC]; PC++; ir <- mdr;
586fetch2:	mpcop=jmap rdmdr ldopr;						// opr <- mdr; jump to opcode
587	mpcop=next;
588
589halt:	mpcop=jump mpccond=jmp mpcaddr=halt extra=0x1;
590	mpcop=jump mpccond=jmp mpcaddr=halt extra=0x1;
591
592//
593// Standard ALU operations (add, sub, and, or, etc.)
594//
595alu_rr:	mpcop=jump mpccond=jmp mpcaddr=fetch2 ifunc
596		isa isb wa aop=reg bop=reg ldcc incpc spc rd ldmdr;	// Ra = Ra (op) Rb; CC; jump to fetch
597	incpc spc rd ldmdr rdmdr ldir;
598
599alu_ri:	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
600	incpc spc rd ldmdr rdmdr ldql
601		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
602	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
603	mpcop=jump mpccond=jmp mpcaddr=fetch ifunc
604		aop=reg bop=qreg wa isa ldcc;				// Ra = Ra (op) Q;  CC; jump to fetch
605	mpcop=next;
606
607//
608// 2-cycle ALU operations (mul, div, mod).  These are the same as the alu_??
609// ops except the ALU inputs and function code are held for 2 clock cycles
610// due to the longer delay in computing these functions.
611//
612xalu_rr: mpcop=next ifunc isa isb aop=reg bop=reg;			// Ra (op) Rb;
613	mpcop=jump mpccond=jmp mpcaddr=fetch2 ifunc
614		isa isb wa aop=reg bop=reg ldcc incpc spc rd ldmdr;	// Ra = Ra (op) Rb; CC; jump to fetch
615	incpc spc rd ldmdr rdmdr ldir;
616
617xalu_ri: incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
618	incpc spc rd ldmdr rdmdr ldql
619		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
620	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
621	mpcop=next ifunc isa isb aop=reg bop=qreg;			// Ra (op) Q;
622	mpcop=jump mpccond=jmp mpcaddr=fetch ifunc
623		aop=reg bop=qreg wa isa ldcc;				// Ra = Ra (op) Q;  CC; jump to fetch
624	mpcop=next;
625
626cmp_rr:	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_OP=add ALU_BCOMP extra=0x22
627		isa isb aop=reg bop=reg ldcc;				// Ra - Rb; CC; jump to fetch
628	mpcop=next;
629
630cmp_ri:	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
631	incpc spc rd ldmdr rdmdr ldql
632		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
633	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
634	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_OP=add ALU_BCOMP
635		aop=reg bop=qreg isa ldcc;				// Ra - Q; CC; jump to fetch
636	mpcop=next;
637
638br_i:	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
639	incpc spc rd ldmdr rdmdr ldql
640		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
641	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
642
643btest:	mpcop=jump mpcaddr=bdojmp icond;				// jump to bdojmp if cond
644	mpcop=next;
645	mpcop=jump mpccond=jmp mpcaddr=fetch;				// jump to fetch
646	mpcop=next;
647bdojmp:	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_AZERO ALU_OP=add
648		bop=qreg dout ldpc;					// PC <- Q, jump to fetch
649	mpcop=next;
650
651
652br_r:	mpcop=jump mpccond=jmp mpcaddr=btest extra=0x10
653		isa aop=reg sb=0 bop=reg ALU_OP=add ldq;		// Q <- Ra; jump to btest
654	mpcop=next;
655
656br_d:	mpcop=jump mpccond=jmp mpcaddr=btest;
657	mpcop=next;
658
659br_x:	mpcop=jump mpccond=jmp mpcaddr=btest;
660	mpcop=next;
661
662call_ii:
663	// Push the PC
664	aop=reg sa=0xf bop=idata idata=2 ALU_OP=add ALU_BCOMP
665		dout ldmar wa extra=0x11;				// SP-2 -> mar; SP = SP - 2;
666	rdpc lddata aop=din bop=idata idata=4 ALU_OP=add ldq;		// Q = PC+4
667	ALU_AZERO ALU_OP=add bop=qreg dout ldmdr;			// Q.L -> mdr
668	wrt;								// [mar] <- mdr;
669	incmar ALU_AZERO ALU_OP=add bop=qreg dout ldhmdr;		// Q.H -> mdr; mar++;
670	mpcop=next;
671	wrt;								// [mar] <- mdr;
672	mpcop=next;
673
674	// Push the FP
675	aop=reg sa=0xf bop=idata idata=2 ALU_OP=add ALU_BCOMP
676			dout ldmar wa;					// SP-2 -> mar; SP = SP - 2;
677	ALU_AZERO bop=reg sb=0xe ALU_OP=add dout ldmdr;			// FP.L -> mdr
678	wrt;								// [mar] <- mdr;
679	incmar ALU_AZERO  bop=reg sb=0xe ALU_OP=add dout ldhmdr; 	// SP.H -> mdr; mar++;
680	mpcop=next;
681	wrt;								// [mar] <- mdr;
682
683	aop=reg sa=0xe bop=reg sb=0xf
684		ALU_AZERO ALU_OP=add wa;				// FP <- SP
685
686	// Dec SP
687	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
688	incpc spc rd ldmdr rdmdr ldql
689		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
690	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
691	aop=reg sa=0xf bop=qreg ALU_OP=add wa;				// SP = SP + Q
692
693	// PC = branch address
694	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
695	incpc spc rd ldmdr rdmdr ldql
696		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
697	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
698	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_AZERO bop=qreg
699		ALU_OP=add dout ldpc;					// PC <- Q
700	mpcop=next;
701
702call_ri: mpcop=jump mpccond=jmp mpcaddr=fetch;
703	mpcop=next;
704
705call_di: mpcop=jump mpccond=jmp mpcaddr=fetch;
706	mpcop=next;
707
708call_xi: mpcop=jump mpccond=jmp mpcaddr=fetch;
709	mpcop=next;
710
711ret:	ALU_AZERO bop=reg sb=0xe ALU_OP=add sa=0xf wa dout ldmar extra=0x12;	// SP <- FP; mar <- FP;
712	aop=reg sa=0xf bop=idata idata=4 ALU_OP=add wa rd incmar ldmdr;	// SP <- SP+4; mdr <- [mar++]
713	ALU_AZERO bop=din lddata ALU_OP=add ldql rd rdmdr incmar ldmdr;	// Q.L <- mdr; mdr <- [mar++]
714	ALU_AZERO bop=din lddata ALU_OP=add ldqh rdmdr;			// Q.H <- mdr;
715	ALU_AZERO bop=qreg ALU_OP=add sa=0xe wa rd incmar ldmdr;	// FP <- Q; mdr <- [mar++]
716	ALU_AZERO bop=din lddata ALU_OP=add ldql rd incmar rdmdr ldmdr;	// Q.L <- mdr; mdr <- [mar++]
717	ALU_AZERO bop=din lddata ALU_OP=add ldqh rdmdr;			// Q.H <- mdr;
718	mpcop=jump mpccond=jmp mpcaddr=fetch1
719		ALU_AZERO bop=qreg ALU_OP=add dout ldpc;		// PC <- Q; jump fetch1
720 	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
721
722
723pushw_d: mpcop=next;
724pushw_x: mpcop=next;
725
726pushw_r: aop=reg sa=0xf bop=idata idata=2 ALU_OP=add ALU_BCOMP
727		extra=0x13 dout ldmar wa;				// mar <- SP-2; SP = SP - 2;
728	aop=reg isa bop=idata idata=0 ALU_OP=add dout ldmdr;		// mdr <- Rb.L;
729	wrt;								// [mar] <- mdr;
730	aop=reg isa bop=idata idata=0 ALU_OP=add dout ldhmdr incmar;	// mdr <- Rb.H; mar++;
731	mpcop=next;
732	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
733	mpcop=next;
734
735pushw_i: incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++;
736	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
737	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
738	aop=reg sa=0xf bop=idata idata=2 ALU_OP=add ALU_BCOMP
739		extra=0x13 dout ldmar wa;				// mar <- SP-2; SP = SP - 2;
740	aop=qreg bop=idata idata=0 ALU_OP=add dout ldmdr;		// mdr <- Q.L;
741	wrt;								// [mar] <- mdr;
742	aop=qreg bop=idata idata=0 ALU_OP=add dout ldhmdr incmar;	// mdr <- Q.H; mar++;
743	mpcop=next;
744	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
745	mpcop=next;
746
747movw_rr: mpcop=jump mpccond=jmp mpcaddr=fetch2 ALU_AZERO ALU_OP=add
748		isa isb wa aop=reg bop=reg ldcc extra=1
749		incpc spc rd ldmdr;					// Ra <- Rb; jump to fetch2; mdr <- [PC]; PC++;
750	incpc spc rd ldmdr rdmdr ldir;					// mdr <- [PC]; PC++; ir <- mdr;
751
752movb_rr: ALU_AZERO ALU_OP=add isb aop=reg bop=reg ldcc extra=1 ldql;	// Q.L <- Rb;
753	mpcop=jump mpccond=jmp mpcaddr=fetch2 aop=idata bop=idata
754		ALU_OP=add ldqh incpc spc rd ldmdr;			// Q.H <- 0; jump to fetch2;mdr <- [PC]; PC++;
755	ALU_AZERO ALU_OP=add bop=qreg isa wa
756		incpc spc rd ldmdr rdmdr ldir;				// Ra <- Q; mdr <- [PC]; PC++; ir <- mdr;
757
758
759movw_ri: incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++;
760	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
761	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
762	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_OP=add ALU_AZERO
763		aop=reg bop=qreg wa isa ldcc;				// Ra = Q;  CC; jump to fetch
764	mpcop=next;
765
766movb_ri:incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++;
767	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
768	rdmdr ldqh ALU_OP=add ALU_AZERO bop=reg sb=0;			// Q.H = 0;
769	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_OP=add ALU_AZERO
770		aop=reg bop=qreg wa isa ldcc;				// Ra = Q;  CC; jump to fetch
771	mpcop=next;
772
773movb_rd:isb aop=idata bop=reg idata=0 ALU_OP=add ldmar dout  extra=3;	// mar <- Rb
774_mbrd:	rd ldmdr;							// mdr <- [mar]
775	mpcop=jump mpccond=jmp mpcaddr=fetch lddata rdmdr isa wa;	// Ra <- mdr
776	ALU_OP=add idata=0 bop=idata aop=reg isa ldcc;			// CC
777
778movw_rd: isb aop=idata bop=reg idata=0 ALU_OP=add ldmar dout  extra=3;	// mar <- Rb
779_mwrd:	rd ldmdr incmar;						// mdr <- [mar++]
780	rd ldmdr lddata rdmdr bop=din ALU_AZERO ALU_OP=add ldql;	// Q.L <- mdr; mdr <- [mar++]
781	lddata rdmdr bop=din ALU_AZERO ALU_OP=add ldqh;			// Q.H <- mdr;
782	mpcop=jump mpccond=jmp mpcaddr=fetch ALU_AZERO bop=qreg
783		ALU_OP=add isa wa ldcc;					// Ra <- Q; CC
784	mpcop=next;
785
786movb_rx: incpc spc rd ldmdr extra=9;					// mdr <- [PC]; PC++;
787	incpc spc rd ldmdr rdmdr ldql
788		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
789	mpcop=jump mpccond=jmp mpcaddr=_mbrd rdmdr ldqh
790		ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr; goto _mbrd
791	isb aop=qreg bop=reg
792		ALU_OP=add ldmar dout;					// mar <- Rb+Q;
793
794movw_rx: incpc spc rd ldmdr extra=9;					// mdr <- [PC]; PC++;
795	incpc spc rd ldmdr rdmdr ldql
796		ALU_OP=add ALU_AZERO lddata bop=din;			// mdr <- [PC]; PC++; Q.L <- mdr
797	mpcop=jump mpccond=jmp mpcaddr=_mwrd rdmdr ldqh ALU_OP=add
798		 ALU_AZERO lddata bop=din;				// Q.H = mdr;
799	isb aop=qreg bop=reg ALU_OP=add
800		ldmar dout;						// mar <- Rb+Q
801
802movb_dr: isa aop=reg bop=idata idata=0 ALU_OP=add ldmar dout ldcc;	// mar <- Ra
803_mbdr:	isb aop=idata bop=reg idata=0 ALU_OP=add ldmdr dout;		// mdr <- Rb
804	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
805	mpcop=next;
806
807movw_dr: isa aop=reg bop=idata idata=0 ALU_OP=add ldmar dout ldcc;	// mar <- Ra
808_mwdr:	isb aop=idata bop=reg idata=0 ALU_OP=add ldmdr dout;		// mdr <- Rb.L
809	wrt;								// [mar] <- mdr;
810	isb aop=idata bop=reg idata=0 ALU_OP=add ldhmdr dout incmar;	// mdr <- Rb.H; mar++;
811	mpcop=next;
812	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
813	mpcop=next;
814
815movb_xr: incpc spc rd ldmdr extra=9;					// mdr <- [PC]; PC++;
816	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
817	mpcop=jump mpccond=jmp mpcaddr=_mbdr rdmdr ldqh ALU_OP=add
818		 ALU_AZERO lddata bop=din;				// Q.H = mdr; jump to _mbdr
819	isa aop=reg bop=qreg ALU_OP=add	ldmar dout ldcc;		// mar <- Ra+Q
820
821
822movw_xr: incpc spc rd ldmdr extra=9;					// mdr <- [PC]; PC++;
823	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
824	mpcop=jump mpccond=jmp mpcaddr=_mwdr rdmdr ldqh ALU_OP=add
825		 ALU_AZERO lddata bop=din;				// Q.H = mdr; jump to _mwdr
826	isa aop=reg bop=qreg ALU_OP=add	ldmar dout ldcc;		// mar <- Ra+Q
827
828movw_xx: mpcop=next  extra=7;
829movb_xx: mpcop=next  extra=7;
830movw_xd: mpcop=next  extra=7;
831movb_xd: mpcop=next  extra=7;
832movw_dd: mpcop=next  extra=7;
833movb_dd: mpcop=next  extra=7;
834movw_dx: mpcop=next  extra=7;
835movb_dx: mpcop=next  extra=7;
836	mpcop=next  extra=7;
837
838movw_di: isa bop=idata idata=0 ALU_OP=add dout ldmar;			// mar <- Ra
839_mwdi:	incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++;
840	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
841	rdmdr ldqh ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr;
842	aop=idata bop=qreg idata=0 ALU_OP=add ldmdr dout;		// mdr <- Q.L
843	wrt;								// [mar] <- mdr;
844	aop=idata bop=qreg idata=0 ALU_OP=add ldhmdr dout incmar;	// mdr <- Q.H; mar++;
845	mpcop=next;
846	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
847	mpcop=next;
848
849movb_di: aop=reg isa bop=idata idata=0 ALU_OP=add dout ldmar extra=0x21;// mar <- Ra
850_mbdi:	incpc spc rd ldmdr;						// mdr <- [PC]; PC++;
851	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
852	aop=idata bop=qreg idata=0 ALU_OP=add ldmdr dout;		// mdr <- Q.L
853	mpcop=jump mpccond=jmp mpcaddr=fetch wrt;			// [mar] <- mdr; jump to fetch
854	mpcop=next;
855
856movw_xi: incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++;
857	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
858	mpcop=jump mpccond=jmp mpcaddr=_mwdi rdmdr ldqh
859		ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr; goto _mwdi
860	isa aop=reg bop=qreg ALU_OP=add dout ldmar;			// mar <- Ra+Q
861
862movb_xi: incpc spc rd ldmdr extra=2;					// mdr <- [PC]; PC++;
863	incpc spc rd ldmdr rdmdr ldql ALU_OP=add ALU_AZERO lddata bop=din; // mdr <- [PC]; PC++; Q.L <- mdr
864	mpcop=jump mpccond=jmp mpcaddr=_mbdi rdmdr ldqh
865		ALU_OP=add ALU_AZERO lddata bop=din;			// Q.H = mdr; goto _mwdi
866	isa aop=reg bop=qreg ALU_OP=add dout ldmar;			// mar <- Ra+Q
867
868
869
870nop:	mpcop=jump mpccond=jmp mpcaddr=fetch extra=0x15;
871	mpcop=next;
872end
873
874/////////////////////////////////////////////////////////////////////////////
875//
876// General notes on assembler
877// Registers are not saved accross function calls unless explicitly saved.
878// Functions return values in R1.
879// The register R0 is a special "always 0" register.  Writing to R0 will have no
880//  effect other than to set condition codes.
881//
882//
883begin macrocode @ 0x100
884ttydata:	.symbol	0x11	// tty data in/out register
885ttystatus:	.symbol	0x10	// tty status register
886
887//
888// Nodes have the format (note that pointers are two bytes):
889//
890// struct node {
891//   struct node *yes_b;
892//   struct node *no_b;
893//   char text[100];
894// };
895//
896nsize:	.symbol 104		// Size of a tree node.  That is "sizeof(struct node)".
897yes_b:	.symbol	0		// Pointer to yes side
898no_b:	.symbol	2		// Pointer to no side
899text:	.symbol 4		// Text of node (animal name or question)
900
901//
902// Execution starts here.
903//
904start:
905	movw	SP, 0		// Initialize stack pointer
906	movw	FP, 0		// Initialize frame pointer
907
908	call	main		// Call main program
909
910sdone:	jmp	sdone		// Infinite loop when main ends
911
912
913////////////////////
914//	main()
915//
916.proc main
917	movw	R13, mend	// Use R13 as a sort of heap pointer
918
919	pushw	welcome		// Push the "Welcome to" message
920	call	printf		// Print the message
921	add	SP,2		// Restore stack pointer
922
923	movw	(root),top_node	// Initialize root node
924	movw	(known),1	// Know one animal
925
926loop:
927	pushw	think		// Push the "Think of an animal..." message
928	call	printf		// Print the message
929	add	SP,2		// Restore stack pointer
930
931	movw	R1, (known)	// Put number of known animals in R1
932	pushw	R1		// Push that number on the stack
933	pushw	numk		// Push the "I know %d animals" message
934	call	printf		// Call printf to print message
935	add	SP,4		// Restore stack
936
937	movw	R1,(root)	// Put the root pointer in R1
938	pushw	R1		// Push the pointer on the stack
939	call	find_animal	// Ask questions to find animal
940	add	SP,2		// Restore the stack
941	movw	(root),R1	// Save new root
942
943	jmp	loop		// Go back and guess another animal
944
945	ret			// Return to call (actually we should never get here)
946.end
947
948////////////////////
949//	find_animal(p)		Find the animal. p is the root node in question tree
950//
951.proc find_animal
952tree:	.symbol	-2		// Local variable for tree pointer
953	sub	SP,2		// Allocate space for local variables
954
955	movw	R1, 4(FP)	// Get the pointer to top node
956	movw	tree(FP),R1	// Store it in "tree"
957
958	movw	R2,yes_b(R1)	// Get pointer in "yes" branch of tree
959	cmp	R2,0		// Compare against 0
960	jne	get_response	// If not 0, then treat as question node
961
962	pushw	R1		// Push pointer to top node
963	call	get_final	// As the final question, and insert new node if necessary
964	add	SP,2		// Restore stack
965	movw	tree(FP),R1	// Save new root node in "tree"
966
967	jmp	done		// All done, go to final cleanup
968
969get_response:
970	movw	R1,tree(FP)	// Put current node pointer in R1
971	movw	R4,R1		// R4 = R1
972	add	R4,text		// Add offset to make R4 pointer to question
973	pushw	R4		// Push text of question
974	call	print		// Print question in tree node
975	add	SP,2		// Restore stack
976
977	pushw	qprompt		// Push "?" prompt
978	call	print		// Print the "? "
979	add	SP,2		// Restore stack
980
981	pushw	buf		// Push address of buffer in which to get response
982	call	gets		// Read response from user
983	add	SP,2		// Restore stack
984
985	pushw	buf		// Push users response on stack
986	pushw	yes		// Push "yes" on stack
987	call	strcmp		// Compare the strings
988	add	SP,4		// Restore stack
989	cmp	R1,0		// Check if R1 was 0
990	jeq	say_yes		// If so, user answered "yes", goto say_yes
991
992	pushw	buf		// Push users response on stack
993	pushw	no		// Push "no" on stack
994	call	strcmp		// Compare the strings
995	add	SP,4		// Restore stack
996	cmp	R1,0		// Check if R1 was 0
997	jeq	say_no		// If so, user answered "no", goto say_no
998
999	pushw	yesno		// Push the "yes or no" error message
1000	call	print		// Print error message
1001	add	SP,2		// Restore stack
1002	jmp	get_response	// Go back and ask again
1003
1004say_yes:
1005	movw	R1,tree(FP)	// Put current tree pointer in R1
1006	movw	R2,yes_b(R1)	// Put "yes" branch pointer in R2
1007	pushw	R2		// Push the yes branch on the stack
1008	call	find_animal	// Recursively ask the next question
1009	add	SP,2		// Restore the stack
1010	movw	R2,tree(FP)	// Get tree pointer again
1011	movw	yes_b(R2),R1	// Update the "yes" branch
1012	jmp	done		// Finish up and prepare to return to caller
1013say_no:
1014	movw	R1,tree(FP)	// Put current tree pointer in R1
1015	movw	R2,no_b(R1)	// Put "no" branch pointer in R2
1016	pushw	R2		// Push the no branch on the stack
1017	call	find_animal	// Recursively ask the next question
1018	add	SP,2		// Restore the stack
1019	movw	R2,tree(FP)	// Get tree pointer again
1020	movw	no_b(R2),R1	// Update the "no" branch
1021	jmp	done		// Finish up and prepare to return to caller
1022
1023done:
1024	movw	R1,tree(FP)	// Put new root node in R1
1025	ret			// Return to caller
1026.end
1027
1028////////////////////
1029//	get_final(p)		Ask final question (at node p), and update tree if necessary.
1030//
1031.proc get_final
1032tree:	.symbol	-2		// Local variable for tree pointer
1033animal_node:	.symbol	-4	// Local variable for new animal node pointer
1034discrim_node:	.symbol	-6	// Local variable for new question node pointer
1035	sub	SP,6		// Allocate space for local variables
1036
1037get_response:
1038	movw	R1, 4(FP)	// Get pointer to current node
1039	movw	tree(FP),R1	// Save it in the 'tree' variable
1040
1041	movw	R1, 4(FP)	// Put pointer to tree in R1
1042	add	R1,text		// Advance R1 to animal name text
1043	pushw	R1		// Push pointer to animal name on stack
1044	pushw	isita		// Push the "is it a..." string pointer
1045	call	printf		// Print the final question
1046	add	SP,4		// Restore stack
1047
1048	pushw	buf		// Push buffer for response
1049	call	gets		// Get the response
1050	add	SP,2		// Restore the stack
1051
1052	pushw	buf		// Push response on stack
1053	pushw	yes		// Push "yes" on stack
1054	call	strcmp		// Compare strings
1055	add	SP,4		// Restore stack
1056	cmp	R1,0		// See if a 0 was returned
1057	jeq	win		// If so, we guessed the animal
1058
1059	pushw	buf		// Push response on stack
1060	pushw	no		// Push "no" on stack
1061	call	strcmp		// Compare strings
1062	add	SP,4		// Restore stack
1063	cmp	R1,0		// See if a 0 was returned
1064	jeq	loose		// If so, we did not guess the animal
1065
1066	pushw	yesno		// Push the "yes or no" error message
1067	call	print		// Print it
1068	add	SP,2		// Restore stack
1069	jmp	get_response	// Go back and ask again
1070
1071win:
1072	pushw	winmsg		// Push the (computer) win message
1073	call	printf		// Print it
1074	add	SP,2		// Restore stack
1075	jmp	done		// All done, go finish up and return
1076
1077loose:
1078	pushw	loosemsg	// Push the (computer) loose message
1079	call	printf		// Print it
1080	add	SP,2		// Restore stack
1081
1082	pushw	nsize			// Push number of bytes in a node
1083	call	malloc			// Allocate memory for new animal node
1084	add	SP,2			// Restore stack
1085	movw	animal_node(FP),R1	// Put address of new node in animal_node
1086
1087	movw	yes_b(R1),0		// Intialize yes branches
1088	movw	no_b(R1),0		// Intialize no branches
1089	add	R1,text			// Move R1 to point to text area
1090	pushw	R1			// Push text buffer
1091	call	gets			// Get animal name
1092	add	SP,2			// Restore stack
1093
1094	movw	R1,tree(FP)		// Put pointer to exiting node in R1
1095	add	R1,text			// Advance to the text field
1096	pushw	R1			// Push pointer to old animal name
1097	movw	R1,animal_node(FP)	// Put pointer to new node in R1
1098	add	R1,text			// Advance to the text field
1099	pushw	R1			// Push new animal name on stack
1100	pushw	dscrim			// Push "what is difference" question
1101	call	printf			// Print the question
1102	add	SP,6			// Restore pointer
1103
1104	pushw	nsize			// Allocate memory for discrimination node
1105	call	malloc			// Allocate memory for new discrimination node
1106	add	SP,2			// Restore stack
1107	movw	discrim_node(FP),R1	// Put address of new node in discrim_node
1108
1109	add	R1,text			// Advance pointer to text field of discrimination node
1110	pushw	R1			// Push pointer to text buffer to input question
1111	call	gets			// Input the question
1112	add	SP,2			// Restore pointer
1113
1114	movw	R1, (known)		// Put number of known animals in R1
1115	add	R1,1			// Increment R1
1116	movw	(known),R1		// Store number of known animals back in "known"
1117
1118L1:	movw	R1,animal_node(FP)	// Put pointer to new animal node in R1
1119	add	R1,text			// Advance R1 to the text field
1120	pushw	R1			// Push new animal name on stack
1121	pushw	which			// Push the "..correct answer for..." message.
1122	call	printf			// Print the message
1123	add	SP,4			// Restore stack
1124
1125	pushw	buf			// Push text buffer on stack
1126	call	gets			// Input a "yes" or "no"
1127	add	SP,2			// Restore stack
1128
1129	pushw	buf			// Push user response
1130	pushw	yes			// Push string "yes"
1131	call	strcmp			// Compare strings
1132	add	SP,4			// Restore stack
1133	cmp	R1,0			// Is the result 0?
1134	jeq	L2			// If so, goto L2.  New animal is on "yes" branch
1135
1136	pushw	buf			// Push user response
1137	pushw	no			// Push string "no"
1138	call	strcmp			// Compare strings
1139	add	SP,4			// Restore stack
1140	cmp	R1,0			// Is the result 0?
1141	jeq	L3			// If so, goto L3.  New animal is on "no" branch
1142
1143	pushw	yesno			// Push the "yes or no" error message
1144	call	printf			// Print it
1145	add	SP,2			// Restore stack
1146	jmp	L1			// Go back and ask again
1147
1148//
1149// Insert new animal on yes branch of new question
1150//
1151L2:	movw	R1,discrim_node(FP)	// Put new question node in R1
1152	movw	R2,tree(FP)		// Put old animal node in R2
1153	movw	R3,animal_node(FP)	// Put new animal node in R3
1154	movw	yes_b(R1),R3		// Set yes branch to new node
1155	movw	no_b(R1),R2		// Set no branch to old node
1156	movw	tree(FP),R1		// Save R1 to tree pointer
1157	jmp	done			// Finish up and return
1158
1159//
1160// Insert new animal on no branch of new question
1161//
1162L3:	movw	R1,discrim_node(FP)	// Put new question node in R1
1163	movw	R2,tree(FP)		// Put old animal node in R2
1164	movw	R3,animal_node(FP)	// Put new animal node in R3
1165	movw	yes_b(R1),R2		// Set yes branch to old node
1166	movw	no_b(R1),R3		// Set no branch to new node
1167	movw	tree(FP),R1		// Save R1 to tree pointer
1168	jmp	done			// Finish up and return
1169
1170done:
1171	movw	R1,tree(FP)		// Put tree pointer into return register R1
1172	ret				// Return to caller
1173.end
1174
1175////////////////////
1176//	malloc(n) -> p	Allocate n bytes and return address in R1.  Allocated memory
1177//			can not be freed.
1178//
1179.proc malloc
1180	movw	R2, 4(FP)	// Get number of bytes
1181	movw	R1,R13		// Pointer to block of memory
1182	add	R13,R2		// Update heap pointer
1183	ret
1184.end
1185
1186////////////////////
1187//	print(s)	Print the string s
1188//
1189.proc print
1190	movw	R1, 4(FP)	// Get parameter (string address)
1191loop:	movb	R2, (R1)	// Put character R1 is pointing to in R2
1192	jeq	done		// If it was a 0, this is the end of the string
1193	movb	(ttydata),R2	// Move char to the tty data register
1194	movb	(ttystatus),#1	// Signal tty controller to print character
1195	add	R1, #1		// Move pointer to next char
1196	jmp	loop		// Go back and print more
1197done:	ret
1198.end
1199
1200////////////////////
1201//	printf(s,...)	Print the format string
1202//
1203.proc printf
1204ptr:	.symbol	-2		// Local var for string pointer
1205arg:	.symbol -4		// Local var for argument pointer
1206	sub	SP,4		// Allocate 4 bytes for local variables
1207
1208	movw	R3,FP		// Assign R3 and add an offset so that it points
1209	add	R3,6		//   to the argument after the control string
1210
1211	movw	R1, 4(FP)	// Put the control string pointer in R1
1212loop:	movb	R2, (R1)	// Get the next char from control string
1213	jeq	done		// If it was a 0, this is the end of the string
1214
1215	cmp	R2, '%'		// See if it is the '%' character
1216	jne	cout		// If not goto cout, and simply print it
1217
1218	add	R1,1		// Advance the string pointer
1219	movb	R2,(R1)		// Get the next char
1220	add	R1,1		// Advance the string pointer again
1221
1222//switch (R2)
1223L1:	cmp	R2,'s'		// See if this is a "%s" conversion
1224	jne	L2		// If not, goto L2
1225
1226// case 's' :
1227	movw	ptr(FP),R1	// Save the string pointer value
1228	movw	arg(FP),R3	// Save the argument pointer value
1229	movw	R2,(R3)		// Get address of string (from arguments) to print
1230	pushw	R2		// Push it on the stack
1231	call	print		// Print the string
1232	add	SP,2		// Restore stack pointer
1233	movw	R1,ptr(FP)	// Restore string pointer value
1234	movw	R3,arg(FP)	// Restore argument pointer value
1235	add	R3,2		// Advance argument pointer to next argument
1236	jmp	loop		// Go back and print more
1237
1238L2:	cmp	R2,'d'		// See if this is a "%d" conversion
1239	jne	loop		// If not, ignore unknown conversion
1240
1241// case 'd' :
1242	movw	ptr(FP),R1	// Save the string pointer value
1243	movw	arg(FP),R3	// Save the argument pointer value
1244	movw	R2,(R3)		// Get number (from arguments) to print
1245	pushw	R2		// Push it on the stack
1246	call	nprint		// Go print the decimal number
1247	add	SP,2		// Restore stack pointer
1248	movw	R1,ptr(FP)	// Restore string pointer value
1249	movw	R3,arg(FP)	// Restore argument pointer value
1250	add	R3,2		// Advance argument pointer to next argument
1251	jmp	loop		// Go back and print more
1252
1253cout:
1254	movb	(ttydata),R2	// Put character in tty data register
1255	movb	(ttystatus),#1	// Signal tty controller to print character
1256	add	R1, #1		// Advance to next char in control string
1257	jmp	loop		// Go back and print more
1258
1259done:	ret			// All done, return to caller
1260.end
1261
1262////////////////////
1263//	nprint(d)	Print the number d in decimal
1264//
1265.proc nprint
1266	movw	R1, 4(FP)	// Move argument value to R1
1267	jeq	zprint		// If it was zero, goto zprint
1268
1269	pushw	R1		// Push value to print on stack
1270	call	nprint_aux 	// Call aux function to print number
1271	add	SP,2		// Restore stack pointer
1272	ret			// All done, return to caller
1273
1274zprint:	movb	(ttydata), '0'	// Put the ascii value of '0' in tty data register
1275	movb	(ttystatus), #1	// Signal tty controller to print character
1276	ret			// All done, return to caller
1277.end
1278
1279////////////////////
1280//	nprint_aux(d)	Print the number d in decimal (but prints nothing if d is zero)
1281//
1282.proc nprint_aux
1283digit:	.symbol	-2		// Digit to print
1284	sub	SP, 2		// Allocate space for local variables
1285
1286	movw	R1, 4(FP)	// Get argument
1287	jeq	done		// If zero, return
1288
1289	// To print the number n we compute
1290	//     R2 = n / 10, and
1291	//     R3 = n % 10
1292	// We can then recursively call nprint_aux to print all
1293	// but the lowest digit, then print the lowest digit ourselves
1294	//
1295	movw	R2, R1		// R2 = R1
1296	div	R2, 10		// R2 = R2 / 10
1297	movw	R3, R1		// R3 = R1
1298	mod	R3, 10		// R3 = R3 % 10
1299	movw	digit(FP),R3	// save lowest digit value
1300
1301	pushw	R2		// Push the higher digits
1302	call	nprint_aux	// Recursively call ourselves to print them
1303	add	SP,2		// Restore stack pointer
1304
1305	movw	R3,digit(FP)	// Restore digit value
1306	add	R3, '0'		// Add ascii for '0' to get ascii for digit
1307	movb	(ttydata),R3	// Put char in tty data register
1308	movb	(ttystatus),#1	// Signal tty controller to print character
1309done:
1310	ret			// All done, resturn to caller
1311.end
1312
1313////////////////////
1314//	strcmp(a,b)		Compare strings a and b
1315//
1316.proc	strcmp
1317	movw	R2,4(FP)	// Get pointer to first string
1318	movw	R3,6(FP)	// Get pointer to second string
1319
1320loop:	movb	R1,(R2)		// Get next char from R2
1321	jeq	eos		// If end of string, goto eos
1322	movb	R4,(R3)		// Get next char from R3
1323	jeq	eos		// If end of string, goto eos
1324
1325	sub	R1,R4		// Compute difference in R1
1326	jne	done		// If difference was not 0, we are done
1327
1328	add	R2,1		// Advance to next char in R2
1329	add	R3,1		// Advance to next char in R3
1330	jmp	loop		// Go compare more
1331
1332eos:
1333	movb	R4,(R3)		// Get next char from R3 again (in case R1 was eos)
1334	sub	R1,R4		// Compute difference in R1
1335
1336done:
1337	ret			// Return to caller, result is in R1
1338.end
1339
1340
1341////////////////////
1342//	gets(b)		Reads chars from tty into b.
1343//
1344.proc gets
1345	movw	R1, 4(FP)	// Get pointer to buffer
1346	movw	R4,R1		// Save starting pointer in R4
1347
1348	//
1349	// Poll for a characcter
1350	//
1351cwait:	movb	R2,(ttystatus)	// Get ready status
1352	and	R2, #2		// Test if a char is ready
1353	jeq	cwait		// If not, go back and wait some more
1354
1355	movb	R3,(ttydata)	// Get char from tty data register
1356	movb	(ttystatus),#2	// Signal char received
1357	cmp	R3,'\r'		// Compare against return char
1358	jeq	done		// Exit if return received
1359
1360	cmp	R3,'\b'		// Compare against backspace char
1361	jeq	del_char	// Delete char if backspace
1362
1363	cmp	R3,0x7f		// Compare against delete char
1364	jeq	del_char	// Delete char if delete character
1365
1366	movb	(ttydata),R3	// Put char to echo in tty data register
1367	movb	(ttystatus),#1	// Signal tty controller to print character
1368
1369	movb	(R1),R3		// Save in buffer
1370	add	R1,1		// increment pointer
1371
1372	jmp	cwait		// Go back and get another char
1373
1374del_char:
1375	cmp	R1,R4		// Compare current pointer against start of line
1376	jle	bell		// If already at start of line, ring bell
1377
1378	movb	R3, 0x7f	// Make sure delete char is in R3
1379	sub	R1,1		// Decrement pointer
1380	movb	(ttydata),R3	// Echo backspace
1381	movb	(ttystatus),#1	// Signal tty controller to print character
1382
1383	jmp	cwait		// Go back and get another char
1384
1385bell:
1386	movb	R3, 7		// Put bell char in R3
1387	movb	(ttydata),R3	// Echo bell
1388	movb	(ttystatus),#1	// Signal tty controller to print character
1389	jmp	cwait		// Go back and get another char
1390
1391done:
1392	movb	(ttydata),'\n'	// Output newline
1393	movb	(ttystatus),#1	// Signal tty controller to print character
1394	movb	(R1),0		// Put eos in the string we just read
1395	ret			// Return to caller
1396.end
1397
1398buf:	.bss	128		// Buffer for input
1399known:	.bss	2		// Number of animals known
1400root:	.bss	2		// root of animals tree
1401
1402top_node:
1403	.short	0		// Pointer to "yes" node
1404	.short	0		// Pointer to "no" node
1405	.byte	"aardvark",0	// Animal name or question text
1406
1407welcome: .byte	"\nWelcome to Animals.\n", 0
1408think:	.byte	"\nThink of an animal and I will try to guess what it is.\n", 0
1409numk:	.byte	"I currently know %d animals.\n\n", 0
1410isita: 	.byte	"Is the animal you are thinking of a %s? ",0
1411yes:	.byte	"yes",0
1412no:	.byte	"no",0
1413yesno:	.byte	"Please type 'yes' or 'no'.\n",0
1414winmsg:	.byte	"I guessed your animal!!!\n\n",0
1415loosemsg: .byte	"I could not guess your animal.  What was your animal? ",0
1416dscrim:	.byte	"Enter a question that would distinguish a %s from a %s.\n> ",0
1417which:	.byte	"The correct answer for a %s is? ",0
1418nl:	.byte	"\n",0
1419qprompt: .byte	"? ",0
1420mend:
1421
1422end
1423