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