Reverse engineering of the first smart watch Seiko UC-2000
Somewhere in late 1983 - early '84, the Japanese company Seiko began selling the first ever computerized watch - Seiko Data-2000 and Seiko UC-2000. Data-2000 had the ability to store 2KB notes, they needed to be entered using a special compact keyboard that came in the kit. UC-2000 is essentially the same Data-2000 with a different color case, but they were already positioned as part of the Wrist Information System, which, among other things, included the UC-2200 terminal, which is a computer with a Z80-compatible processor, BASIC interpreter and a thermal printer, but without a screen, in which quality the clock was used (as it is not strange). Among other things, the terminal made it possible to load applications with special cartridges on the watch. You can read more about the lineup of the early Seiko smartwatch, for example, in this article . In the same post, I will tell you how I wrote (maybe) the first, for more than 33 years, program for this watch. A note on the clock in the journal Popular Science for 84 years, the entire lower periphery is shown in the bottom left photo.
Small introduction
About UC-2000, I learned a couple of years ago, at about the same time left such a comment on the GT. Since then, the thought to buy a watch and try to write something for them has not left me. Initially, I was inclined to buy Epson RC-20, but they are so rare that during this time I saw only one offer on Ebay which I missed out of stupidity. As a result, I was tired of waiting and I bought a much more affordable UC-2000, without a terminal and keyboard, which were not needed for my purposes. In fact, of course, I would have to buy a docking station in order to remove the dump of the ROM from the cartridge with applications and understand the operation of the wireless interface that the clock used to communicate with the periphery. But, to my happiness, this work was done by one person back in 2002, he had a project to create his own electronic clock, and he wanted to borrow a screen from Seiko. I do not know how his work ended, but what was published on his website helped me a lot. This person (unfortunately, I do not know his name) published applications from a complete cartridge, described the wireless inductive interface protocol, and also wrote an application that largely implements the functionality of the terminal. ')
So, having these introductory, I wrote out the clock and began to search for information. Here it is necessary to clarify that I am not strong either in assembler (I wrote one and a half programs on it for my entire life before), especially in electronics, but as usually happens, the lack of knowledge was compensated by a great desire. Because of this, my methods and terminology may seem strange or even erroneous, I hope you will correct me in the comments.
Reverse engineering
What was known about the architecture of this watch? Here, on this advertising poster, perhaps, all available technical information is displayed:
4bit CPU, 6KB ROM, 1.5KB LCD ROM, 2KB RAM. And that's all.
Photos of the entrails do not provide any additional useful information - all the chips are expected without package without any marking:
From top to bottom, from left to right: an inductor used for the wireless interface and a battery compartment;PCB with a processor module on a ceramic substrate - 2 chips, CPU and RAM;matrix LCD panel - 4 lines of 10 characters each, 5x7 dots;reverse side of the board - 4 display controller chips.
Nothing remains but to try to manually disassemble programs from a regular cartridge, there are 5 of them:
Amida - game, the Japanese maze;
ard - card game;
Hit is a game, we shoot back from enemies;
Race - tote simulator;
Scheduler - diary, the only practical application.
Judging by the advertisement, there was still a cartridge, with a Japanese-English dictionary, but apparently it was only sold on the Japanese market, so it is not easy to find it.
We look at the hex-dump of one of the applications, for example the game HIT
00000000 CC 0F CC F5 CD 4A C1 09 C0 E0 CC 18 CC 22 CC 7C .J.."| 00000010 CC CB C2 A9 C3 07 C3 9C C0 9B CD AE B0 00 45 78 .њ›°.Ex 00000020 45 5E 45 22 3C 10 A8 F2 88 82 3C 18 A8 F2 C2 27 E^E"<.€‚<.' 00000030 57 48 43 4E D4 21 3C 10 E1 22 45 22 CC 21 AE 89 WHCN!<."E"!‰ 00000040 AE 55 C2 43 57 48 43 56 D4 28 3C 10 FA 02 AE 49 UCWHCV(<..I 00000050 C2 83 3C 18 8B 20 8B 0C 36 19 D0 3A 8B 22 8B 00 ѓ<.‹ ‹.6.:‹"‹. 00000060 36 19 D0 3A 8B 14 36 19 D0 3A 8B 24 8B 08 36 19 6.:‹.6.:‹$‹.6. 00000070 D0 3A CC 4B 8B 20 8B 06 22 19 3E 10 9B 0E 9B 29 :K‹ ‹.".>.›.›) 00000080 E7 21 CC 4A 3A 0E D4 4A 4E 11 EB 21 CC 4A 3B 0C !J:.JN.!J;. 00000090 D4 4A 4E 11 CC 4C 4E 11 3E 10 9B 2F 9B 0E 36 19 JN.LN.>.›/›.6. 000000A0 D4 5D 5C 8F AE 55 3C 10 8A 08 AE 1D D8 59 8B 00 ]\ЏU<.Љ..Y‹. 000000B0 CC 5B 8A 02 AE 46 AE 4C CC 28 83 23 83 02 AF F0 [Љ.FL(ѓ#ѓ.Ї 000000C0 80 79 80 58 83 2B 83 0A AF F0 81 79 81 58 83 33 ЂyЂXѓ+ѓ.ЇЃyЃXѓ3 000000D0 83 12 AF F0 82 79 82 58 83 21 83 00 AF F0 80 39 ѓ.Ї‚y‚Xѓ!ѓ.ЇЂ9 000000E0 80 18 3C 10 B6 01 CC 5C AE 1D D8 78 8B 00 CC 7A Ђ.<.¶.\.x‹.z 000000F0 8A 02 AE 46 AE 4C CC 5C 57 48 43 58 D4 85 3C 10 Љ.FL\WHCX…<. 00000100 F2 06 F6 0D FA 1C FE 02 AE 49 C2 DF CC BD 3C 00 ....IЅ<. 00000110 46 E8 3C 10 8A 02 AE 55 AE 46 AE 4C CC 85 8A 04 F<.Љ.UFL…Љ. 00000120 79 86 7C 10 3C 18 8C C7 8D C7 8E C7 8F C7 8C 85 y†|.<.ЊЌЋЏЊ… 00000130 AE 22 AE 55 A7 FD A7 F2 AE 46 AE 4C CC 85 3C 18 "U§§FL…<. 00000140 FA 24 8B 20 8B 14 22 19 CC A8 8B 22 8B 1C 2A 19 $‹ ‹.".‹"‹.*. 00000150 3E 10 9B 35 9B 14 36 19 D0 B1 9B 2F 9B 0E 36 19 >.›5›.6.±›/›.6. 00000160 D4 BC 5C 8F AE 55 3C 10 8A 08 AE 1D D8 B9 8B 00 ј\ЏU<.Љ..№‹. 00000170 CC BB 8A 02 AE 46 AE 4C CC 85 A8 F2 88 82 8A 02 »Љ.FL…€‚Љ. 00000180 5C 8F 45 22 3C 18 A8 F2 AE 22 3C 08 45 68 AE 55 \ЏE"<."<.EhU 00000190 AE 46 AE 4C CC 85 57 48 43 58 D4 D1 3C 10 FA 02 FL…WHCX<.. 000001A0 AE 49 C3 83 3C 18 80 BF 80 9E 87 D7 86 CF 85 C7 Iѓ<.ЂїЂћ‡†… 000001B0 87 11 4F 11 80 F9 80 D8 82 A7 82 86 81 A3 81 82 ‡.O.ЂЂ‚§‚†ЃЈЃ‚ 000001C0 AF B6 80 6D 80 4C 81 AB 81 8A AF B6 81 6D 81 4C Ї¶ЂmЂLЃ«ЃЉЇ¶ЃmЃL 000001D0 81 B3 81 92 AF B6 82 6D 82 4C 81 A1 81 80 AF B6 ЃіЃ'Ї¶‚m‚LЃЎЃЂЇ¶ 000001E0 80 2D 80 0C 80 F5 80 D4 CC D1 3C 00 F5 81 CC FC Ђ-Ђ.ЂЂ<.Ѓ 000001F0 3C 10 FA 09 3A 0A D0 FD C1 90 5C 8F 4F A5 FB A1 <..:.ђ\ЏOҐЎ 00000200 CD 02 8A 06 CC FC 4C 5C 8F 44 34 5C D5 0F 8A 0A .Љ.L\ЏD4\.Љ. 00000210 8F A5 5C 8F 8E 21 41 32 AE 4C AE 5A CD 48 12 22 ЏҐ\ЏЋ!A2LZH." 00000220 FA 21 CD 13 5C 8F E9 2B E5 21 CD 48 3C 18 8B 24 !.\Џ+!H<.‹$ 00000230 8B 0E 36 19 D1 1E 3C 10 8A A4 8A 8E CD 48 3E 18 ‹.6..<.Љ¤ЉЋH>. 00000240 9A F1 9A D0 8B E0 8B CE 35 DF D1 2E 8B E2 8B C2 љљ‹‹5.‹‹ 00000250 35 DF D1 34 8B D6 35 DF D1 3A CD 40 8B E4 8B CC 54‹5:@‹‹ 00000260 36 DF D1 48 85 DF CD 48 8B E2 8B C4 36 DF D1 48 6H…H‹‹6H 00000270 85 DF CD 48 8B E2 8B D8 36 DF D1 48 85 DF CD 48 …H‹‹6H…H 00000280 87 CF 88 E0 88 D6 2B C7 36 DF D1 47 29 C7 8C C7 ‡€€+6G)Њ 00000290 AE 46 CC FC 3C 10 FA 0A B6 01 C1 1A 4F 08 D9 53 F<..¶..O.S 000002A0 4C 5C AE 4F CD 54 8A 02 AE 46 CD 4D AE 46 AE 4F L\OTЉ.FMFO 000002B0 3C 10 8C C7 10 02 FC 01 CD 60 8C 00 3E 00 9B 0D <.Њ...`Њ.>.›. 000002C0 ED 38 45 30 10 22 B4 21 CD 66 8C 21 01 18 11 02 8E0."ґ!fЊ!.... 000002D0 B9 00 CD 7E CD 81 CD 84 CD 87 CD 8A CD 8D CD 90 №.~Ѓ„‡ЉЌђ 000002E0 CD 93 CD 96 CD 99 CD 9C CD 9F CD A2 CD A5 CD A8 “–њџўҐ 000002F0 CD AB 41 2E AE 97 CD 7C AF 13 CD 4D AE E2 AE EE «A.—|Ї.M 00000300 CD 7C AE EE AE CA CD 7C AE EE AE E2 CD 7C AE E2 ||| 00000310 AE CA CD 7C AE E2 AE CA CD 7C AE EE AE CA CD 7C ||| 00000320 AE E2 AE EE CD 7C AE EE AE CA CD 7C AE E2 AE EE || 00000330 CD 7C AE E2 AE EE CD 7C AE E2 AE CA CD 7C AE E2 ||| 00000340 AE CA CD 7C AE E2 AE EE CD 7C AE EE AE CA CD 7C ||| 00000350 AE E2 AE EE CD 7C AE E2 AE CA CD 7C 3C 00 F1 81 ||<.Ѓ 00000360 CD B4 3C 10 AE 89 CD BC 3C 10 BA 00 CD BD CD C4 ґ<.‰ј<.є.Ѕ 00000370 CD DA CD F3 CE 08 CD F3 C9 8F 78 23 7D 30 7D 31 .Џx#}0}1 00000380 7D 54 7C 90 AE 0D CD BC 78 00 AE 18 78 07 AE 73 }T|ђ.јx..xs 00000390 AE 12 78 41 AE 7E AB D7 AB D7 7C 90 7D 52 7D 15 .xA~««|ђ}R}. 000003A0 7D 11 7D 14 7D 71 7C 90 7C 90 7C F7 79 86 7C 11 }.}.}q|ђ|ђ|y†|. 000003B0 A7 EF CD BC AE 2D 3C 18 AE 5F AE 52 AE 3A AE 6A §ј-<._R:j 000003C0 AE 3F 3C 10 78 00 AE 73 8B 22 7F F7 78 22 7F F7 ?<.xs‹".x". 000003D0 7F F7 7F F7 7F F7 FB 23 8B 24 78 44 CD E7 78 66 ...#‹$xDxf 000003E0 AE 7E 7F F7 CD BC 78 00 AE 0D 78 06 7D 37 7D 56 ~.јx..x.}7}V 000003F0 7D 15 7D 52 AB D7 AB D7 7D 71 7D 37 7D 55 7D 52 }.}R««}q}7}U}R 00000400 7C 90 AE 12 78 84 AE 7E 79 84 AB E3 A7 EF CD BC |ђ.x„~y„«§ј 00000410 78 23 AE 18 78 40 AE 73 CD BC 7D 17 7D 11 7D 35 x#.x@sј}.}.}5 00000420 7D 15 B0 00 7D 50 7D 37 7D 31 7D 36 7D 54 B0 00 }.°.}P}7}1}6}T°. 00000430 7D 54 7D 31 7D 35 7D 15 B0 00 8B 80 8B 62 8B 42 }T}1}5}.°.‹Ђ‹b‹B 00000440 34 5C B0 00 88 62 88 5C 89 62 89 5C 8A 62 8A 5C 4\°.€b€\‰b‰\ЉbЉ\ 00000450 88 22 88 1C 8A 20 8A 12 B0 00 78 04 A0 AB A0 AB €"€.Љ Љ.°.x. « « 00000460 78 26 A0 AB A0 AB 78 60 A0 AB A0 AB 78 82 A0 AB x& « «x` « «x‚ « 00000470 A0 AB B0 00 3C 10 60 D7 7C B2 3C 18 B0 00 3C 10 «°.<.`|І<.°.<. 00000480 62 95 7D F3 61 D7 7E 74 3C 18 B0 00 3C 00 46 62 b•}a~t<.°.<.Fb 00000490 B0 00 3C 00 42 7C B0 00 3C 00 45 F0 B0 00 3C 00 °.<.B|°.<.E°.<. 000004A0 46 70 B0 00 62 11 7F F5 B0 00 3C 00 EE A1 CE 59 Fp°.b..°.<.ЎY 000004B0 5C 4F B0 00 3C 00 EE A1 CE 5E 5D 0F B0 00 60 D7 \O°.<.Ў^].°.` 000004C0 7F F2 61 D7 7F F2 62 D7 7F F2 63 D7 7F F2 60 95 .a.b.c.`• 000004D0 7F F2 B0 00 60 53 7C F6 61 53 7C F6 62 53 7C F6 .°.`S|aS|bS| 000004E0 60 11 7C F6 B0 00 F0 81 CE 7A 7C 90 F0 61 CE 7B `.|°.Ѓz|ђa{ 000004F0 7C 90 CE 7C 6C 80 6C 60 6C 40 B0 00 F1 81 CE 85 |ђ|lЂl`l@°.Ѓ… 00000500 7C 90 F1 61 CE 86 7C 90 CE 87 6D 80 6D 60 6D 40 |ђa†|ђ‡mЂm`m@ 00000510 B0 00 8C C7 8D C7 8E 85 5C 8F 41 30 A7 EF AE 46 °.ЊЌЋ…\ЏA0§F 00000520 AE 4C 45 E8 3C 08 41 60 41 40 41 20 B0 00 3C 18 LE<.A`A@A °.<. 00000530 82 A7 82 86 AE B2 80 F5 80 D4 82 AF 82 8E AE B2 ‚§‚†ІЂЂ‚Ї‚ЋІ 00000540 81 F5 81 D4 82 B7 82 96 AE B2 82 F5 82 D4 82 BF ЃЃ‚·‚–І‚‚‚ї 00000550 82 9E AE B2 83 F5 83 D4 82 A5 82 84 AE B2 80 B5 ‚ћІѓѓ‚Ґ‚„ІЂµ 00000560 80 94 B0 00 8B A0 8B 80 36 9D D2 C8 8B A0 8B 88 Ђ”°.‹ ‹Ђ6ќ‹ ‹€ 00000570 36 9D D2 C8 8B A0 8B 9C 36 9D D2 C8 8B A2 8B 90 6ќ‹ ‹њ6ќ‹ў‹ђ 00000580 36 9D D2 C8 8B A4 8B 84 36 9D D2 C8 4E 95 CE C9 6ќ‹¤‹„6ќN• 00000590 8E 85 B0 00 3C 18 3E 10 80 33 80 12 86 4B 85 43 Ћ…°.<.>.Ђ3Ђ.†K…C 000005A0 9B 01 BB 00 CE D6 CE D9 CE DC CE DF 88 60 88 48 ›.».€`€H 000005B0 CE E1 88 60 88 5C CE E1 88 62 88 50 CE E1 88 64 €`€\€b€P€d 000005C0 88 44 B0 00 3C 18 81 A3 81 82 AE FA 80 6D 80 4C €D°.<.ЃЈЃ‚ЂmЂL 000005D0 81 B3 81 92 AE FA 82 6D 82 4C B0 00 3C 18 81 AB ЃіЃ'‚m‚L°.<.Ѓ« 000005E0 81 8A AE FA 81 6D 81 4C 81 A1 81 80 AE FA 80 2D ЃЉЃmЃLЃЎЃЂЂ- 000005F0 80 0C B0 00 8B A2 8B 9C 35 9D D3 10 8B A0 8B 92 Ђ.°.‹ў‹њ5ќ.‹ ‹' 00000600 35 9D D3 10 8B A2 8B 86 35 9D D3 10 8B A2 8B 9A 5ќ.‹ў‹†5ќ.‹ў‹љ 00000610 35 9D D3 10 8B A4 8B 8E 35 9D D3 10 4D 85 CF 12 5ќ.‹¤‹Ћ5ќ.M…. 00000620 89 A2 89 9C B0 00 3C 18 81 A3 81 82 82 A7 82 86 ‰ў‰њ°.<.ЃЈЃ‚‚§‚† 00000630 AF B6 80 F5 80 D4 82 AF 82 8E AF B6 81 F5 81 D4 Ї¶ЂЂ‚Ї‚ЋЇ¶ЃЃ 00000640 82 B7 82 96 AF B6 82 F5 82 D4 82 BF 82 9E AF B6 ‚·‚–Ї¶‚‚‚ї‚ћЇ¶ 00000650 83 F5 83 D4 82 A5 82 84 AF B6 80 B5 80 94 80 6D ѓѓ‚Ґ‚„Ї¶ЂµЂ”Ђm 00000660 80 4C 83 23 83 02 AF F0 80 79 80 58 3C 10 B6 02 ЂLѓ#ѓ.ЇЂyЂX<.¶. 00000670 3C 18 CF 3B CF AF 81 AB 81 8A 82 A7 82 86 AF B6 <.;ЇЃ«ЃЉ‚§‚†Ї¶ 00000680 80 F5 80 D4 82 AF 82 8E AF B6 81 F5 81 D4 82 B7 ЂЂ‚Ї‚ЋЇ¶ЃЃ‚· 00000690 82 96 AF B6 82 F5 82 D4 82 BF 82 9E AF B6 83 F5 ‚–Ї¶‚‚‚ї‚ћЇ¶ѓ 000006A0 83 D4 82 A5 82 84 AF B6 80 B5 80 94 81 6D 81 4C ѓ‚Ґ‚„Ї¶ЂµЂ”ЃmЃL 000006B0 83 2B 83 0A AF F0 81 79 81 58 3C 10 B6 02 3C 18 ѓ+ѓ.ЇЃyЃX<.¶.<. 000006C0 CF 62 CF AF 81 B3 81 92 82 A7 82 86 AF B6 80 F5 bЇЃіЃ'‚§‚†Ї¶Ђ 000006D0 80 D4 82 AF 82 8E AF B6 81 F5 81 D4 82 B7 82 96 Ђ‚Ї‚ЋЇ¶ЃЃ‚·‚– 000006E0 AF B6 82 F5 82 D4 82 BF 82 9E AF B6 83 F5 83 D4 Ї¶‚‚‚ї‚ћЇ¶ѓѓ 000006F0 82 A5 82 84 AF B6 80 B5 80 94 82 6D 82 4C 83 33 ‚Ґ‚„Ї¶ЂµЂ”‚m‚Lѓ3 00000700 83 12 AF F0 82 79 82 58 3C 10 B6 02 3C 18 CF 89 ѓ.Ї‚y‚X<.¶.<.‰ 00000710 CF AF 81 A1 81 80 82 A7 82 86 AF B6 80 F5 80 D4 ЇЃЎЃЂ‚§‚†Ї¶ЂЂ 00000720 82 AF 82 8E AF B6 81 F5 81 D4 82 B7 82 96 AF B6 ‚Ї‚ЋЇ¶ЃЃ‚·‚–Ї¶ 00000730 82 F5 82 D4 82 BF 82 9E AF B6 83 F5 83 D4 82 A5 ‚‚‚ї‚ћЇ¶ѓѓ‚Ґ 00000740 82 84 AF B6 80 B5 80 94 80 2D 80 0C 83 21 83 00 ‚„Ї¶ЂµЂ”Ђ-Ђ.ѓ!ѓ. 00000750 AF F0 80 39 80 18 3C 10 B6 02 3C 18 CF B5 AE 1D ЇЂ9Ђ.<.¶.<.µ. 00000760 DB B3 8B 00 CF B4 8A 02 AE 4C B0 00 35 95 D7 EE і‹.ґЉ.L°.5• 00000770 3E 10 90 ED 90 CC 89 A2 89 9C 8E 85 3C 00 EE A1 >.ђђ‰ў‰њЋ…<.Ў 00000780 CF C2 5C 4F CF C3 3C 10 4D 4C 8B 80 8B 6A 8B 40 \O<.ML‹Ђ‹j‹@ 00000790 35 5C DB EE D7 D5 8B 66 24 5C 45 24 8E 21 3C 00 5\‹f$\E$Ћ!<. 000007A0 EE A1 CF D3 5D 0F CF D4 CF EE 8B 82 8B 60 35 5C Ў].‹‚‹`5\ 000007B0 D7 EE 8B 80 8B 66 24 5C 45 28 8E 21 3C 00 EE A1 ‹Ђ‹f$\E(Ћ!<.Ў 000007C0 CF E2 5D 0F CF E3 3C 18 8B 24 8B 0C 36 19 3C 10 ].<.‹$‹.6.<. 000007D0 D3 EC 89 E4 89 CC CF EE 89 E2 89 D6 3C 18 B0 00 ‰‰‰‰<.°. 000007E0 36 19 D7 FD 8B 22 8B 1C 3C 00 EE A1 CF F8 5C 4F 6.‹"‹.<.Ў\O 000007F0 CF F9 3C 10 8A 08 5C 8F 8E 21 3C 18 B0 00 03 00 <.Љ.\ЏЋ!<.°...
If I had previously programmed AVR controllers in assembler, I would immediately have taken the first 14 pairs of bytes for the interrupt vector table, but I did not program the AVR in assembler, so I thought it was just some sort of subroutine call, i.e. suggested that:
instructions take 2 bytes (this is also obvious because even bytes are often repeated, and odd ones are much more random);
opcode is in the first byte, and the operands in the second and, most likely, partially in the first;
instructions like 0xC *** is a CALL command with a subroutine address.
After these 28 bytes is a pair of 0xB000 , the same instruction is found further throughout the program, including at the very end (not counting the last two bytes, which turned out to be just a kind of program index in ROM), I assumed that this is a return from the subroutine, the command RET .
This is all that I understood from binary files after the first swoop, even before the arrival of hours. I tried to find string constants, but, to my surprise, I couldn’t find anything like the necessary sequences of character codes.
Then I tried to enter from the other side and began to watch the instruction sets of all 4-bit microprocessors and microcontrollers of the 70-80s in a row that Google could reach - nothing like that. I, in my opinion, never met a single 4-bit processor with double-byte instructions of constant length. There was some hope for modern 4-bit controllers from Epson, I thought that their system of commands could go back to the beginning of the 80s, but no, and there is nothing. As a result, it was decided to wait for the clock and act by typing.
The clock arrived, quickly assembled such a transmitter:
It didn’t work with the coil from the first transformer that turned up, or rather it worked only without the watch’s back cover, with the second coil turned up it was possible to get a stable transmission. To download programs, I used a slightly modified application published on sigma957.org . Subsequently, I wrapped the coil and assembled the transmitter on the ATtiny85, more suitable for practical use:
Another way to interact with the clock using the phone
When I did the transmitters, I noticed that the clock in principle can receive data at half the lower frequency - 16384 Hz, although the percentage of errors increases dramatically. This suggested an idea that at first seemed insane: to use the phone’s speaker as a coil to transfer data to the watch. To my surprise, there was no limit when the idea turned out to be quite workable, here’s a video of the resulting program that fully emulates the operation of a compact keyboard:
Of course, the percentage of errors is large, about 10-20%, therefore, without feedback, there is no possibility to transfer the application. But, for example, you can adjust the contrast in the absence of a normal keyboard (after changing the battery, it is always up to the point that it is impossible to use the clock). Well, it works far from all phones, I tested it on the Nexus 5X - excellent, Galaxy S8 - bad, Nexus 5 - very bad, only individual bytes pass.
First of all, I played with all the standard applications, then I started replacing suspicious instructions with 0x0000 (then I mistakenly assumed that it was a NOP) and literally after a couple of replacements I came across a plot with text output. I added two instructions to the piggy bank, setting the cursor position:
0111 10ii iii0 0iii, i - ,
and directly output the character:
0111 11ii iii1 0iii, i -
It was because of this interesting arrangement of bits that it turned out that I could not find the lines right away. I was in seventh heaven, I immediately wrote “Hello world”, which worked somehow strangely because I did not understand the purpose of the jump table in the heading, but it was already something.
Then I figured out the addressing of the CALL command - it turned out that the subroutines that call such instructions from the header do not end in RET, as one would expect, but they end in calls to the subroutines from the ROM. It turns out, I was mistaken, instructions like 0xC *** are more like an unconditional jump of JMP A :
0011 AAAA AAAA AAAA, A - ,
and the CALL A subroutine call was the instruction:
1010 AAAA AAAA AAAA
Then the process again stalled. It was already possible to divide the program into separate blocks, the functions of which were generally understood, for example, it was possible to determine exactly that such a set of instructions displays the score in the HIT game, but I could not understand what each instruction was doing.
Having put down the hexes for a couple of days, I decided to use the good old method - throwing everything out of the program that does not break it, thus simplifying it as much as possible, and at the same time studying what breaks. For preparation, I chose the Scheduler program, it has a minimum size (the code takes only 2/3, the remaining space is used to store the 31st note by 20 characters) and it looked simpler than the others.
Such tactics immediately began to bear fruit. Having found the subroutines for handling keystrokes, it became clear that the table in the heading is transitions to the addresses of event handlers (not interrupts), I haven’t figured out this table until now, that's what I know by now:
Index in title
Description
Standard handler address
0
Application launch
0x227
one
Second timer
0x190
2
-
0x11A
3
-
0x109
four
-
0x0E0
five
Pressing the Mode Button
0x243
6
Pressing the Transmit button
0x283
7
Right click
0x2DF
eight
Left click
0x383
9
-
0x2A9
ten
-
0x307
eleven
Received bytes per coil
0x39C
12
-
0x09B
13
I did not fully understand it, but screen redrawing is usually implemented in the handler.
0x98F
14
On the external keyboard, the APL button is pressed (application launch)
-
Thanks to the same button handlers with which the user chose the desired note, he identified addition and subtraction instructions - 0x221A and 0x2A1A , although without understanding the operands. Then one of the conditional transitions was identified, again without operands.
At the same time, the program almost completely retained the functionality of working with notes. As I later understood, blocks of input of notes from the keyboard, various checks for boundary conditions and the like “redundant” code were cut out. I shuffled the remaining subroutines into a convenient for work and compact form, the benefit of the transition instructions I already knew. Compactness, by the way, was very relevant, since transfer of 2048 bytes to the clock takes about 30 seconds. Imagine the process - reset two bytes, send to the clock, wait 30 seconds, see what happened - if everything breaks badly, then return the instruction, if it does not break, we look for the next victim and again 30 seconds. Slowly, very slowly. Therefore, with Scheduler reduced to 512 bytes, the work went much faster.
Further stick poking led to the understanding that instructions 0x8AE4 0x8ADC 0x8AA0 in the program launch handler set the address of the current note, I interpreted them as loading the immediate value into the LDI R, I register
1000 10RR RRRi iii-, R - , i -
Now it became clear that we have 32 four-bit registers, besides, instructions 0x3C00 , 0x3C08 , 0x3C10 , 0x3C18 wereeverywhere , according to some signs, I accepted the choice of the current bank of registers, which was later confirmed. Total, we have 4 banks in 32 registers. Finding the registers was one of the key points, after which I really believed in the possibility of disassembling the programs of these watches.
Located near 0x8257 0x8236 0x8215 turned out to be instructions to copy the registers MOV Rd, Rs
1000 00dd ddds ssss, d - , s -
After that, I could not easily figure out the operands of the previously found addition and subtraction operations; these turned out to be operations on the ADM register groups Rd, Rs and SBM Rd, Rs (M - from Multiple). These instructions, operating with groups of registers, showed that each bank of registers is divided into another 4 pages with 8 registers. Each instruction operating with register groups can operate with any number of registers within a page, and the indices of the initial and final register of the group must be the same for both operands. I probably explain not quite clearly, so I will try again in the picture:
It turns out that some commands can operate with 4-byte values at once - not bad for a four-bit processor. For ease of use of group commands, I decided to name the registers as RA0, RA1 ... RA7, RB0, RB1, etc. etc.
So, in general, the syntax of the instructions has become approximately clear, it remains the case of technology - to formally describe as many instructions as possible. To do this, first, I made a list of all instructions from the regular programs in binary form and divided it into groups of six first bits, so you could immediately figure out what data the command operates, for example, if the right bit in the group is always 0, then almost certainly the second operand is an immediate value. Secondly, by this time I already knew enough instructions to write a program for clocks in machine codes that would display the current values of the registers of all banks - press one button - the values of the registers of the 0th bank are displayed, the other of the 1st and others . It was my first useful program for UC-2000!
Content of the zero register bank
In the process of writing this program, I caught some terrible glitches with the value of the zero register of each bank and could not understand what was wrong. As it turned out, the reason was that I used 0x0000 as the NOP, and in fact this is the addition command of the registers, i.e. I constantly in different places folded the zero register with myself).
With these two tools, in a couple of days I have formally described over 40 instructions. A lot of time was taken away by instructions with non-standard syntax, such as INC and DEC. Even more time was taken by the instruction with opcode 010101 , which was always the first in button handlers and was found in some other places. As it turned out, she copied the value to the current bank's register from some group of registers, which I called the I / O registers. It was empirically established that there are only 16 of these registers, a description of the purpose of those that I managed to understand in the following table:
Register
Description
IO0
The 0th bit is set if the left or right button is pressed; 2nd - the MODE or TRANSMIT button is pressed; 3rd - received bytes per coil
IO1
Receive Data Flag
IO2
Transmission error flag
IO3
-
IO4
-
IO5
Senior nibble taken on a coil
IO6
Junior Nibble Taken by the Coil
IO7
Button interrupt flags, 0th bit - left button, 1st - right. 2nd - MODE, 3rd - TRANSMIT
IO8
Flags of pressed buttons, the same sequence as in IO7
IO9
-
IO10
-
IO11
-
IO12
-
IO13
-
IO14
1/16 second counter
IO15
Also, using the register value mapping program, I found out that the first two banks of registers are used by the internal clock program, therefore, for obvious reasons, it is better to use only 2 and 3 banks as general registers.
The purpose of the registers of the 0th bank:
Register
Description
RA0
Current minutes, low order, BCD
RA1
Current minutes, high order, BCD
RA2
The current hour in 12-hour format
RA3
12-hour interval, 0 - AM, 1 - PM
RA4
Current date, low order, BCD
RA5
Current date, high order, BCD
RA6
Current month
RA7
The current day of the week. 0 - Sunday and beyond
RB0
Minutes of the alarm, low order, BCD
RB1
Minutes of the alarm, senior level, BCD
RB2
Alarm clock in 12-hour format
RB3
0th bit - AM / PM alarm, 1st - on / off
RB4
Current mode, 0 - clock, 1 - downloadable program and further, alarm clock, stopwatch, time setting, data transfer
RA5
Current seconds, low order, BCD
RA6
Current seconds, high order, BCD
RA7 ... RD7
-
In the 1st bank, only the registers RB0 - RB3 are interesting, they are used to indicate events to which the loaded program will respond. The remaining registers of this bank are used differently in different operating modes of the clock, so I did not analyze them (although, of course, there may be something interesting)
The result of all this work was a set of 61 formally described instructions. Unfortunately, I was not able to restore everything that can be seen from the table (which is just below under the spoiler), there is a gap in the interval of 5800-5BFF, maybe one or even several instructions were hidden there. There are very specialized commands, such as peep with piezo dynamics, most likely, there is something more behind them, I did not even give names to such instructions. Questionable NOP. In many instructions there are insignificant bits labeled by me as "-", in fact, of course, some may influence something that I have missed.
Instruction set
A lot of time was spent on selecting suitable mnemonics, some teams were called rather ugly (especially in the middle of the table), I myself constantly forgot them.
Then I came close to the ability to write applications, but for this I needed an assembler, writing something harder to view register values in machine codes when the size of opcodes and operands is not a multiple of a byte, to put it mildly, is not convenient.
Assembler
I naively assumed that there are ready-made implementations of universal assemblers, the once heard phrase “tabular assembler” was spinning around in my head, which I started to google. It turned out yes, indeed, there is such a class of assemblers, called the “table driven assembler”, but I could not find anything suitable - these were either long-abandoned products from the 90s of the TDASM type, or modern highly limited projects “on the knee”. And it would be all nothing, but all these tabular assemblers had a serious drawback - they each had their own notation, which perfectly described the instructions of processors from the supported list, but did not want to describe the set of UC-2000 instructions: some simply could not work with operands multiple bytes, some could not address both bytes and two-byte commands, etc.
I was already inclined to write my extremely simple assembler, but I came across axasm ( an article describing the author). Briefly, the macro-substitutions C are used to describe the instructions, due to which a great versatility is obtained, and all the code analysis is placed on the preprocessor, we just have to convert the MOV Rd, Rs code into MOV (Rd, Rs), for The author uses AWK for this, and the entire process is automated by a Bash script. At the same time, of course, this method has drawbacks - it’s impossible to hang several instructions on one assembler command, under Windows you have to use MinGW (although you can rewrite everything, of course, but I was lazy), well, in general, all this is rather cumbersome.
So, I made the description of the commands known to me for axasm and it went much better, all I needed was a disassembler for convenient parsing of standard applications, which I quickly corrected by writing my very simple but fully functional one. By that time I had already described most of the instructions, and it was possible to start writing something “serious”.
Of course, I had no illusions about the capabilities of the 4-bit processor in the 83rd electronic clock, but I was still unpleasantly surprised by the seemingly elementary command lack:
There is no bit shift! In no way. It seems to be a basic operation, the absence of which complicates a lot. The left shift, for example, can be replaced by adding the register to itself, but what can we replace the right shift? (
There is no logical operation on two registers! AND, OR and XOR are only register with immediate value. What is really there, not even denial.
No team can use indirect addressing of registers, it is probably not very surprising, but very inconvenient.
The stack depth of the subroutine call is only 3 levels, this is also not surprising, but I, who were not used to such restrictions, at first caught incomprehensible program hangs and could not understand for a long time what the matter was.
Here, for example, how I had to be perverted to implement the disjunction of the two registers RA0, RA1:
But each instruction takes us 2 bytes from 2048, a nightmare.
But all arithmetic commands have analogues with decimal correction. This suggests that the microprocessor was originally developed and used by Seiko-Epson engineers for something like a clock with a calculator function and was later adapted for the UC-2000.
Another unpleasant surprise, for me, was the lack of access to individual pixels of the display, although photos of the clock, which show that time is displayed with non-standard characters of numbers that take up two familiarities at once, seemed to hint at this possibility. However, as soon as I saw the symbol table , there were no illusions left - the halves of the numbers are just separate characters. Therefore, for Tetris, we had to use pseudographic characters, since they are enough to use the characters "█", "▀", "" and "" to split the screen into 8x10 "pixels", the playing field turns out like this:
The “glass” is rotated and occupies the entire screen, but even so, of course, it is not much enough down to the classic 10x20 cells.
In spite of this limited set of instructions, Tetris fit in 700 bytes, although, when I started it, I feared that I would not fit in 2 KB.
Source code with comments
; ##define brdAdr RA2 ##define brdValTop RA3 ##define brdValBtm RA4 ##define ind RA5 ##define drawLine RA6 ##define appState RA7 ##define curLine RB0 ;9, 10 ##define preLine RB3 ##define scoresL RB4 ;13, 14 ##define scoresH RB7 ##define piceAngle RC0 ##define piceNum RC1 ##define piceSelecter RC2 ##define piceShift RC3 ##define scoresAddL RC4 ;21;22 ##define scoresAddH RC7 ##define curPosL RC4 ##define curPosH RC5 ##define piceLn0t RD0 ##define piceLn0b RD1 ##define piceLn1t RD2 ##define piceLn1b RD3 ##define piceLn2t RD4 ##define piceLn2b RD5 ##define piceLn3t RD6 ##define piceLn3b RD7 ; ##define brdAdr2b (((board*2)>>8) & 0x0F) ##define brdAdr1b (((board*2)>>4) & 0x0F) ##define brdAdr0b (((board*2) ) & 0x0F) ; ##define picesAdr2b (((pices*2)>>8) & 0x0F) ##define picesAdr1b (((pices*2)>>4) & 0x0F) ##define picesAdr0b (((pices*2) ) & 0x0F) ORG 0 ; JMP start ; JMP timer JMP 0x11A ; JMP 0x109 JMP 0x0E0 JMP btn_mode JMP btn_transm JMP btn_right JMP btn_left JMP 0x2A9 JMP 0x307 JMP 0x39C JMP 0x09B JMP update_screen RET ; start: CLRM RB1, RB3%8 LDI RB2, 0xF ; 4- LCRB B2 LDI appState, 1 JMP 0x227 ; ; MODE btn_mode: CPJR RB3, 0, btn_mode_startapp ; , CLRM RB1, RB3%8 ; "" JMP 0x243 btn_mode_startapp: LDI RB3, 8 ; LDI RB1, 1 ; JMP 0x243 ; TRANSMIT btn_transm: LARB B3 LCRB B2 ADI piceAngle, 4 ; JMP update_screen ; btn_right: LARB B3 LCRB B2 CPJR appState, 2, btn_right_c1 CALL prepareNewGame JMP 0x2DF btn_right_c1: INC piceShift, piceShift%8 ; JMP 0x2DF ; btn_left: LARB B3 LCRB B2 DEC piceShift, piceShift%8 ; JMP 0x383 ; timer: LARB B3 LCRB B2 CPJR appState, 2, timer_draw CPJR appState, 3, timer_clear_lines_screen JMP 0x190 timer_clear_lines_screen: LDI appState, 2 ; JMP update_screen timer_draw: INC curLine, curLine%8 ; JMP update_screen update_screen: LARB B3 LCRB B2 CPJR appState, 2, update_screen_draw PLAI 125 ; STLI 0 ; CPJR appState, 0, update_screen_gover CPJR appState, 3, update_screen_clear_lines update_screen_start: PLAI 12 PSAI STR_TETRIS ; TETRIS CALL OS_PRINT0-6 ; JMP 0x98F update_screen_gover: PLAI 10 ;GAME OVER PSAI STR_GAMEOVER CALL OS_PRINT0-10 JMP update_screen_print_scores update_screen_clear_lines: PLAI 10 ; PSAI STR_SCORE ; CALL OS_PRINT0-8 STL scoresAddL+1 STL scoresAddL PSAI STR_TOTAL update_screen_print_scores: CALL OS_PRINT0-6 ; Total STL scoresH ; STL scoresH-1 ; STL scoresH-2 ; STL scoresL ; JMP 0x98F update_screen_draw: CALL updatePice ; CALL draw ; JMP 0x98F ; prepareNewGame: CALL OS_CLRCB LDI appState, 2 LDI brdAdr, brdAdr2b LDI brdAdr-1, brdAdr1b LDI brdAdr-2, brdAdr0b PSAM brdAdr-2, brdAdr%8 CLRM scoresL, scoresH%8 CLRM brdValTop, brdValBtm%8 LDI ind, 10 prepareNewGame_loop: STSM brdValTop, brdValBtm%8 DEC ind, ind%8 JNC prepareNewGame_loop ; prepareNewPice: CLRM curLine, preLine%8 LDI piceShift, 2 prepareNewPice_random: IN piceAngle, 14 ADD piceNum, piceAngle CPI piceNum, 7 JNC prepareNewPice_random LDI piceAngle, 0 CMP scoresAddL, scoresAddL+1 JZ updatePice ADBM scoresL, scoresAddH LDI appState, 3 JMP update_screen ; updatePice: LDI brdAdr, picesAdr2b LDI brdAdr-1, picesAdr1b LDI brdAdr-2, picesAdr0b ADM brdAdr-2, piceSelecter PSAM brdAdr-2, brdAdr%8 LDSM piceLn0t, piceLn0b%8 LDSM piceLn1t, piceLn1b%8 LDSM piceLn2t, piceLn2b%8 LDSM piceLn3t, piceLn3b%8 ; - shiftPice: MOV ind, piceShift shiftPice_loop: CPJR ind, 0, shiftPice_end ADM piceLn0t, piceLn3b ; BTJR piceLn1t, 0, +4 ; BTJR piceLn2t, 0, +3 ; BTJR piceLn3t, 0, +2 ; DEC ind, ind%8 JMP shiftPice_loop JMP processCollision shiftPice_end: CPI preLine, 15 JNZ checkCollision ; board storePice: LDI brdAdr, brdAdr2b LDI brdAdr-1, brdAdr1b LDI brdAdr-2, brdAdr0b ADM brdAdr-2, curLine+2 CLRM scoresAddL, scoresAddH%8 LDI ind, 3 storePice_loop: PSAM brdAdr-2, brdAdr%8 LDSM brdValTop, brdValBtm%8 XORI piceLn0t, 0xF ; OR XORI piceLn0b, 0xF BTJR piceLn0t, 0, +1 ORI brdValTop, 1 BTJR piceLn0t, 1, +1 ORI brdValTop, 2 BTJR piceLn0t, 2, +1 ORI brdValTop, 4 BTJR piceLn0t, 3, +1 ORI brdValTop, 8 BTJR piceLn0b, 0, +1 ORI brdValBtm, 1 BTJR piceLn0b, 1, +1 ORI brdValBtm, 2 BTJR piceLn0b, 2, +1 ORI brdValBtm, 4 BTJR piceLn0b, 3, +1 ORI brdValBtm, 8 PSAM brdAdr-2, brdAdr%8 STSM brdValTop, brdValBtm%8 CMP piceLn0t, piceLn0b ; JZ storePice_loop2_end CPI brdValTop, 0xF JNZ storePice_loop2_end CPI brdValBtm, 0xF JNZ storePice_loop2_end MVACM brdAdr-2, brdAdr%8 ADBM scoresAddL, scoresAddH ; INCB scoresAddL, scoresAddH%8 ; storePice_loop2: DEC brdAdr-2, brdAdr%8 ; PSAM brdAdr-2, brdAdr%8 LDSM brdValTop, brdValBtm%8 STSM brdValTop, brdValBtm%8 CPJR brdValBtm, 0, +1 JMP storePice_loop2 CPJR brdValTop, 0, +1 JMP storePice_loop2 MVCAM brdAdr-2, brdAdr%8 storePice_loop2_end: LSHM piceLn3b, 0 LSHM piceLn3b, 0 INC brdAdr-2, brdAdr%8 DEC ind, ind%8 JNC storePice_loop JMP prepareNewPice ; checkCollision: LDI brdAdr, brdAdr2b LDI brdAdr-1, brdAdr1b LDI brdAdr-2, brdAdr0b ADM brdAdr-2, curLine+2 PSAM brdAdr-2, brdAdr%8 MVACM piceLn0t, piceLn3b LDI ind, 4 checkCollision_loop: LDSM brdValTop, brdValBtm%8 checkCollision_loop2: CMP piceLn0t, piceLn0b JZ checkCollision_end2 ADM piceLn0t, piceLn0b JC checkCollision_compare ADM brdValTop, brdValBtm JMP checkCollision_loop2 checkCollision_compare: ADM brdValTop, brdValBtm JC processCollision JMP checkCollision_loop2 checkCollision_end2: LSHM piceLn3b, 0 LSHM piceLn3b, 0 DEC ind, ind%8 JNZ checkCollision_loop MVCAM piceLn0t, piceLn3b MVACM piceAngle, piceShift ; MOV preLine, curLine ; RET ; processCollision: CPJR curLine, 0, gameOver CMP curLine, preLine JZ processCollision_pre MOV curLine, preLine ; LDI preLine, 15 ;, processCollision_pre: MVCAM piceAngle, piceShift ; JMP updatePice ; gameOver: LDI appState, 0 JMP update_screen ; draw: LDI brdAdr, brdAdr2b LDI brdAdr-1, brdAdr1b LDI brdAdr-2, brdAdr0b PSAM brdAdr-2, brdAdr%8 ; MVAC curLine, curLine ; LDI curPosL, 0xE ; LDI curPosH, 0x1 ; 4 LDI ind, 0 draw_loop0: ; [...] LDSM brdValTop, brdValBtm%8 ; brdValTop brdValBtm , ; CMP curLine, ind ; JNZ draw_ORend XORI piceLn0b, 0xF ; OR XORI piceLn0t, 0xF BTJR piceLn0b, 0, +1 ORI brdValBtm, 1 BTJR piceLn0b, 1, +1 ORI brdValBtm, 2 BTJR piceLn0b, 2, +1 ORI brdValBtm, 4 BTJR piceLn0b, 3, +1 ORI brdValBtm, 8 BTJR piceLn0t, 0, +1 ORI brdValTop, 1 BTJR piceLn0t, 1, +1 ORI brdValTop, 2 BTJR piceLn0t, 2, +1 ORI brdValTop, 4 BTJR piceLn0t, 3, +1 ORI brdValTop, 8 LSHM piceLn3b, 0 ; , LSHM piceLn3b, 0 ; , piceLn0t-piceLn0b CMP piceLn0t, piceLn0b JZ draw_ORend INC curLine, curLine%8 draw_ORend: CPJR ind, 0, draw_b1 draw_loop1: ;[...] PLAM curPosL, curPosH%8 ; BTJR brdValBtm, 2, +5 BTJR brdValBtm, 3, +2 STLI 0x20 ; JMP draw_else2 STLI 0xE8 ; JMP draw_else2 BTJR brdValBtm, 3, +2 STLI 0xE7 ; JMP draw_else2 STLI 0xFF ; draw_else2: ADM brdValTop, brdValBtm ; 2 ADM brdValTop, brdValBtm ;.. 2 SBI curPosL, 0xA ; JNC draw_loop1 ;4- DEC curPosH, curPosH%8 ; 10 JNC draw_loop1 ; ( ) LDI curPosH, 0x1 ; , ADI curPosL, 0x9 ; 4 JNC draw_b1 ; INC curPosH, curPosH%8 ; draw_b1: INC ind, ind%8 ; CPI ind, 11 ; JNZ draw_loop0 MVCA curLine, curLine ; curLine RET ; STR_TETRIS: DS "TETRIS" STR_GAMEOVER: DS "GAME OVER!" STR_SCORE: DS "Score +" STR_TOTAL: DS "Total " ; , board: DB 0b00000000 DB 0b00000000 DB 0b00000000 DB 0b00000000 DB 0b00000000 DB 0b00000000 DB 0b00000000 DB 0b00000000 DB 0b00000000 DB 0b00000000 DB 0b00000000 DB 0b11111111 ; ;, , : ; 3 ( 3- ), ; , 4 , ; . ; . pices: DB 0b00000000 ;o 0° DB 0b00000011 DB 0b00000011 DB 0b00000000 DB 0b00000000 ;o 90° DB 0b00000011 DB 0b00000011 DB 0b00000000 DB 0b00000000 ;o 180° DB 0b00000011 DB 0b00000011 DB 0b00000000 DB 0b00000000 ;o 270° DB 0b00000011 DB 0b00000011 DB 0b00000000 DB 0b00000000 ;I 0° DB 0b00001111 DB 0b00000000 DB 0b00000000 DB 0b00000001 ;I 90° DB 0b00000001 DB 0b00000001 DB 0b00000001 DB 0b00000000 ;I 180° DB 0b00001111 DB 0b00000000 DB 0b00000000 DB 0b00000001 ;I 270° DB 0b00000001 DB 0b00000001 DB 0b00000001 DB 0b00000000 ;s 0° DB 0b00000011 DB 0b00000110 DB 0b00000000 DB 0b00000010 ;s 90° DB 0b00000011 DB 0b00000001 DB 0b00000000 DB 0b00000000 ;s 180° DB 0b00000011 DB 0b00000110 DB 0b00000000 DB 0b00000010 ;s 270° DB 0b00000011 DB 0b00000001 DB 0b00000000 DB 0b00000000 ;z 0° DB 0b00000110 DB 0b00000011 DB 0b00000000 DB 0b00000001 ;z 90° DB 0b00000011 DB 0b00000010 DB 0b00000000 DB 0b00000000 ;z 180° DB 0b00000110 DB 0b00000011 DB 0b00000000 DB 0b00000001 ;z 270° DB 0b00000011 DB 0b00000010 DB 0b00000000 DB 0b00000000 ;L 0° DB 0b00000111 DB 0b00000100 DB 0b00000000 DB 0b00000010 ;L 90° DB 0b00000010 DB 0b00000011 DB 0b00000000 DB 0b00000001 ;L 180° DB 0b00000111 DB 0b00000000 DB 0b00000000 DB 0b00000011 ;L 270° DB 0b00000001 DB 0b00000001 DB 0b00000000 DB 0b00000000 ;J 0° DB 0b00000111 DB 0b00000001 DB 0b00000000 DB 0b00000001 ;J 90° DB 0b00000001 DB 0b00000011 DB 0b00000000 DB 0b00000100 ;J 180° DB 0b00000111 DB 0b00000000 DB 0b00000000 DB 0b00000011 ;J 270° DB 0b00000010 DB 0b00000010 DB 0b00000000 DB 0b00000000 ;T 0° DB 0b00000111 DB 0b00000010 DB 0b00000000 DB 0b00000010 ;T 90° DB 0b00000011 DB 0b00000010 DB 0b00000000 DB 0b00000010 ;T 180° DB 0b00000111 DB 0b00000000 DB 0b00000000 DB 0b00000001 ;T 270° DB 0b00000011 DB 0b00000001 DB 0b00000000 END
Bottom line: after a little over three weeks, after receiving the parcel with the clock, I was already able to play Tetris on UC-2000:
In the process of writing Tetris, it became clear that event handlers are always called as long as they are listed in the registers RB0-RB3 of the second bank (I spoke about them above), regardless of whether the program is running or not. Because of this, you can completely redo the functionality of the clock, just by drawing what you need on top of the regular modes. To demonstrate this, I wrote a program that adds 6 additional ones to the default dial, switching between them by a combination of the left button + MODE. At the same time, additional dials organically fit into the work of the other functions of the watch:
One of the most popular features of modern smart watches - user dials, was potentially available as early as the year 83, amazing! It is strange that Seiko did not develop this direction. And in general, it is a little insulting that the potential of these watches has not been fully disclosed. Although, of course, there is nothing strange in this, from 2017 everything looks completely different from the 83rd. Especially, if you remember how many not very successful attempts to invent smart watches were after them. But this, as they say, is another story.