github.com/jflude/taocp@v0.0.0-20240210234939-99f2a91af3c2/mix/cycle_test.go (about) 1 package mix 2 3 import ( 4 "errors" 5 "os" 6 "strings" 7 "testing" 8 ) 9 10 func TestCycle(t *testing.T) { 11 c, tmpDir := newSandbox(t, "") 12 defer closeSandbox(t, c, tmpDir) 13 if testing.Verbose() { 14 c.Tracer = os.Stdout 15 } 16 17 // LDA 18 copy(c.Contents[mBase+0:], egCycle1) 19 c.Contents[mBase+2000] = NewWord(-(80<<18 | 030504)) 20 c.next = 0 21 for i, v := range okCycle1 { 22 if err := c.Cycle(); err != nil { 23 t.Errorf("#%d: error: %v", i+1, err) 24 c.next++ 25 continue 26 } 27 if c.Reg[A] != v { 28 t.Errorf("#%d: got: %#v, want: %#v", 29 i+1, c.Reg[A], v) 30 } 31 } 32 33 // LD[1-6]N 34 copy(c.Contents[mBase+0:], egCycle2) 35 c.Contents[mBase+2000] = NewWord(-01234) 36 c.next = 0 37 for i, v := range okCycle2 { 38 if err := c.Cycle(); err != nil { 39 t.Errorf("#%d: error: %v", i+1, err) 40 c.next++ 41 continue 42 } 43 if c.Reg[I1+i] != v { 44 t.Errorf("#%d: got: %#v, want: %#v", 45 i+1, c.Reg[I1+i], v) 46 } 47 } 48 49 // STA 50 copy(c.Contents[mBase+0:], egCycle3) 51 c.Reg[A] = NewWord(0607101100) 52 c.next = 0 53 for i, v := range okCycle3 { 54 c.Contents[mBase+2000] = NewWord(-0102030405) 55 if err := c.Cycle(); err != nil { 56 t.Errorf("#%d: error: %v", i+1, err) 57 c.next++ 58 continue 59 } 60 if c.Contents[mBase+2000] != v { 61 t.Errorf("#%d: got: %#v, want: %#v", 62 i+1, c.Contents[mBase+2000], v) 63 } 64 } 65 66 // ST1 67 copy(c.Contents[mBase+0:], egCycle4) 68 c.Reg[I1] = NewWord(01100) 69 c.next = 0 70 for i, v := range okCycle4 { 71 c.Contents[mBase+2000] = NewWord(-0102030405) 72 if err := c.Cycle(); err != nil { 73 t.Errorf("#%d: error: %v", i+1, err) 74 c.next++ 75 continue 76 } 77 if c.Contents[mBase+2000] != v { 78 t.Errorf("#%d: got: %#v, want: %#v", 79 i+1, c.Contents[mBase+2000], v) 80 } 81 } 82 83 // ADD, SUB, MUL, DIV 84 for i, op := range egCycle5 { 85 c.Contents[mBase+0] = op[0] 86 c.Reg[A] = op[1] 87 c.Reg[X] = op[2] 88 c.Contents[mBase+1000] = op[3] 89 c.next = 0 90 if err := c.Cycle(); err != nil { 91 t.Errorf("#%d: error: %v", i+1, err) 92 continue 93 } 94 if c.Reg[A] != op[4] { 95 t.Errorf("#%d: got: A = %#v, want: A = %#v", 96 i+1, c.Reg[A], op[4]) 97 } 98 if c.Reg[X] != op[5] { 99 t.Errorf("#%d: got: X = %#v, want: X = %#v", 100 i+1, c.Reg[X], op[5]) 101 } 102 } 103 104 // SLA, SRA, SRAX, SLC, SRC, SLB, SRB 105 c.Reg[A] = NewWord(0102030405) 106 c.Reg[X] = NewWord(-0607101112) 107 c.next = 0 108 for i, op := range egCycle6 { 109 c.Contents[mBase+i] = op[0] 110 if err := c.Cycle(); err != nil { 111 t.Errorf("#%d: error: %v", i+1, err) 112 c.next++ 113 continue 114 } 115 if c.Reg[A] != op[1] { 116 t.Errorf("#%d: got: A = %#v, want: A = %#v", 117 i+1, c.Reg[A], op[1]) 118 c.Reg[A] = op[1] 119 } 120 if c.Reg[X] != op[2] { 121 t.Errorf("#%d: got: X = %#v, want: X = %#v", 122 i+1, c.Reg[X], op[2]) 123 c.Reg[X] = op[2] 124 } 125 } 126 127 // NUM, INCA1, CHAR 128 c.Reg[A] = NewWord(-0374047) 129 c.Reg[X] = NewWord(04571573636) 130 c.next = 0 131 for i, op := range egCycle7 { 132 c.Contents[mBase+i] = op[0] 133 if err := c.Cycle(); err != nil { 134 t.Errorf("#%d: error: %v", i+1, err) 135 c.next++ 136 continue 137 } 138 if c.Reg[A] != op[1] { 139 t.Errorf("#%d: got: A = %#v, want: A = %#v", 140 i+1, c.Reg[A], op[1]) 141 c.Reg[A] = op[1] 142 } 143 if c.Reg[X] != op[2] { 144 t.Errorf("#%d: got: X = %#v, want: X = %#v", 145 i+1, c.Reg[X], op[2]) 146 c.Reg[X] = op[2] 147 } 148 } 149 150 // NUM (overflow, etc) 151 c.Contents[mBase+0] = NUM 152 for i, op := range egCycle8 { 153 c.Reg[A] = op[0] 154 c.Reg[X] = op[1] 155 c.Overflow = false 156 c.next = 0 157 if err := c.Cycle(); err != nil { 158 t.Errorf("#%d: error: %v", i+1, err) 159 continue 160 } 161 if c.Overflow { 162 c.Reg[A] = c.Reg[A].Negate() 163 } 164 if c.Reg[A] != op[2] { 165 t.Errorf("#%d: got: A = %#v, want: A = %#v", 166 i+1, c.Reg[A], op[2]) 167 } 168 } 169 170 // AND, OR, XOR 171 c.next = 1000 172 for i, op := range egCycle9 { 173 c.Contents[mBase+1000+i] = op[0] 174 c.Contents[mBase+0] = op[1] 175 c.Reg[A] = NewWord(-05555555555) 176 if err := c.Cycle(); err != nil { 177 t.Errorf("#%d: error: %v", i+1, err) 178 c.next++ 179 continue 180 } 181 if c.Reg[A] != op[2] { 182 t.Errorf("#%d: got: A = %#v, want: A = %#v", 183 i+1, c.Reg[A], op[2]) 184 } 185 } 186 187 // Program M, Section 1.3.2 188 copy(c.Contents[mBase+3000:], egCycle10) 189 c.Contents[mBase+0] = NewWord(3000<<18 | 39) // JMP 3000 190 c.Contents[mBase+1] = NewWord(0205) // HLT 191 c.Contents[mBase+1000] = NewWord(1) 192 c.Contents[mBase+1001] = NewWord(7) 193 c.Contents[mBase+1002] = NewWord(2) 194 c.Contents[mBase+1003] = NewWord(7) 195 c.Contents[mBase+1004] = NewWord(6) 196 c.Contents[mBase+1005] = NewWord(3) 197 c.Contents[mBase+1006] = NewWord(1) 198 c.Contents[mBase+1007] = NewWord(4) 199 c.Contents[mBase+1008] = NewWord(5) 200 c.Contents[mBase+1009] = NewWord(2) 201 c.Reg[I1] = 10 202 c.next = 0 203 if err := c.resume(); !errors.Is(err, ErrHalted) { 204 t.Error("error:", err) 205 } 206 if c.Reg[A].Int() != 7 { 207 t.Errorf("got: %#o (%v), want: 7", c.Reg[A], c.Reg[A]) 208 } 209 if c.Elapsed != 226 { 210 t.Fatalf("got: elapsed %d, want %d", c.Elapsed, 226) 211 } 212 213 // Program P, Section 1.3.2 214 c.zeroContents() 215 c.unlockContents() 216 c.Elapsed = 0 217 c.Idle = 0 218 copy(c.Contents[mBase+3000:], egCycle11a) 219 copy(c.Contents[mBase+0:], egCycle11b) 220 copy(c.Contents[mBase+1995:], egCycle11c) 221 copy(c.Contents[mBase+2024:], egCycle11d) 222 copy(c.Contents[mBase+2049:], egCycle11e) 223 c.next = 3000 224 if err := c.resume(); !errors.Is(err, ErrHalted) { 225 t.Error("error:", err) 226 } 227 b, err := os.ReadFile("printer.mix") 228 if err != nil { 229 t.Fatal("error:", err) 230 } 231 if strings.Compare(string(b), okCycle11) != 0 { 232 t.Error("got: incorrect printer output") 233 } 234 if c.Elapsed != 6100052 { 235 t.Fatalf("got: elapsed %d, want %d", c.Elapsed, 6100052) 236 } 237 if c.Idle != 5909153 { 238 t.Fatalf("got: idle %d, want %d", c.Idle, 5909153) 239 } 240 } 241 242 func BenchmarkProgramM(b *testing.B) { 243 c := NewComputer() 244 copy(c.Contents[mBase+3000:], egCycle10) 245 c.Contents[mBase+0] = NewWord(3000<<18 | 39) // JMP 3000 246 c.Contents[mBase+1] = NewWord(0205) // HLT 247 c.Contents[mBase+1000] = NewWord(1) 248 c.Contents[mBase+1001] = NewWord(7) 249 c.Contents[mBase+1002] = NewWord(2) 250 c.Contents[mBase+1003] = NewWord(7) 251 c.Contents[mBase+1004] = NewWord(6) 252 c.Contents[mBase+1005] = NewWord(3) 253 c.Contents[mBase+1006] = NewWord(1) 254 c.Contents[mBase+1007] = NewWord(4) 255 c.Contents[mBase+1008] = NewWord(5) 256 c.Contents[mBase+1009] = NewWord(2) 257 b.ResetTimer() 258 for i := 0; i < b.N; i++ { 259 c.Reg[I1] = 10 260 c.next = 0 261 if err := c.resume(); !errors.Is(err, ErrHalted) { 262 b.Fatal("error:", err) 263 } 264 } 265 } 266 267 func BenchmarkProgramP(b *testing.B) { 268 c := NewComputer() 269 binding := DefaultBinding 270 binding[PrinterUnit] = "/dev/null" 271 c.Bind(binding) 272 copy(c.Contents[mBase+3000:], egCycle11a) 273 copy(c.Contents[mBase+0:], egCycle11b) 274 copy(c.Contents[mBase+1995:], egCycle11c) 275 copy(c.Contents[mBase+2024:], egCycle11d) 276 copy(c.Contents[mBase+2049:], egCycle11e) 277 b.ResetTimer() 278 for i := 0; i < b.N; i++ { 279 c.next = 3000 280 if err := c.resume(); !errors.Is(err, ErrHalted) { 281 b.Error("error:", err) 282 } 283 } 284 } 285 286 var ( 287 egCycle1 = []Word{ 288 NewWord(2000<<18 | 0510), // LDA 2000 289 NewWord(2000<<18 | 01510), // LDA 2000(1:5) 290 NewWord(2000<<18 | 03510), // LDA 2000(3:5) 291 NewWord(2000<<18 | 0310), // LDA 2000(0:3) 292 NewWord(2000<<18 | 04410), // LDA 2000(4:4) 293 NewWord(2000<<18 | 010), // LDA 2000(0:0) 294 } 295 okCycle1 = []Word{ 296 NewWord(-(80<<18 | 030504)), 297 NewWord(80<<18 | 030504), 298 NewWord(030504), 299 NewWord(-(80<<6 | 3)), 300 NewWord(5), 301 NewWord(0).Negate(), 302 } 303 304 egCycle2 = []Word{ 305 NewWord(2000<<18 | 0521), // LD1N 2000 306 NewWord(2000<<18 | 01522), // LD2N 2000(1:5) 307 NewWord(2000<<18 | 03523), // LD3N 2000(3:5) 308 NewWord(2000<<18 | 0324), // LD4N 2000(0:3) 309 NewWord(2000<<18 | 04425), // LD5N 2000(4:4) 310 NewWord(2000<<18 | 026), // LD6N 2000(0:0) 311 } 312 okCycle2 = []Word{ 313 NewWord(01234), 314 NewWord(-01234), 315 NewWord(-01234), 316 0, 317 NewWord(-012), 318 0, 319 } 320 321 egCycle3 = []Word{ 322 NewWord(2000<<18 | 0530), // STA 2000 323 NewWord(2000<<18 | 01530), // STA 2000(1:5) 324 NewWord(2000<<18 | 05530), // STA 2000(5:5) 325 NewWord(2000<<18 | 02230), // STA 2000(2:2) 326 NewWord(2000<<18 | 02330), // STA 2000(2:3) 327 NewWord(2000<<18 | 0130), // STA 2000(0:1) 328 } 329 okCycle3 = []Word{ 330 NewWord(0607101100), 331 NewWord(-0607101100), 332 NewWord(-0102030400), 333 NewWord(-0100030405), 334 NewWord(-0111000405), 335 NewWord(02030405), 336 } 337 338 egCycle4 = []Word{ 339 NewWord(2000<<18 | 0531), // ST1 2000 340 NewWord(2000<<18 | 01531), // ST1 2000(1:5) 341 NewWord(2000<<18 | 05531), // ST1 2000(5:5) 342 NewWord(2000<<18 | 02231), // ST1 2000(2:2) 343 NewWord(2000<<18 | 02331), // ST1 2000(2:3) 344 NewWord(2000<<18 | 0131), // ST1 2000(0:1) 345 } 346 okCycle4 = []Word{ 347 NewWord(01100), 348 NewWord(-01100), 349 NewWord(-0102030400), 350 NewWord(-0100030405), 351 NewWord(-0111000405), 352 NewWord(02030405), 353 } 354 355 egCycle5 = [][]Word{ 356 { // #1 357 NewWord(01750000501), // ADD 1000 358 NewWord(1234<<18 | 010226), // A (before) 359 0, // X (before) 360 NewWord(100<<18 | 050062), // CONTENTS[1000] 361 NewWord(1334<<18 | 060310), // A (after) 362 0, // X (after) 363 }, 364 { // #2 365 NewWord(01750000502), // SUB 1000 366 NewWord(-(1234<<18 | 9)), 367 0, 368 NewWord(-(2000<<18 | (150 << 6))), 369 NewWord(766<<18 | 149<<6 | 067), 370 0, 371 }, 372 { // #3 373 NewWord(01750001103), // MUL 1000(1:1) 374 NewWord(-112), 375 0, 376 NewWord(0200000000), 377 NewWord(0).Negate(), 378 NewWord(-224), 379 }, 380 { // #4 381 NewWord(01750000503), // MUL 1000 382 NewWord(-(50<<24 | 112<<6 | 4)), 383 0, 384 NewWord(-0200000000), 385 NewWord(100<<18 | 224), 386 NewWord(8 << 24), 387 }, 388 { // #5 389 NewWord(01750000504), // DIV 1000 390 0, 391 NewWord(17), 392 NewWord(3), 393 NewWord(5), 394 NewWord(2), 395 }, 396 { // #6 397 NewWord(01750000504), // DIV 1000 398 NewWord(0).Negate(), 399 NewWord(1235<<18 | 0301), 400 NewWord(-0200), 401 NewWord(617<<12 | 04001), 402 NewWord(-0101), 403 }, 404 } 405 406 egCycle6 = [][3]Word{ 407 { // #1 408 NewWord(01000306), // SRAX 1 409 NewWord(01020304), // A 410 NewWord(-0506071011), // X 411 }, 412 { // #2 413 NewWord(02000006), // SLA 2 414 NewWord(0203040000), 415 NewWord(-0506071011), 416 }, 417 { // #3 418 NewWord(04000506), // SRC 4 419 NewWord(0607101102), 420 NewWord(-0304000005), 421 }, 422 { // #4 423 NewWord(02000106), // SRA 2 424 NewWord(060710), 425 NewWord(-0304000005), 426 }, 427 { // #5 428 NewWord(0765000406), // SLC 501 429 NewWord(06071003), 430 NewWord(-0400000500), 431 }, 432 { // #6 433 NewWord(03000606), // SLB 3 434 NewWord(060710030), 435 NewWord(-04000005000), 436 }, 437 { // #7 438 NewWord(03000706), // SRB 3 439 NewWord(06071003), 440 NewWord(-0400000500), 441 }, 442 } 443 444 egCycle7 = [][3]Word{ 445 { // #1 446 NewWord(05), // NUM 447 NewWord(-12977700), 448 NewWord(04571573636), 449 }, 450 { // #2 451 NewWord(01000060), // INCA 1 452 NewWord(-12977699), 453 NewWord(04571573636), 454 }, 455 { // #3 456 NewWord(0105), // CHAR 457 NewWord(-03636374047), 458 NewWord(04545444747), 459 }, 460 } 461 462 egCycle8 = [][3]Word{ 463 { // #1 464 NewWord(-03736363636), // A (before) 465 NewWord(-03636363637), // X (before) 466 NewWord(-1000000001), // A (after, negated if overflow) 467 }, 468 { // #2 469 NewWord(-04747474747), 470 NewWord(04747474747), 471 NewWord(02402761777), 472 }, 473 } 474 475 egCycle9 = [][3]Word{ 476 { // #1 477 NewWord(0305), // AND 0 478 NewWord(0000777777), 479 NewWord(-0555555), 480 }, 481 { // #2 482 NewWord(0405), // OR 0 483 NewWord(02222222222), 484 NewWord(-07777777777), 485 }, 486 { // #3 487 NewWord(0505), // XOR 0 488 NewWord(07777777777), 489 NewWord(-02222222222), 490 }, 491 } 492 493 // * FIND THE MAXIMUM 494 // X EQU 1000 495 egCycle10 = []Word{ // ORIG 3000 496 NewWord(3009<<18 | 0240), // MAXIMUM STJ EXIT 497 NewWord(010263), // INIT ENT3 0,1 498 NewWord(3005<<18 | 39), // JMP CHANGEM 499 NewWord(1000<<18 | 030570), // LOOP CMPA X,3 500 NewWord(3007<<18 | 0700 | 39), // JLE *+3 501 NewWord(030200 | 50), // CHANGEM ENT2 0,3 502 NewWord(1000<<18 | 030500 | 8), // LDA X,3 503 NewWord(01000100 | 51), // DEC3 1 504 NewWord(3003<<18 | 0200 | 43), // J3P LOOP 505 NewWord(3009<<18 | 39), // EXIT JMP * 506 } 507 508 // * EXAMPLE: TABLE OF PRIMES 509 // L EQU 500 510 // PRINTER EQU 18 511 // PRIME EQU -1 512 // BUF0 EQU 2000 513 // BUF1 EQU BUF0+25 514 egCycle11a = []Word{ // ORIG 3000 515 NewWord(02243), // START IOC 0(PRINTER) 516 NewWord(2050<<18 | 0511), // LD1 =1-L= 517 NewWord(2051<<18 | 0512), // LD2 =3= 518 NewWord(01000061), // 2H INC1 1 519 NewWord(499<<18 | 010532), // ST2 PRIME+L,1 520 NewWord(3016<<18 | 0151), // J1Z 2F 521 NewWord(02000062), // 4H INC2 2 522 NewWord(02000263), // ENT3 2 523 NewWord(0260), // 6H ENTA 0 524 NewWord(020267), // ENTX 0,2 525 NewWord(-01030504), // DIV PRIME,3 526 NewWord(3006<<18 | 0157), // JXZ 4B 527 NewWord(-01030570), // CMPA PRIME,3 528 NewWord(01000063), // INC3 1 529 NewWord(3008<<18 | 0647), // JG 6B 530 NewWord(3003<<18 | 047), // JMP 2B 531 NewWord(1995<<18 | 02245), // 2H OUT TITLE(PRINTER) 532 NewWord(2035<<18 | 0264), // ENT4 BUF1+10 533 NewWord(-062000265), // ENT5 -50 534 NewWord(501<<18 | 065), // 2H INC5 L+1 535 NewWord(-01050510), // 4H LDA PRIME,5 536 NewWord(0105), // CHAR 537 NewWord(041437), // STX 0,4(1:4) 538 NewWord(01000164), // DEC4 1 539 NewWord(062000165), // DEC5 50 540 NewWord(3020<<18 | 0255), // J5P 4B 541 NewWord(042245), // OUT 0,4(PRINTER) 542 NewWord(030040514), // LD4 24,4 543 NewWord(3019<<18 | 055), // J5N 2B 544 NewWord(0205), // HLT 545 } 546 // * TABLES AND BUFFERS 547 egCycle11b = []Word{ // ORIG PRIME+1 (=0) 548 NewWord(2), // CON 2 549 } 550 egCycle11c = []Word{ // ORIG BUF0-5 (=1995) 551 NewWord(0611232627), // TITLE ALF FIRST 552 NewWord(06113105), // ALF FIVE 553 NewWord(010301704), // ALF HUND 554 NewWord(02305040021), // ALF RED P 555 NewWord(02311160526), // ALF RIMES 556 } 557 egCycle11d = []Word{ // ORIG BUF0+24 (=2024) 558 NewWord(2035), // CON BUF1+10 559 } 560 egCycle11e = []Word{ // ORIG BUF1+24 (=2049) 561 NewWord(2010), // CON BUF0+10 562 NewWord(-499), // CON 1-L 563 NewWord(3), // CON 3 564 } 565 566 okCycle11 = "\014" + `FIRST FIVE HUNDRED PRIMES 567 0002 0233 0547 0877 1229 1597 1993 2371 2749 3187 568 0003 0239 0557 0881 1231 1601 1997 2377 2753 3191 569 0005 0241 0563 0883 1237 1607 1999 2381 2767 3203 570 0007 0251 0569 0887 1249 1609 2003 2383 2777 3209 571 0011 0257 0571 0907 1259 1613 2011 2389 2789 3217 572 0013 0263 0577 0911 1277 1619 2017 2393 2791 3221 573 0017 0269 0587 0919 1279 1621 2027 2399 2797 3229 574 0019 0271 0593 0929 1283 1627 2029 2411 2801 3251 575 0023 0277 0599 0937 1289 1637 2039 2417 2803 3253 576 0029 0281 0601 0941 1291 1657 2053 2423 2819 3257 577 0031 0283 0607 0947 1297 1663 2063 2437 2833 3259 578 0037 0293 0613 0953 1301 1667 2069 2441 2837 3271 579 0041 0307 0617 0967 1303 1669 2081 2447 2843 3299 580 0043 0311 0619 0971 1307 1693 2083 2459 2851 3301 581 0047 0313 0631 0977 1319 1697 2087 2467 2857 3307 582 0053 0317 0641 0983 1321 1699 2089 2473 2861 3313 583 0059 0331 0643 0991 1327 1709 2099 2477 2879 3319 584 0061 0337 0647 0997 1361 1721 2111 2503 2887 3323 585 0067 0347 0653 1009 1367 1723 2113 2521 2897 3329 586 0071 0349 0659 1013 1373 1733 2129 2531 2903 3331 587 0073 0353 0661 1019 1381 1741 2131 2539 2909 3343 588 0079 0359 0673 1021 1399 1747 2137 2543 2917 3347 589 0083 0367 0677 1031 1409 1753 2141 2549 2927 3359 590 0089 0373 0683 1033 1423 1759 2143 2551 2939 3361 591 0097 0379 0691 1039 1427 1777 2153 2557 2953 3371 592 0101 0383 0701 1049 1429 1783 2161 2579 2957 3373 593 0103 0389 0709 1051 1433 1787 2179 2591 2963 3389 594 0107 0397 0719 1061 1439 1789 2203 2593 2969 3391 595 0109 0401 0727 1063 1447 1801 2207 2609 2971 3407 596 0113 0409 0733 1069 1451 1811 2213 2617 2999 3413 597 0127 0419 0739 1087 1453 1823 2221 2621 3001 3433 598 0131 0421 0743 1091 1459 1831 2237 2633 3011 3449 599 0137 0431 0751 1093 1471 1847 2239 2647 3019 3457 600 0139 0433 0757 1097 1481 1861 2243 2657 3023 3461 601 0149 0439 0761 1103 1483 1867 2251 2659 3037 3463 602 0151 0443 0769 1109 1487 1871 2267 2663 3041 3467 603 0157 0449 0773 1117 1489 1873 2269 2671 3049 3469 604 0163 0457 0787 1123 1493 1877 2273 2677 3061 3491 605 0167 0461 0797 1129 1499 1879 2281 2683 3067 3499 606 0173 0463 0809 1151 1511 1889 2287 2687 3079 3511 607 0179 0467 0811 1153 1523 1901 2293 2689 3083 3517 608 0181 0479 0821 1163 1531 1907 2297 2693 3089 3527 609 0191 0487 0823 1171 1543 1913 2309 2699 3109 3529 610 0193 0491 0827 1181 1549 1931 2311 2707 3119 3533 611 0197 0499 0829 1187 1553 1933 2333 2711 3121 3539 612 0199 0503 0839 1193 1559 1949 2339 2713 3137 3541 613 0211 0509 0853 1201 1567 1951 2341 2719 3163 3547 614 0223 0521 0857 1213 1571 1973 2347 2729 3167 3557 615 0227 0523 0859 1217 1579 1979 2351 2731 3169 3559 616 0229 0541 0863 1223 1583 1987 2357 2741 3181 3571 617 ` 618 )