JavaScriptによるZ80エミュレータでの「手抜き」回転行列

[2018年10月9日の日記](https://srad.jp/~yasuoka/journal/624453/)にも書いたが、40年前の私(安岡孝一)は、Z80における「手抜き」回転行列にハマっていた。

> &nbsp; $\left[\begin{array}{rr}cosθ&-sinθ\cr sinθ&cosθ\end{array}\right]\left[\begin{array}{c}x\cr y\end{array}\right]$
>
> 画面中心を(0,0)とするxy座標系において、適当な微小角度θで回転をおこないたい。θの値は、まあ何でも良くて、とにかく見た目が「回って」いる雰囲気を出したい。ただ、対象とするCPUがZ80なので、乗算は自分で実装するしかなく、そのあたりの「手抜き」を考える。
> 微小角度θにおいてcosθは1に近い値なので、ここの実装を簡単にすべく、とりあえずcosθ＝1－2<sup>-k</sup>としてみる。そうすると、sin<sup>2</sup>θ＝2<sup>(1-k)</sup>－2<sup>-2k</sup>となるので、小さい方の項を捨てれば、だいたいsinθ≒2<sup>(1-k)/2</sup>。つまり、kが奇数なら実装が簡単となり、たとえばk＝7なら、cosθ＝127/128, sinθ≒1/8となる。

HLレジスタにX座標(Hレジスタに符号付整数、Lレジスタに256を分母とする分数)が、DEレジスタにY座標が入っているとして、cosθ=127/128, sinθ≒1/8による回転をZ80で実装すると、だいたいこんな感じ。

```
E5     PUSH HL
7C       LD A,H
2F      CPL      
07     RLCA
4F       LD C,A
9F      SBC A,A
47       LD B,A
09      ADD HL,BC
7B       LD A,E
42       LD B,D
CB28    SRA B
1F      RRA
CB28    SRA B
1F      RRA
CB28    SRA B
1F      RRA
4F       LD C,A
ED42    SBC HL,BC
EB       EX DE,HL
7C       LD A,H
2F      CPL
07     RLCA
4F       LD C,A
9F      SBC A,A
47       LD B,A
09      ADD HL,BC
C1      POP BC
79       LD A,C
CB28    SRA B
1F      RRA
CB28    SRA B
1F      RRA
CB28    SRA B
1F      RRA
4F       LD C,A
09      ADD HL,BC
EB       EX DE,HL
C9      RET
```

ざっと227ステートで、XY座標を1つ回転できる。このXY座標を、PC-8001の160×100ドット画面に変換しつつ、1ドット描画してみよう。

```
3EB0     LD A,B0H
84      ADD A,H
D660    SUB A,60H
D8      RET C
1F      RRA
5F       LD E,A
9F      SBC A,A
E60F    AND A,0FH
3C      INC A
47       LD B,A
3ECE     LD A,CEH
92      SUB A,D
D69C    SUB A,9CH
D8      RET C
CB47    BIT 0,A
2802     JR Z,+4
CB20    SLA B
CB4F    BIT 1,A
2804     JR Z,+6
CB20    SLA B
CB20    SLA B
E67C    AND A,7CH
57       LD D,A
CB22    SLA D
0F     RRCA
0F     RRCA
1F      RRA
67       LD H,A
9F      SBC A,A
E680    AND A,80H
92      SUB A,D
6F       LD L,A
3001     JR NC,+3
25      DEC H
16F3     LD D,F3H
19      ADD HL,DE
7E       LD A,(HL)
A8      XOR A,B
77       LD (HL),A
C9      RET
```

最大224ステートあたりだが、Y座標を4で割って120倍するあたりは、もう少し速くできる気がする。なお、以下のPC-8001エミュレータでは、32個のドットを動かすたびに、100000ステート程度のウェイトを挟んでみた。よければ、テンキーの4と6(あるいは左右の矢印キー)で、回転を楽しんでほしい。

```
<!DOCTYPE html><head><meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>PC-8001 Emulator by Koichi Yasuoka, June 12, 2025</title>
<script>
var pc8001=new Object();
pc8001.memory=new Array(65536);
pc8001.memory.fill(0x76);
["0000 C3 00 E6",
 "045A                               C3 50 09",          // clear display
 "093A                               79 32 62 EA 78 32", // init display
 "0940 65 EA C6 B0 3E 14 8F 32 66 EA D3 30 3E 20 D3 51",
 "0950 ED 5B 5A EA 21 00 F3 06 50 73 23 10 FC 70 23 70",
 "0960 23 3A 65 EA C6 B0 9F C6 02 77 23 72 23 01 50 11",
 "0970 71 23 72 23 10 FA 71 23 70 23 11 00 F3 EB 01 B8",
 "0980 0B ED B0 21 01 01 22 63 EA C9",
 "1602       21 76 EA 11 81 06 7B 07 30 06 D3 10 3E 03", // read date
 "1610 18 18 DB 40 B4 C6 10 CB 1E 7B E6 07 20 0A 7D D6",
 "1620 7A 20 02 ED 67 2C 15 C8 3E 05 D3 40 06 3A 10 FE",
 "1630 3E 01 32 67 EA D3 40 1D 18 CE",

 "E600 31 FF FF CD 20 E8 CD F0 E7 CD 30 E7 CD B0 E7 CD",
 "E610 D0 E6 CD E0 E6 CD B0 E7 CD 80 E7 CD D0 E6 18 E9",

 "E6D0 01 00 10 0B 78 B1 20 FB C9",
 "E6E0 DB 00 F6 AF FE EF C0 DD 21 00 E9 DD 7E 04 B7 28",
 "E6F0 35 DD 6E 05 DD 66 06 AE 77 DD 5E 00 DD 56 01 DD",
 "E700 6E 02 DD 66 03 CD 80 E8 EB DD 75 00 DD 74 01 DD",
 "E710 73 02 DD 72 03 CD 40 E8 38 07 DD 75 05 DD 74 06",
 "E720 DA 06 00 DD 70 04 DD 7D C6 08 DD 6F 20 BD C9",
 "E730 DB 00 F6 AF FE BF C0 DD 21 00 E9 DD 7E 04 B7 28",
 "E740 34 DD 6E 05 DD 66 06 AE 77 DD 6E 00 DD 66 01 DD",
 "E750 5E 02 DD 56 03 CD 80 E8 DD 75 00 DD 74 01 DD 73",
 "E760 02 DD 72 03 CD 40 E8 38 07 DD 75 05 DD 74 06 DA",
 "E770 06 00 DD 70 04 DD 7D C6 08 DD 6F 20 BE C9",
 "E780 DD 21 00 E9 DD 7E 04 B7 28 09 DD 7D C6 08 DD 6F",
 "E790 20 F2 C9 CD B0 E8 67 DD 77 01 16 32 DD 72 03 CD",
 "E7A0 40 E8 D8 DD 70 04 DD 75 05 DD 74 06 C9",
 "E7B0 DD 21 00 E9 DD 7E 04 B7 28 22 DD 6E 05 DD 66 06",
 "E7C0 AE 77 DD 66 01 DD 35 03 DD 56 03 CD 40 E8 38 07",
 "E7D0 DD 75 05 DD 74 06 DA 06 00 DD 70 04 DD 7D C6 08",
 "E7E0 DD 6F 20 D0 C9",
 "E7F0 DD 21 00 E9 DD 36 04 00 CD B0 E8 67 DD 77 01 DD",
 "E800 55 CB 2A DD 72 03 CD 40 E8 38 09 DD 70 04 DD 75",
 "E810 05 DD 74 06 DD 7D C6 08 DD 6F 20 D8 C9",
 "E820 21 00 B8 22 5A EA 01 19 50 CD 3A 09 CD 02 16 2A",
 "E830 76 EA 22 CE E8 C9",
 "E840 3E B0 84 D6 60 D8 1F 5F 9F E6 0F 3C 47 3E CE 92",
 "E850 D6 9C D8 CB 47 28 02 CB 20 CB 4F 28 04 CB 20 CB",
 "E860 20 E6 7C 57 CB 22 0F 0F 1F 67 9F E6 80 92 6F 30",
 "E870 01 25 16 F3 19 7E A8 77 C9",
 "E880 E5 7C 2F 07 4F 9F 47 09 7B 42 CB 28 1F CB 28 1F",
 "E890 CB 28 1F 4F ED 42 EB 7C 2F 07 4F 9F 47 09 C1 79",
 "E8A0 CB 28 1F CB 28 1F CB 28 1F 4F 09 EB C9",
 "E8B0 2A CE E8 7C 07 0F CB 15 1F 8D 3D 67 22 CE E8 C9",
 "E8C0 00 00 00 00 00 00 00 00 00 00 00 00 E6 00 00 00"
].forEach(function(v){
  var t=v.split(/ +/);
  var a=parseInt(t[0],16);
  var i;
  for(i=1;i<t.length;i++)
    pc8001.memory[a+i-1]=parseInt(t[i],16);
});
pc8001.font=[
// 0x00 - 0x07
  "-------- -###---- -###---- -###---- -###---- ###----- --#----- -###----",
  "-------- -#------ -#------ -#------ -#------ #------- -#-#---- -#--#---",
  "-------- -###---- -###---- -###---- -###---- ###----- -###---- -###----",
  "-------- ---##-#- ---#--#- -#----#- -#------ #---##-- -#-#--#- -#--#---",
  "-------- -####-#- -###-#-- -###-#-- -######- ####--#- -#-#-#-- -###-#--",
  "-------- ----###- ----#--- ----#--- -----#-- ---#--#- ---##--- -----#--",
  "-------- ----#-#- ---#-#-- ---#-#-- -----#-- ---#--#- ---#-#-- -----#--",
  "-------- ----#-#- --#---#- --#---#- -----#-- ----##-# ---#--#- -----###",
// 0x08 - 0x0f
  "-###---- -#-#---- -#------ -#-#---- --####-- --###--- -###---- -###----",
  "-#--#--- -#-#---- -#------ -#-#---- -#------ -#------ -#------ -#------",
  "-###---- -###---- -#------ -###---- -#------ -#------ -###---- -###----",
  "-#--#### -#-#---- -#--###- -#-#---- -#---#-- --#####- ---#---- ---#----",
  "-###-#-- -#-####- -####--- -#-#---# --###--- ----#--# -#####-- -######-",
  "-----### -----#-- ----##-- ---##-## ----#--- ----###- ---#--#- -----#--",
  "-------# -----#-- ----#--- ---#-#-# ----#--- ----#-#- ---#--#- -----#--",
  "-----### -----#-- ----#--- ---#---# ----#### ----#--# ----##-- ----###-",
// 0x10 - 0x17
  "-###---- -###---- -###---- -###---- -###---- -#--#--- -###---- -###----",
  "-#--#--- -#--#--- -#--#--- -#--#--- -#--#--- -##-#--- -#------ -#------",
  "-#--#--- -#--#--- -#--#--- -#--#--- -#--#--- -#-##--- -###---- -###----",
  "-#--#### -#--#-#- -#--###- -#--#### -#--#-#- -#--#--# ---#---- -#--###-",
  "-###-#-- -###-##- -###---# -###---# -###-##- -#--#-#- -####--# -####--#",
  "-----### ------#- -----##- -----### ----#-#- ----##-- ----##-# ----###-",
  "-----#-- ------#- ----#--- -------# ---##### ----#-#- ----#-## ----#--#",
  "-----### -----### ----#### ----#### ------#- ----#--# ----#--# ----###-",
// 0x18 - 0x1f
  "--###--- -###---- -###---- -###---- -------- -------- -------- --------",
  "-#------ -#------ -#------ -#------ ----#--- ---#---- ----#--- ----#---",
  "-#------ -###---- -###---- -###---- -----#-- --#----- ---###-- ----#---",
  "--###--- -#------ ---###-- -#------ -######- -######- --#-#-#- ----#---",
  "----#--# -###---# -###--#- -######- -----#-- --#----- ----#--- --#-#-#-",
  "----##-# ---##-## ---###-- ---#---- ----#--- ---#---- ----#--- ---###--",
  "----#-## ---#-#-# ---#--#- ---#---- -------- -------- ----#--- ----#---",
  "----#--# ---#---# ---###-- ----###- -------- -------- -------- --------",
// 0x20 - 0x27
  "-------- ----#--- --#--#-- --#--#-- ----#--- -------- --##---- -----#--",
  "-------- ----#--- --#--#-- --#--#-- ---####- -##---#- -#--#--- ----#---",
  "-------- ----#--- --#--#-- -######- --#-#--- -##--#-- -#--#--- ---#----",
  "-------- ----#--- -------- --#--#-- ---###-- ----#--- --##---- --------",
  "-------- -------- -------- -######- ----#-#- ---#---- -#--#-#- --------",
  "-------- -------- -------- --#--#-- --####-- --#--##- -#---#-- --------",
  "-------- ----#--- -------- --#--#-- ----#--- -#---##- --###-#- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0x28 - 0x2f
  "-----#-- --#----- ----#--- -------- -------- -------- -------- --------",
  "----#--- ---#---- --#-#-#- ----#--- -------- -------- -------- ------#-",
  "---#---- ----#--- ---###-- ----#--- -------- -------- -------- -----#--",
  "---#---- ----#--- --#####- --#####- -------- -######- -------- ----#---",
  "---#---- ----#--- ---###-- ----#--- -------- -------- -------- ---#----",
  "----#--- ---#---- --#-#-#- ----#--- ----#--- -------- ---##--- --#-----",
  "-----#-- --#----- ----#--- -------- ----#--- -------- ---##--- -#------",
  "-------- -------- -------- -------- ---#---- -------- -------- --------",
// 0x30 - 0x37
  "--####-- ----#--- --####-- --####-- -----#-- -######- ---###-- -######-",
  "-#----#- ---##--- -#----#- -#----#- ----##-- -#------ --#----- -#----#-",
  "-#---##- --#-#--- ------#- ------#- ---#-#-- -####--- -#------ -----#--",
  "-#-##-#- ----#--- ----##-- ---###-- --#--#-- -----#-- -#####-- ----#---",
  "-##---#- ----#--- --##---- ------#- -######- ------#- -#----#- ---#----",
  "-#----#- ----#--- -#------ -#----#- -----#-- -#---#-- -#----#- ---#----",
  "--####-- --#####- -######- --####-- -----#-- --###--- --####-- ---#----",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0x38 - 0x3f
  "--####-- --####-- -------- -------- ----###- -------- -###---- --####--",
  "-#----#- -#----#- -------- -------- ---##--- -------- ---##--- -#----#-",
  "-#----#- -#----#- ----#--- ----#--- --##---- -######- ----##-- ------#-",
  "--####-- --#####- -------- -------- -##----- -------- -----##- ----##--",
  "-#----#- ------#- -------- -------- --##---- -######- ----##-- ---#----",
  "-#----#- -----#-- ----#--- ----#--- ---##--- -------- ---##--- --------",
  "--####-- --###--- -------- ----#--- ----###- -------- -###---- ---#----",
  "-------- -------- -------- ---#---- -------- -------- -------- --------",
// 0x40 - 0x47
  "---###-- ---##--- -#####-- ---###-- -####--- -######- -######- ---###--",
  "--#---#- --#--#-- --#---#- --#---#- --#--#-- -#------ -#------ --#---#-",
  "-#--#-#- -#----#- --#---#- -#------ --#---#- -#------ -#------ -#------",
  "-#-#-##- -######- --####-- -#------ --#---#- -####--- -####--- -#--###-",
  "-#--##-- -#----#- --#---#- -#------ --#---#- -#------ -#------ -#----#-",
  "--#----- -#----#- --#---#- --#---#- --#--#-- -#------ -#------ --#---#-",
  "---####- -#----#- -#####-- ---###-- -####--- -######- -#------ ---###--",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0x48 - 0x4f
  "-#----#- ---###-- ----###- -#----#- -#------ -#----#- -#----#- ---##---",
  "-#----#- ----#--- -----#-- -#---#-- -#------ -##--##- -##---#- --#--#--",
  "-#----#- ----#--- -----#-- -#--#--- -#------ -#-##-#- -#-#--#- -#----#-",
  "-######- ----#--- -----#-- -###---- -#------ -#-##-#- -#--#-#- -#----#-",
  "-#----#- ----#--- -----#-- -#--#--- -#------ -#----#- -#---##- -#----#-",
  "-#----#- ----#--- -#---#-- -#---#-- -#------ -#----#- -#----#- --#--#--",
  "-#----#- ---###-- --###--- -#----#- -######- -#----#- -#----#- ---##---",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0x50 - 0x57
  "-#####-- ---##--- -#####-- --####-- --#####- -#----#- -#----#- -#----#-",
  "-#----#- --#--#-- -#----#- -#----#- ----#--- -#----#- -#----#- -#----#-",
  "-#----#- -#----#- -#----#- -#------ ----#--- -#----#- -#----#- -#----#-",
  "-#####-- -#----#- -#####-- --####-- ----#--- -#----#- --#--#-- -#-##-#-",
  "-#------ -#--#-#- -#--#--- ------#- ----#--- -#----#- --#--#-- -#-##-#-",
  "-#------ --#--#-- -#---#-- -#----#- ----#--- -#----#- ---##--- -##--##-",
  "-#------ ---##-#- -#----#- --####-- ----#--- --####-- ---##--- -#----#-",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0x58 - 0x5f
  "-#----#- --#---#- -######- --####-- --#---#- --####-- ----#--- --------",
  "-#----#- --#---#- ------#- --#----- --#---#- -----#-- ---#-#-- --------",
  "--#--#-- --#---#- -----#-- --#----- ---#-#-- -----#-- --#---#- --------",
  "---##--- ---###-- ---##--- --#----- --#####- -----#-- -------- --------",
  "--#--#-- ----#--- --#----- --#----- ----#--- -----#-- -------- --------",
  "-#----#- ----#--- -#------ --#----- --#####- -----#-- -------- --------",
  "-#----#- ----#--- -######- --####-- ----#--- --####-- -------- -######-",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0x60 - 0x67
  "-------- -------- -#------ -------- ------#- -------- ----##-- --------",
  "-------- -------- -#------ -------- ------#- -------- ---#--#- --------",
  "-------- --####-- -#-###-- --####-- --###-#- --####-- ---#---- --###-#-",
  "-------- -----#-- -##---#- -#----#- -#---##- -#----#- -#####-- -#---##-",
  "-------- --####-- -#----#- -#------ -#----#- -######- ---#---- -#---##-",
  "-------- -#---#-- -##---#- -#----#- -#---##- -#------ ---#---- --###-#-",
  "-------- --###-#- -#-###-- --####-- --###-#- --####-- ---#---- ------#-",
  "-------- -------- -------- -------- -------- -------- -------- --####--",
// 0x68 - 0x6f
  "-#------ ----#--- -----#-- -#------ ---##--- -------- -------- --------",
  "-#------ -------- -------- -#------ ----#--- -------- -------- --------",
  "-#-###-- ---##--- ----##-- -#---#-- ----#--- -###-##- -#-###-- --####--",
  "-##---#- ----#--- -----#-- -#--#--- ----#--- -#--#--# -##---#- -#----#-",
  "-#----#- ----#--- -----#-- -#-#---- ----#--- -#--#--# -#----#- -#----#-",
  "-#----#- ----#--- -----#-- -##-#--- ----#--- -#--#--# -#----#- -#----#-",
  "-#----#- ---###-- -#---#-- -#---#-- ---###-- -#--#--# -#----#- --####--",
  "-------- -------- --###--- -------- -------- -------- -------- --------",
// 0x70 - 0x77
  "-------- -------- -------- -------- ---#---- -------- -------- --------",
  "-------- -------- -------- -------- ---#---- -------- -------- --------",
  "-#-###-- --###-#- -#-###-- --#####- -#####-- -#----#- -#----#- -#-----#",
  "-##---#- -#---##- -##---#- -#------ ---#---- -#----#- -#----#- -#--#--#",
  "-##---#- -#---##- -#------ --####-- ---#---- -#----#- -#----#- -#--#--#",
  "-#-###-- --###-#- -#------ ------#- ---#--#- -#---##- --#--#-- -#--#--#",
  "-#------ ------#- -#------ -#####-- ----##-- --###-#- ---##--- --##-##-",
  "-#------ ------#- -------- -------- -------- -------- -------- --------",
// 0x78 - 0x7f
  "-------- -------- -------- ----###- ----#--- -###---- --##---- --------",
  "-------- -------- -------- ---#---- ----#--- ----#--- -#--#--# --------",
  "-#----#- -#----#- -######- ---#---- -------- ----#--- -----##- --------",
  "--#--#-- -#----#- -----#-- --#----- -------- -----#-- -------- --------",
  "---##--- -#---##- ---##--- ---#---- -------- ----#--- -------- --------",
  "--#--#-- --###-#- --#----- ---#---- ----#--- ----#--- -------- --------",
  "-#----#- ------#- -######- ----###- ----#--- -###---- -------- --------",
  "-------- --####-- -------- -------- -------- -------- -------- --------",
// 0x80 - 0x87
  "-------- -------- -------- -------- -------- -------- -------- ########",
  "-------- -------- -------- -------- -------- -------- ######## ########",
  "-------- -------- -------- -------- -------- ######## ######## ########",
  "-------- -------- -------- -------- ######## ######## ######## ########",
  "-------- -------- -------- ######## ######## ######## ######## ########",
  "-------- -------- ######## ######## ######## ######## ######## ########",
  "-------- ######## ######## ######## ######## ######## ######## ########",
  "######## ######## ######## ######## ######## ######## ######## ########",
// 0x88 - 0x8f
  "#------- ##------ ###----- ####---- #####--- ######-- #######- ----#---",
  "#------- ##------ ###----- ####---- #####--- ######-- #######- ----#---",
  "#------- ##------ ###----- ####---- #####--- ######-- #######- ----#---",
  "#------- ##------ ###----- ####---- #####--- ######-- #######- ----#---",
  "#------- ##------ ###----- ####---- #####--- ######-- #######- ########",
  "#------- ##------ ###----- ####---- #####--- ######-- #######- ----#---",
  "#------- ##------ ###----- ####---- #####--- ######-- #######- ----#---",
  "#------- ##------ ###----- ####---- #####--- ######-- #######- ----#---",
// 0x90 - 0x97
  "----#--- -------- ----#--- ----#--- ######## -------- ----#--- -------#",
  "----#--- -------- ----#--- ----#--- -------- -------- ----#--- -------#",
  "----#--- -------- ----#--- ----#--- -------- -------- ----#--- -------#",
  "----#--- -------- ----#--- ----#--- -------- -------- ----#--- -------#",
  "######## ######## #####--- ----#### -------- ######## ----#--- -------#",
  "-------- ----#--- ----#--- ----#--- -------- -------- ----#--- -------#",
  "-------- ----#--- ----#--- ----#--- -------- -------- ----#--- -------#",
  "-------- ----#--- ----#--- ----#--- -------- -------- ----#--- -------#",
// 0x98 - 0x9f
  "-------- -------- ----#--- ----#--- -------- -------- ----#--- ----#---",
  "-------- -------- ----#--- ----#--- -------- -------- ----#--- ----#---",
  "-------- -------- ----#--- ----#--- -------- -------- ----#--- ----#---",
  "-------- -------- ----#--- ----#--- -------- -------- -----#-- ---#----",
  "----#### #####--- ----#### #####--- ------## ###----- ------## ###-----",
  "----#--- ----#--- -------- -------- -----#-- ---#---- -------- --------",
  "----#--- ----#--- -------- -------- ----#--- ----#--- -------- --------",
  "----#--- ----#--- -------- -------- ----#--- ----#--- -------- --------",
// 0xa0 - 0xa7
  "-------- -------- ---###-- -------- -------- -------- -------- --------",
  "-------- -------- ---#---- -------- -------- -------- -######- --------",
  "-------- -------- ---#---- -------- -------- -------- ------#- --#####-",
  "-------- -------- ---#---- ----#--- -------- ---##--- -######- ------#-",
  "-------- --###--- -------- ----#--- --#----- ---##--- ------#- ----##--",
  "-------- --#-#--- -------- ----#--- ---#---- -------- -----#-- ----#---",
  "-------- --###--- -------- --###--- ----#--- -------- --###--- ---#----",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0xa8 - 0xaf
  "-------- -------- -------- -------- -------- -------- -------- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------",
  "-----#-- ----#--- -------- -----#-- ---#---- -------- --####-- --------",
  "----#--- --#####- --#####- --#####- --#####- ---###-- -----#-- --#-#-#-",
  "---##--- --#---#- ----#--- ----##-- ---#--#- -----#-- --####-- --#-#-#-",
  "--#-#--- ------#- ----#--- ---#-#-- ---#-#-- -----#-- -----#-- ------#-",
  "----#--- ----##-- --#####- --#--#-- ---#---- --#####- --####-- ----##--",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0xb0 - 0xb7
  "-------- -######- ------#- ----#--- -------- ----#--- ---#---- ----#---",
  "-------- ------#- -----#-- -######- --#####- -######- -######- --#####-",
  "-------- ------#- ----#--- -#----#- ----#--- ----#--- ---#--#- ----#---",
  "--#####- ---#-#-- ---##--- -#----#- ----#--- ---##--- ---#--#- --#####-",
  "-------- ---##--- --#-#--- ------#- ----#--- --#-#--- ---#--#- ----#---",
  "-------- ---#---- -#--#--- -----#-- ----#--- -#--#--- ---#--#- ----#---",
  "-------- --#----- ----#--- --###--- --#####- ----#--- --#--#-- ----#---",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0xb8 - 0xbf
  "---####- --#----- -------- --#--#-- -------- -######- --#----- -#----#-",
  "--#---#- --#####- -######- -######- -###---- ------#- -######- -#----#-",
  "-#----#- -#--#--- ------#- --#--#-- -------- -----#-- --#---#- --#---#-",
  "-----#-- ----#--- ------#- --#--#-- -###--#- ----#--- --#--#-- ------#-",
  "----#--- ----#--- ------#- -----#-- ------#- ---##--- --#----- -----#--",
  "---#---- ----#--- ------#- ----#--- -----#-- --#--#-- --#----- ----#---",
  "-##----- ---#---- -######- ---#---- -####--- -#----#- ---####- --##----",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0xc0 - 0xc7
  "---####- -----#-- -------- --####-- ---#---- ----#--- -------- --------",
  "--#---#- --###--- -#-#--#- -------- ---#---- ----#--- --####-- --#####-",
  "-##---#- ----#--- -#-#--#- -######- ---#---- -######- -------- ------#-",
  "---#-#-- -######- -#-#--#- ----#--- ---##--- ----#--- -------- ---#-#--",
  "----#--- ----#--- -----#-- ----#--- ---#-#-- ----#--- -------- ----#---",
  "---#---- ----#--- ----#--- ---#---- ---#---- ---#---- -------- ---#-#--",
  "-##----- -###---- -###---- --#----- ---#---- --#----- -######- --#-----",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0xc8 - 0xcf
  "----#--- ------#- ---#---- -#------ -------- -------- ----#--- -######-",
  "--#####- ------#- ----#--- -#------ -######- ---#---- --#####- ------#-",
  "-----#-- ------#- -----#-- -######- ------#- --#-#--- ----#--- ------#-",
  "----#--- -----#-- -#----#- -#------ ------#- -#---#-- ----#--- -----#--",
  "---###-- ----#--- -#----#- -#------ -----#-- ------#- --#-#-#- --#-#---",
  "--#-#-#- ---#---- -#----#- -#------ ----#--- ------#- --#-#-#- ---#----",
  "----#--- --#----- -#----#- --#####- --##---- -------- ----#--- ----#---",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0xd0 - 0xd7
  "-------- -----#-- -------- -------- --#----- -------- -######- --####--",
  "--####-- ----#--- ------#- -######- --#----- --###--- ------#- --------",
  "-------- ---#---- ------#- ---#---- -######- ----#--- ------#- -######-",
  "--####-- --#----- ---#-#-- -######- --#---#- ----#--- -######- ------#-",
  "-------- -#--#--- ----#--- ---#---- --#--#-- ----#--- ------#- -----#--",
  "-#####-- -#####-- ---#-#-- ---#---- --#----- ----#--- ------#- ----#---",
  "------#- ------#- -##----- ---####- --#----- -######- -######- ---#----",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0xd8 - 0xdf
  "-#----#- --#-#--- --#----- -------- -------- -------- ---#---- -###----",
  "-#----#- --#-#--- --#----- -######- -######- -###---- -#--#--- -#-#----",
  "-#----#- --#-#--- --#----- -#----#- -#----#- ------#- --#----- -###----",
  "-#----#- --#-#-#- --#---#- -#----#- -#----#- ------#- -------- --------",
  "------#- --#-#-#- --#--#-- -#----#- ------#- -----#-- -------- --------",
  "-----#-- --#-##-- --#-#--- -#----#- -----#-- ----#--- -------- --------",
  "---##--- -#--#--- --##---- -######- ---##--- -###---- -------- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------",
// 0xe0 - 0xe7
  "-------- ----#--- ----#--- ----#--- -------# #------- ######## ########",
  "-------- ----#--- ----#--- ----#--- ------## ##------ -####### #######-",
  "######## ----#### ######## #####--- -----### ###----- --###### ######--",
  "-------- ----#--- ----#--- ----#--- ----#### ####---- ---##### #####---",
  "-------- ----#--- ----#--- ----#--- ---##### #####--- ----#### ####----",
  "######## ----#### ######## #####--- --###### ######-- -----### ###-----",
  "-------- ----#--- ----#--- ----#--- -####### #######- ------## ##------",
  "-------- ----#--- ----#--- ----#--- ######## ######## -------# #-------",
// 0xe8 - 0xef
  "----#--- --##-##- ----#--- ---###-- -------- -------- -------# #-------",
  "---###-- -####### ---###-- ---###-- --####-- --####-- ------#- -#------",
  "--#####- -####### --#####- -####### -######- -#----#- -----#-- --#-----",
  "-####### -####### -####### -####### -######- -#----#- ----#--- ---#----",
  "-####### --#####- --#####- -##-#-## -######- -#----#- ---#---- ----#---",
  "---###-- ---###-- ---###-- ----#--- -######- -#----#- --#----- -----#--",
  "--#####- ----#--- ----#--- --#####- --####-- --####-- -#------ ------#-",
  "-------- -------- -------- -------- -------- -------- #------- -------#",
// 0xf0 - 0xf7
  "#------# -####### -#------ --###### -####### -----#-- -------- --###-#-",
  "-#----#- -#--#--# -######- --#----# -#-----# ###-###- ---##--- ---#--#-",
  "--#--#-- -#--#--# -#--#--- --###### -#-----# #-#--#-- --#--#-- -#######",
  "---##--- -####### --####-- --#----# -####### ###-#### -#----#- ---#-###",
  "---##--- -#-----# --#-#--- --###### -#-----# #-#---#- --####-- --###-##",
  "--#--#-- -#-----# -######- --#----# -#-----# ###-#### ---#-#-- -#-#--#-",
  "-#----#- -#-----# ----#--- -#-----# -####### ----#-#- --#--#-- ---#-#--",
  "#------# -------- -------- -------- -------- ------#- -------- --------",
// 0xf8 - 0xff
  "-------- -------- -------- -------- -------- -------- -------- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------",
  "-------- -------- -------- -------- -------- -------- -------- --------"];
pc8001.display=new Object();
pc8001.display.columns=40;
pc8001.display.initColor=0xe8;
pc8001.initDisplay=function(svg){
  var d=pc8001.display;
  var x,y,e,t,c;
  d.svg=svg;
  d.lines=25;
  d.reverse=0;
  d.colors=new Array(256);
  d.colors.fill("control");
  for(x=0;x<8;x++){
    d.colors[0x08+x]="rgb(0 0 0)";
    d.colors[0x18+x]="#000000";
    d.colors[0x28+x]="rgb(0 0 255)";
    d.colors[0x38+x]="#0000ff";
    d.colors[0x48+x]="rgb(255 0 0)";
    d.colors[0x58+x]="#ff0000";
    d.colors[0x68+x]="rgb(255 0 255)";
    d.colors[0x78+x]="#ff00ff";
    d.colors[0x88+x]="rgb(0 255 0)";
    d.colors[0x98+x]="#00ff00";
    d.colors[0xa8+x]="rgb(0 255 255)";
    d.colors[0xb8+x]="#00ffff";
    d.colors[0xc8+x]="rgb(255 255 0)";
    d.colors[0xd8+x]="#ffff00";
    d.colors[0xe8+x]="rgb(255 255 255)";
    d.colors[0xf8+x]="#ffffff";
  }
  e=document.createElementNS("http://www.w3.org/2000/svg","text");
  e.setAttribute("font-family","monospace");
  e.setAttribute("font-size",2);
  e.setAttribute("fill","none");
  d.svg.appendChild(e);
  e.textContent=String.fromCodePoint(0x2588);
  d.monowidth=(e.getBBox().width<2)?1:2;
  e=[[0x3000,0x2598,0x259d,0x2580],
     [0x2596,0x258c,0x259e,0x259b],
     [0x2597,0x259a,0x2590,0x259c],
     [0x2584,0x2599,0x259f,0x2588]];
  if(pc8001.display.monowidth<2)
    e[0][0]=0xa0;
  d.font=new Array(256);
  d.font.fill("");
  d.font.forEach(function(v,x,a){
    var t=new Array(8);
    var i,j
    for(i=j=0;i<8;i++){
      t[i]=pc8001.font[(x&0xf8)+i].split(" ")[x%8].replace(/-/g,"0").replace(/#/g,"1");
      if(t[i]=="00000000")
        j++;
    }
    if(j!=8){
      for(i=0;i<8;i+=2){
        for(j=0;j<8;j+=2)
          a[x]+=String.fromCodePoint(e[parseInt(t[j+1].substr(i+1,1)+t[j].substr(i+1,1),2)][parseInt(t[j+1].substr(i,1)+t[j].substr(i,1),2)]);
      }
    }
  });
  d.blocks=new Array(256);
  d.blocks.fill("");
  for(x=1;x<256;x++){
    if((x&0xcc)>0)
      d.blocks[x]+=String.fromCodePoint(e[(x>>4)&3][x&3],e[(x>>6)&3][(x>>2)&3]);
    else
      d.blocks[x]+=String.fromCodePoint(e[(x>>4)&3][x&3]);
  }
  d.bgchars=new Array(56);
  d.bgchars.fill("");
  for(x=0;x<4;x++){
    d.bgchars[0x04+x]=d.bgchars[0x14+x]=d.bgchars[0x24+x]=d.bgchars[0x34+x]=String.fromCodePoint(0x2588);
    d.bgchars[0x10+x]=String.fromCodePoint(0x258f);
    d.bgchars[0x20+x]=String.fromCodePoint(0x2595);
    d.bgchars[0x30+x]=String.fromCodePoint(0x258c,e[0][0],e[0][0],0x2590);
  }
  e=document.createElementNS("http://www.w3.org/2000/svg","path");
  e.setAttribute("id","charpath");
  t=(d.monowidth<2)?"2.4":"4";
  e.setAttribute("d","M 0 1 h "+t+" m -"+t+" 1 h "+t+" m -"+t+" 1 h "+t+" m -"+t+" 1 h "+t);
  d.svg.appendChild(e);
  e=document.createElementNS("http://www.w3.org/2000/svg","g");
  e.setAttribute("class","blink");
  d.svg.appendChild(e);
  d.blinker=e;
  d.textArray=t=new Array(80);
  for(x=0;x<80;x++)
    t[x]=new Array(25);
  d.start=d.end=0xf300;
  for(y=0;y<25;y++){
    for(x=0;x<80;x++){
      pc8001.memory[d.end]=0;
      d.end++;
      t[x][y]=new Object();
      t[x][y].color=d.colors[d.initColor];
      c=(x%2==0||d.columns==80)?d.colors[d.initColor]:"none";
      e=document.createElementNS("http://www.w3.org/2000/svg","text");
      e.setAttribute("y",x*2);
      e.setAttribute("x",y*4);
      e.setAttribute("font-size",160/d.columns);
      e.setAttribute("font-family","monospace"); 
      e.setAttribute("fill",c);
      e.setAttribute("transform","matrix(0 1 1 0 "+((d.monowidth<2)?128:144)/d.columns+" 0)");
      e.setAttribute("textLength",4);
      e.setAttribute("lengthAdjust","spacingAndGlyphs");
      d.svg.appendChild(e);
      t[x][y].controlbox=e;
      t[x][y].control=d.reverse;
      e=document.createElementNS("http://www.w3.org/2000/svg","text");
      e.setAttribute("font-family","monospace");
      if(d.colors[d.initColor].substr(0,1)=="#"){
        e.setAttribute("font-size",2);
        e.setAttribute("transform","matrix(0 "+((d.monowidth<2)?5/3:1)+" "+80/d.columns+" 0 "+(x*2+72/d.columns)+" "+y*100/d.lines+")");
      }
      else{
        e.setAttribute("font-size",1);
        e.setAttribute("transform","matrix(0 "+((d.monowidth<2)?5/3:1)+" "+40/d.columns+" 0 "+x*2+" "+y*100/d.lines+")");
      }
      e.setAttribute("fill",c);
      d.svg.appendChild(e);
      t[x][y].textbox=e;
      e=document.createElementNS("http://www.w3.org/2000/svg","textPath");
      e.setAttribute("href","#charpath");
      t[x][y].textbox.appendChild(e);
      t[x][y].textpath=e;
      t[x][y].data=0;
    }
    pc8001.memory[d.end]=0;
    d.end++;
    pc8001.memory[d.end]=0;
    d.end++;
    pc8001.memory[d.end]=(d.columns==40)?2:1;
    d.end++;
    for(x=3;x<39;x++){
      pc8001.memory[d.end]=(x%2==0)?80:d.initColor;
      d.end++;
    }
    pc8001.memory[d.end]=0;
    d.end++;
  }
  d.end--;
  pc8001.outports[0x30]=(d.columns==80)?0x29:0x28;
}
pc8001.resizeDisplay=function(columns,lines){
  var d=pc8001.display;
  var x,y,t;
  if((columns!=40&&columns!=80)||lines<20||lines>25){
    console.log("Unable resizeDisplay",columns,lines);
    return;
  }
  if(columns!=d.columns||lines!=d.lines){
    for(y=0;y<25;y++){
      for(x=0;x<80;x++){
        t=d.textArray[x][y];
        t.controlbox.setAttribute("x",y*100/lines);
        t.controlbox.setAttribute("font-size",160/columns);
        t.controlbox.setAttribute("transform","matrix(0 1 1 0 "+(d.monowidth<2?128:144)/columns+" 0)");
        t.controlbox.textContent=d.bgchars[t.control];
        if(t.color.substr(0,1)=="#"){
          t.textbox.setAttribute("font-size",2);
          t.textbox.setAttribute("transform","matrix(0 "+((d.monowidth<2)?5/3:1)+" "+80/columns+" 0 "+(x*2+72/columns)+" "+y*100/lines+")");
          t.textpath.textContent=d.blocks[t.data];
        }
        else{
          t.textbox.setAttribute("font-size",1);
          t.textbox.setAttribute("transform","matrix(0 "+((d.monowidth<2)?5/3:1)+" "+40/columns+" 0 "+x*2+" "+y*100/lines+")");
          t.textpath.textContent=d.font[t.data];
        }
        if(y>=lines||(x%2==1&&columns==40)){
          t.controlbox.setAttribute("fill","none");
          t.textbox.setAttribute("fill","none");
        }
        else{
          t.controlbox.setAttribute("fill",t.color);
          t.textbox.setAttribute("fill",((t.control&1)==1)?"none":((t.control&4)==4)?"black":t.color);
          if((t.control&2)==2)
            d.blinker.appendChild(t.textbox);
          else
            d.svg.appendChild(t.textbox);
        }
      }
    }
  }
  d.columns=columns;
  d.lines=lines;
}
pc8001.reverseDisplay=function(rev){
  var d=pc8001.display;
  var x,y,t;
  if(rev!=0)
    rev=4;
  if(d.reverse==rev)
    return;
  for(y=0;y<25;y++){
    for(x=0;x<80;x++){
      t=d.textArray[x][y];
      t.control^=4;
      t.controlbox.textContent=d.bgchars[t.control];
      if(y<d.lines&&(x%2==0||d.columns==80))
        t.textbox.setAttribute("fill",((t.control&1)==1)?"none":((t.control&4)==4)?"black":t.color);
    }
  }
  d.reverse=rev;
}
pc8001.writeMemory=function(address,data){
  var t=pc8001.memory[address];
  var d=pc8001.display;
  var x,y,f,i,j,k;
  if(data<0||data>0xff){
    console.log("writeMemory",address.toString(16),data);
    Object.keys(pc8001.z80.regs).forEach(function(v){
      console.log(" reg",v,pc8001.z80.regs[v].toString(16).toUpperCase().padStart(v.length*2,"0"));
  });
    console.log(" flags",pc8001.z80.flags);
    data=(data+65536)&0xff;
  }
  if(address<0x6000)
    console.log("write",data,"to ROM",address.toString(16).toUpperCase().padStart(4,"0"),"at",pc8001.z80.regs["PC"].toString(16).toUpperCase().padStart(4,"0"));
  else
    pc8001.memory[address]=data;
  if(address<d.start||d.end<address||t==data)
    return;
  x=(address-d.start)%120;
  y=Math.floor((address-d.start)/120);
  if(x<80){
    t=d.textArray[x][y];
    if(y<d.lines&&(x%2==0||d.columns==80))
      t.textpath.textContent=(t.color.substr(0,1)=="#")?d.blocks[data]:d.font[data];
    t.data=data;
    return;
  }
  for(f=1;f==1;y=(y>d.lines-2)?0:y+1){
    i=d.start+80+y*120;
    j=d.textArray[79][(y==0)?d.lines-1:y-1].control;
    k=d.textArray[79][(y==0)?d.lines-1:y-1].color;
    for(x=0;x<80;x++){
      if(pc8001.memory[i]==x){
        i++;
        t=d.colors[pc8001.memory[i]];
        if(t=="control")
          j=(pc8001.memory[i]&0x3f)^d.reverse;
        else
          k=t;
        i++;
      }
      t=d.textArray[x][y];
      f=0;
      if(t.color!=k){
        if(x%2==0||d.columns==80){
          t.controlbox.setAttribute("fill",k);
          t.textbox.setAttribute("fill",k);
          if(t.color.substr(0,1)!=k.substr(0,1)){
            if(k.substr(0,1)=="#"){
              t.textbox.setAttribute("font-size",2);
              t.textbox.setAttribute("transform","matrix(0 "+((d.monowidth<2)?5/3:1)+" "+80/d.columns+" 0 "+(x*2+72/d.columns)+" "+y*100/d.lines+")");
              t.textpath.textContent=d.blocks[t.data];
            }
            else{
              t.textbox.setAttribute("font-size",1);
              t.textbox.setAttribute("transform","matrix(0 "+((d.monowidth<2)?5/3:1)+" "+40/d.columns+" 0 "+x*2+" "+y*100/d.lines+")");
              t.textpath.textContent=d.font[t.data];
            }
          }
        }
        t.color=k;
        f=1;
      }
      if(t.control!=j){
        if(x%2==0||d.columns==80){
          t.textbox.setAttribute("fill",((j&1)==1)?"none":((j&4)==4)?"black":k);
          if(((t.control^j)&2)==2){
            if((j&2)==2)
              d.blinker.appendChild(t.textbox);
            else
              d.svg.appendChild(t.textbox);
          }
          t.controlbox.textContent=d.bgchars[j];
        }
        t.control=j;
        f=1;
      }
    }
  }
}
pc8001.inports=new Array(256);
pc8001.inports.fill(0xff);
pc8001.outports=new Array(256);
pc8001.outports.fill(0);
pc8001.keymap=new Array(256);
pc8001.keymap.fill([]);
pc8001.keymap[13]=[1,0x7f];                    // enter-key
pc8001.keymap[100]=pc8001.keymap[37]=[0,0xef]; // ten-key 4 = leftarrow
pc8001.keymap[102]=pc8001.keymap[39]=[0,0xbf]; // ten-key 6 = rightarrow
pc8001.keydown=function(event){
  var k=pc8001.keymap[event.keyCode]
  var i;
  if(k.length<2)
    return;
  for(i=0;i<k.length;i+=2)
    pc8001.inports[k[i]]&=k[i+1];
}
pc8001.keyup=function(event){
  var k=pc8001.keymap[event.keyCode]
  var i;
  if(k.length<2)
    return;
  for(i=0;i<k.length;i+=2)
    pc8001.inports[k[i]]|=(k[i+1]^0xff);
  if(pc8001.beep.counter<0){
    pc8001.beep.counter=pc8001.beep.on=0;
    pc8001.beep.start=pc8001.z80.states;
    pc8001.beep.oscillator.start();
  }
}
pc8001.beep=new Object();
pc8001.beep.audio=new(window.AudioContext||window.webkitAudioContext)();
pc8001.beep.buffer=pc8001.beep.audio.createBuffer(1,Math.floor(pc8001.beep.audio.sampleRate/60),pc8001.beep.audio.sampleRate);
pc8001.beep.oscillator=pc8001.beep.audio.createBufferSource();
pc8001.beep.oscillator.buffer=pc8001.beep.buffer;
pc8001.beep.wave=pc8001.beep.buffer.getChannelData(0);
pc8001.beep.wave.fill(0);
pc8001.beep.counter=-1;
pc8001.beep.oscillator.loop=true;
pc8001.beep.oscillator.connect(pc8001.beep.audio.destination);
pc8001.beep.refWave=new Array(pc8001.beep.wave.length);
pc8001.beep.refWave.fill(0);
pc8001.beep.refWave.forEach(function(v,i,a){
  a[i]=Math.sin(i*Math.PI*2/pc8001.beep.audio.sampleRate*2400);
});
pc8001.calendar=new Object();
pc8001.calendar.command=function(com){
  var d,j,k;
  switch(com){
    case 4:
      pc8001.calendar.differential=0;
    case 3:
      pc8001.calendar.readreg="00000000";
      pc8001.calendar.writereg="";
      pc8001.calendar.date=new Date();
      return 0;
    case 2:
      d=new Date();
      k=pc8001.calendar.writereg;
      if(k.length>40){
        j=parseInt(parseInt(k.slice(0,-40),2).toString(16),10);
        if(!isNaN(j))
          d.setFullYear(j);
      }
      if(k.length>39){
        j=parseInt(k.slice(-40,-36),2);
        if(!isNaN(j))
          d.setMonth(j-1);
      }
      if(k.length>31){
        j=parseInt(parseInt(k.slice(-32,-24),2).toString(16),10);
        if(!isNaN(j))
          d.setDate(j);
      }
      if(k.length>23){
        j=parseInt(parseInt(k.slice(-24,-16),2).toString(16),10);
        if(!isNaN(j))
          d.setHours(j);
      }
      if(k.length>15){
        j=parseInt(parseInt(k.slice(-16,-8),2).toString(16),10);
        if(!isNaN(j))
          d.setMinutes(j);
      }
      if(k.length>7){
        j=parseInt(parseInt(k.slice(-8),2).toString(16),10);
        if(!isNaN(j))
          d.setSeconds(j);
      }
      pc8001.calendar.date=new Date();
      pc8001.calendar.differential=pc8001.calendar.date-d;
    case 1:
      d=new Date(pc8001.calendar.date-pc8001.calendar.differential);
      j=d.getFullYear().toString()+(d.getMonth()+1).toString(16)+d.getDay().toString()
      k=parseInt(j,16).toString(2).padStart(32,"0");
      j=(d.getDate()*1000000+d.getHours()*10000+d.getMinutes()*100+d.getSeconds()).toString();
      k+=parseInt(j,16).toString(2).padStart(32,"0");
      pc8001.calendar.readreg=k;
      pc8001.calendar.writereg="";
  }
  return (pc8001.calendar.readreg.slice(-1)=="1")?0x10:0;
}
pc8001.calendar.command(4);
pc8001.calendar.shift=function(b){
  var t;
  pc8001.calendar.writereg=(((b&8)==0)?"0":"1")+pc8001.calendar.writereg;
  t=pc8001.calendar.readreg.slice(-1)+pc8001.calendar.readreg.slice(0,-1);
  pc8001.calendar.readreg=t;
  return (t.slice(-1)=="1")?0x10:0;
}
pc8001.z80=new Object();
pc8001.z80.frequency=3000000;                  // down to 3MHz
pc8001.z80.millistates=pc8001.z80.frequency/1000;
pc8001.z80.regs={"PC":0,"SP":0,"A":0,"B":0,"C":0,"D":0,"E":0,"H":0,"L":0,"J":0,"X":0,"K":0,"Y":0,"a":0,"b":0,"c":0,"d":0,"e":0,"h":0,"l":0};
pc8001.z80.flags={"Z":0,"C":0,"V":0,"M":0,"H":0,"N":0,"DUMMY":0,"z":0,"c":0,"v":0,"m":0,"h":0,"n":0,"dummy":0};
pc8001.z80.mnemonics={};
pc8001.z80.halt=pc8001.z80.states=0;
pc8001.z80.ops=new Array(256);
pc8001.z80.ops.fill(["UNDEF","",0]);
pc8001.z80.ops[0xcb]=new Array(257);
pc8001.z80.ops[0xcb].fill(["UNDEF","CB",0]);
pc8001.z80.ops[0xcb][256]=-1;
pc8001.z80.ops[0xdd]=new Array(257);
pc8001.z80.ops[0xdd].fill(["UNDEF","DD",0]);
pc8001.z80.ops[0xdd][256]=-1;
pc8001.z80.ops[0xed]=new Array(257);
pc8001.z80.ops[0xed].fill(["UNDEF","ED",0]);
pc8001.z80.ops[0xed][256]=-1;
pc8001.z80.ops[0xfd]=new Array(257);
pc8001.z80.ops[0xfd].fill(["UNDEF","FD",0]);
pc8001.z80.ops[0xfd][256]=-1;
pc8001.z80.mnemonics["UNDEF"]=function(x,m){
  pc8001.z80.regs["PC"]=(pc8001.z80.regs["PC"]+0xffff)&0xffff;
  pc8001.z80.halt=1;
  console.log(performance.now()-pc8001.z80.millitimer,"milliseconds");
  console.log(pc8001.z80.states,"states");
  console.log(m[0],m[1],x.toString(16).toUpperCase().padStart(2,"0"));
  Object.keys(pc8001.z80.regs).forEach(function(v){
    console.log(" reg",v,pc8001.z80.regs[v].toString(16).toUpperCase().padStart(v.length*2,"0"));
  });
  console.log(" flags",pc8001.z80.flags);
}
pc8001.z80.ops[0x00]=["NOP",4];
pc8001.z80.mnemonics["NOP"]=function(x,m){
}
pc8001.operators=["ADD","ADC","SUB","SBC","AND","XOR","OR","CP"];
pc8001.params=["B","C","D","E","H","L","(HL)","A"];
pc8001.params.forEach(function(v,i,a){
  var j;
  for(j=0;j<8;j++)
    pc8001.z80.ops[i*8+j+0x40]=["LD",v,a[j],(i==6||j==6)?7:4];
  pc8001.z80.ops[i*8+4]=["INC",v,(i==6)?11:4];
  pc8001.z80.ops[i*8+5]=["DEC",v,(i==6)?11:4];
  pc8001.z80.ops[i*8+6]=["LD",v,"n",(i==6)?10:7];
  pc8001.operators.forEach(function(w,j){
    pc8001.z80.ops[i+j*8+0x80]=[w,"A",v,(i==6)?7:4];
  });
  if(i!=6){
    pc8001.z80.ops[0xdd][i*8+0x46]=["LD",v,"(JX+d)",19];
    pc8001.z80.ops[0xdd][i+0x70]=["LD","(JX+d)",v,19];
    pc8001.z80.ops[0xdd][i*8+0x44]=["LD",v,"J",8];
    pc8001.z80.ops[0xdd][i*8+0x45]=["LD",v,"X",8];
    pc8001.z80.ops[0xdd][i+0x60]=["LD","J",v,8];
    pc8001.z80.ops[0xdd][i+0x68]=["LD","X",v,8];
    pc8001.z80.ops[0xfd][i*8+0x46]=["LD",v,"(KY+d)",19];
    pc8001.z80.ops[0xfd][i+0x70]=["LD","(KY+d)",v,19];
    pc8001.z80.ops[0xfd][i*8+0x44]=["LD",v,"K",8];
    pc8001.z80.ops[0xfd][i*8+0x45]=["LD",v,"Y",8];
    pc8001.z80.ops[0xfd][i+0x60]=["LD","K",v,8];
    pc8001.z80.ops[0xfd][i+0x68]=["LD","Y",v,8];
    pc8001.z80.ops[0xed][i*8+0x40]=["IN",v,"(BC)",12];
    pc8001.z80.ops[0xed][i*8+0x41]=["OUT","(BC)",v,12];
  }
  pc8001.z80.ops[0xcb][i+0x00]=["RLC",v,(i==6)?15:8];
  pc8001.z80.ops[0xcb][i+0x08]=["RRC",v,(i==6)?15:8];
  pc8001.z80.ops[0xcb][i+0x10]=["RL",v,(i==6)?15:8];
  pc8001.z80.ops[0xcb][i+0x18]=["RR",v,(i==6)?15:8];
  pc8001.z80.ops[0xcb][i+0x20]=["SLA",v,(i==6)?15:8];
  pc8001.z80.ops[0xcb][i+0x28]=["SRA",v,(i==6)?15:8];
  pc8001.z80.ops[0xcb][i+0x30]=["SLL",v,(i==6)?15:8];
  pc8001.z80.ops[0xcb][i+0x38]=["SRL",v,(i==6)?15:8];
  for(j=0;j<8;j++){
    pc8001.z80.ops[0xcb][i+j*8+0x40]=["BIT",j,v,(i==6)?12:8];
    pc8001.z80.ops[0xcb][i+j*8+0x80]=["RES",j,v,(i==6)?15:8];
    pc8001.z80.ops[0xcb][i+j*8+0xc0]=["SET",j,v,(i==6)?15:8];
  }
});
pc8001.operators.forEach(function(v,i){
  pc8001.z80.ops[i*8+0xc6]=[v,"A","n",7];
  pc8001.z80.ops[0xdd][i*8+0x84]=[v,"A","J",8];
  pc8001.z80.ops[0xdd][i*8+0x85]=[v,"A","X",8];
  pc8001.z80.ops[0xdd][i*8+0x86]=[v,"A","(JX+d)",19];
  pc8001.z80.ops[0xfd][i*8+0x84]=[v,"A","K",8];
  pc8001.z80.ops[0xfd][i*8+0x85]=[v,"A","Y",8];
  pc8001.z80.ops[0xfd][i*8+0x86]=[v,"A","(KY+d)",19];
});
pc8001.z80.ops[0x76]=["HALT","",4];
pc8001.z80.mnemonics["HALT"]=pc8001.z80.mnemonics["UNDEF"];
pc8001.z80.ops[0x02]=["LD","(BC)","A",7];
pc8001.z80.ops[0x0a]=["LD","A","(BC)",7];
pc8001.z80.ops[0x12]=["LD","(DE)","A",7];
pc8001.z80.ops[0x1a]=["LD","A","(DE)",7];
pc8001.z80.ops[0x32]=["LD","(nn)","A",13];
pc8001.z80.ops[0x3a]=["LD","A","(nn)",13];
pc8001.z80.ops[0xdd][0x26]=["LD","J","n",11];
pc8001.z80.ops[0xdd][0x2e]=["LD","X","n",11];
pc8001.z80.ops[0xdd][0x36]=["LD","(JX+d)","n",19];
pc8001.z80.ops[0xdd][0x64]=["LD","J","J",8];
pc8001.z80.ops[0xdd][0x65]=["LD","J","X",8];
pc8001.z80.ops[0xdd][0x6c]=["LD","X","J",8];
pc8001.z80.ops[0xdd][0x6d]=["LD","X","X",8];
pc8001.z80.ops[0xfd][0x26]=["LD","K","n",11];
pc8001.z80.ops[0xfd][0x2e]=["LD","Y","n",11];
pc8001.z80.ops[0xfd][0x36]=["LD","(KY+d)","n",19];
pc8001.z80.ops[0xfd][0x64]=["LD","K","K",8];
pc8001.z80.ops[0xfd][0x65]=["LD","K","Y",8];
pc8001.z80.ops[0xfd][0x6c]=["LD","Y","K",8];
pc8001.z80.ops[0xfd][0x6d]=["LD","Y","Y",8];
pc8001.z80.mnemonics["LD"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a=-1;
  var b,c;
  switch(m[1].length){
    case 4:
      if(m[1]=="(nn)"){
        a=pc8001.memory[pc]+pc8001.memory[(pc+1)&0xffff]*256;
        pc8001.z80.regs["PC"]=pc=(pc+2)&0xffff;
      }
      else
        a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
  }
  switch(m[2].length){
    case 4:
      if(m[2]=="(nn)"){
        b=pc8001.memory[pc]+pc8001.memory[(pc+1)&0xffff]*256;
        pc8001.z80.regs["PC"]=pc=(pc+2)&0xffff;
      }
      else
        b=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      c=pc8001.memory[b];
      break;
    case 6:
      b=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(b>0x7f)
        b+=0xff00;
      b+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      c=pc8001.memory[b&0xffff];
      break;
    default:
      if(m[2]=="n"){
        c=pc8001.memory[pc];
        pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      }
      else
        c=pc8001.z80.regs[m[2]];
  }
  if(a<0)
    pc8001.z80.regs[m[1]]=c;
  else
    pc8001.writeMemory(a,c);
}
pc8001.z80.ops[0x01]=["LD16","BC","nn",10];
pc8001.z80.ops[0x11]=["LD16","DE","nn",10];
pc8001.z80.ops[0x21]=["LD16","HL","nn",10];
pc8001.z80.ops[0x22]=["LD16","(nn)","HL",16];
pc8001.z80.ops[0x2a]=["LD16","HL","(nn)",16];
pc8001.z80.ops[0x31]=["LD16","SP","nn",10];
pc8001.z80.ops[0xf9]=["LD16","SP","HL",6];
pc8001.z80.ops[0xed][0x43]=["LD16","(nn)","BC",20];
pc8001.z80.ops[0xed][0x4b]=["LD16","BC","(nn)",20];
pc8001.z80.ops[0xed][0x53]=["LD16","(nn)","DE",20];
pc8001.z80.ops[0xed][0x5b]=["LD16","DE","(nn)",20];
pc8001.z80.ops[0xed][0x63]=["LD16","(nn)","HL",20];
pc8001.z80.ops[0xed][0x6b]=["LD16","HL","(nn)",20];
pc8001.z80.ops[0xed][0x73]=["LD16","(nn)","SP",20];
pc8001.z80.ops[0xed][0x7b]=["LD16","SP","(nn)",20];
pc8001.z80.ops[0xdd][0x21]=["LD16","JX","nn",14];
pc8001.z80.ops[0xdd][0x22]=["LD16","(nn)","JX",20];
pc8001.z80.ops[0xdd][0x2a]=["LD16","JX","(nn)",20];
pc8001.z80.ops[0xdd][0xf9]=["LD16","SP","JX",10];
pc8001.z80.ops[0xfd][0x21]=["LD16","KY","nn",14];
pc8001.z80.ops[0xfd][0x22]=["LD16","(nn)","KY",20];
pc8001.z80.ops[0xfd][0x2a]=["LD16","KY","(nn)",20];
pc8001.z80.ops[0xfd][0xf9]=["LD16","SP","KY",10];
pc8001.z80.mnemonics["LD16"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var h,l,a;
  switch(m[2]){
    case "nn":
      l=pc8001.memory[pc];
      h=pc8001.memory[(pc+1)&0xffff];
      pc=pc8001.z80.regs["PC"]=(pc+2)&0xffff;
      break;
    case "(nn)":
      a=pc8001.memory[pc]+pc8001.memory[(pc+1)&0xffff]*256;
      pc=pc8001.z80.regs["PC"]=(pc+2)&0xffff;
      l=pc8001.memory[a];
      h=pc8001.memory[(a+1)&0xffff];
      break;
    case "SP":
      a=pc8001.z80.regs["SP"];
      h=a>>8;
      l=a&0xff;
      break;
    default:
      h=pc8001.z80.regs[m[2].substr(0,1)];
      l=pc8001.z80.regs[m[2].substr(1)];
  }
  switch(m[1]){
    case "(nn)":
      a=pc8001.memory[pc]+pc8001.memory[(pc+1)&0xffff]*256;
      pc=pc8001.z80.regs["PC"]=(pc+2)&0xffff;
      pc8001.writeMemory(a,l);
      pc8001.writeMemory((a+1)&0xffff,h);
      return;
    case "SP":
      pc8001.z80.regs["SP"]=h*256+l;
      return;
    default:
      pc8001.z80.regs[m[1].substr(0,1)]=h;
      pc8001.z80.regs[m[1].substr(1)]=l;
  }
}
pc8001.z80.ops[0x08]=["EX","AF","af",4];
pc8001.z80.ops[0xe3]=["EX","(SP)","HL",19];
pc8001.z80.ops[0xeb]=["EX","DE","HL",4];
pc8001.z80.mnemonics["EX"]=function(x,m){
  var a,t;
  if(m[1]=="(SP)"){
    a=pc8001.z80.regs["SP"]
    t=pc8001.memory[a];
    pc8001.writeMemory(a,pc8001.z80.regs[m[2].substr(1)]);
    pc8001.z80.regs[m[2].substr(1)]=t;
    a=(a+1)&0xffff;
    t=pc8001.memory[a];
    pc8001.writeMemory(a,pc8001.z80.regs[m[2].substr(0,1)]);
    pc8001.z80.regs[m[2].substr(0,1)]=t;
    return;
  }
  t=pc8001.z80.regs[m[1].substr(0,1)];
  pc8001.z80.regs[m[1].substr(0,1)]=pc8001.z80.regs[m[2].substr(0,1)];
  pc8001.z80.regs[m[2].substr(0,1)]=t;
  if(m[1].substr(1)=="F"){
    a=["Z","C","V","M","H","N","DUMMY"];
    a.forEach(function(v){
      var b=pc8001.z80.flags[v];
      pc8001.z80.flags[v]=pc8001.z80.flags[v.toLowerCase()];
      pc8001.z80.flags[v.toLowerCase()]=b;
    });
    return;
  }
  t=pc8001.z80.regs[m[1].substr(1)];
  pc8001.z80.regs[m[1].substr(1)]=pc8001.z80.regs[m[2].substr(1)];
  pc8001.z80.regs[m[2].substr(1)]=t;
}
pc8001.z80.ops[0xd9]=["EXX",4];
pc8001.z80.mnemonics["EXX"]=function(x,m){
  var r=["B","C","D","E","H","L"];
  r.forEach(function(v){
    var t=pc8001.z80.regs[v];
    pc8001.z80.regs[v]=pc8001.z80.regs[v.toLowerCase()];
    pc8001.z80.regs[v.toLowerCase()]=t;
  });
}
pc8001.z80.ops[0xdd][0x34]=["INC","(JX+d)",23];
pc8001.z80.ops[0xfd][0x34]=["INC","(KY+d)",23];
pc8001.z80.mnemonics["INC"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  t=(t+1)&0xff;
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["V"]=(t==0x80)?1:0;
  pc8001.z80.flags["H"]=((t&0x0f)==0)?1:0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.ops[0x03]=["INC16","BC",6];
pc8001.z80.ops[0x13]=["INC16","DE",6];
pc8001.z80.ops[0x23]=["INC16","HL",6];
pc8001.z80.ops[0x33]=["INC16","SP",6];
pc8001.z80.ops[0xdd][0x23]=["INC16","JX",10];
pc8001.z80.ops[0xfd][0x23]=["INC16","KY",10];
pc8001.z80.mnemonics["INC16"]=function(x,m){
  var t;
  if(m[1]=="SP")
    pc8001.z80.regs["SP"]=(pc8001.z80.regs["SP"]+1)&0xffff;
  else{
    pc8001.z80.regs[m[1].substr(1)]=t=(pc8001.z80.regs[m[1].substr(1)]+1)&0xff;
    if(t==0)
      pc8001.z80.regs[m[1].substr(0,1)]=(pc8001.z80.regs[m[1].substr(0,1)]+1)&0xff;
  }
}
pc8001.z80.ops[0xdd][0x35]=["DEC","(JX+d)",23];
pc8001.z80.ops[0xfd][0x35]=["DEC","(KY+d)",23];
pc8001.z80.mnemonics["DEC"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  t=(t+0xff)&0xff;
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["V"]=(t==0x7f)?1:0;
  pc8001.z80.flags["H"]=((t&0x0f)==0x0f)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.ops[0x0b]=["DEC16","BC",6];
pc8001.z80.ops[0x1b]=["DEC16","DE",6];
pc8001.z80.ops[0x2b]=["DEC16","HL",6];
pc8001.z80.ops[0x3b]=["DEC16","SP",6];
pc8001.z80.ops[0xdd][0x2b]=["DEC16","JX",6];
pc8001.z80.ops[0xfd][0x2b]=["DEC16","KY",6];
pc8001.z80.mnemonics["DEC16"]=function(x,m){
  var t;
  if(m[1]=="SP")
    pc8001.z80.regs["SP"]=(pc8001.z80.regs["SP"]+0xffff)&0xffff;
  else{
    pc8001.z80.regs[m[1].substr(1)]=t=(pc8001.z80.regs[m[1].substr(1)]+0xff)&0xff;
    if(t==0xff)
      pc8001.z80.regs[m[1].substr(0,1)]=(pc8001.z80.regs[m[1].substr(0,1)]+0xff)&0xff;
  }
}
pc8001.z80.ops[0x09]=["ADD16","HL","BC",11];
pc8001.z80.ops[0x19]=["ADD16","HL","DE",11];
pc8001.z80.ops[0x29]=["ADD16","HL","HL",11];
pc8001.z80.ops[0x39]=["ADD16","HL","SP",11];
pc8001.z80.ops[0xdd][0x09]=["ADD16","JX","BC",15];
pc8001.z80.ops[0xdd][0x19]=["ADD16","JX","DE",15];
pc8001.z80.ops[0xdd][0x29]=["ADD16","JX","JX",15];
pc8001.z80.ops[0xdd][0x39]=["ADD16","JX","SP",15];
pc8001.z80.ops[0xfd][0x09]=["ADD16","KY","BC",15];
pc8001.z80.ops[0xfd][0x19]=["ADD16","KY","DE",15];
pc8001.z80.ops[0xfd][0x29]=["ADD16","KY","KY",15];
pc8001.z80.ops[0xfd][0x39]=["ADD16","KY","SP",15];
pc8001.z80.mnemonics["ADD16"]=function(x,m){
  var t;
  t=pc8001.z80.regs[m[1].substr(0,1)]*256+pc8001.z80.regs[m[1].substr(1)];
  if(m[2]=="SP")
    t+=pc8001.z80.regs["SP"];
  else
    t+=pc8001.z80.regs[m[2].substr(0,1)]*256+pc8001.z80.regs[m[2].substr(1)];
  if(t>0xffff){
    pc8001.z80.flags["C"]=1;
    t&=0xffff;
  }
  else
    pc8001.z80.flags["C"]=0;
  pc8001.z80.regs[m[1].substr(0,1)]=t>>8;
  pc8001.z80.regs[m[1].substr(1)]=t&0xff;
}
pc8001.z80.mnemonics["ADD"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t,u,v;
  switch(m[2].length){
    case 4:
      t=pc8001.memory[pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)]];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      if(m[2]=="n"){
        t=pc8001.memory[pc];
        pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      }
      else
        t=pc8001.z80.regs[m[2]];
  }
  u=pc8001.z80.regs[m[1]];
  v=t+u;
  pc8001.z80.flags["C"]=(v>0xff)?1:0;
  v&=0xff;
  pc8001.z80.regs[m[1]]=v;
  pc8001.z80.flags["Z"]=(v==0)?1:0;
  pc8001.z80.flags["M"]=(v>0x7f)?1:0;
  pc8001.z80.flags["V"]=((t>0x7f&&u>0x7f&&v<0x80)||(t<0x80&&u<0x80&&v>0x7f))?1:0;
  pc8001.z80.flags["H"]=((t&0x0f)+(u&0x0f)>0x0f)?1:0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.ops[0xed][0x4a]=["ADC16","HL","BC",15]
pc8001.z80.ops[0xed][0x5a]=["ADC16","HL","DE",15]
pc8001.z80.ops[0xed][0x6a]=["ADC16","HL","HL",15]
pc8001.z80.ops[0xed][0x7a]=["ADC16","HL","SP",15]
pc8001.z80.mnemonics["ADC16"]=function(x,m){
  var t,u,v;
  t=pc8001.z80.regs[m[1].substr(0,1)]*256+pc8001.z80.regs[m[1].substr(1)];
  if(m[2]=="SP")
    u=pc8001.z80.regs["SP"];
  else
    u=pc8001.z80.regs[m[2].substr(0,1)]*256+pc8001.z80.regs[m[2].substr(1)];
  v=t+u+pc8001.z80.flags["C"]
  if(v>0xffff){
    pc8001.z80.flags["C"]=1;
    v&=0xffff;
  }
  else
    pc8001.z80.flags["C"]=0;
  pc8001.z80.regs[m[1].substr(0,1)]=v>>8;
  pc8001.z80.regs[m[1].substr(1)]=v&0xff;
  pc8001.z80.flags["Z"]=(v==0)?1:0;
  pc8001.z80.flags["M"]=(v>0x7fff)?1:0;
  pc8001.z80.flags["V"]=((u<0x8000&&t<0x8000&&v>0x7fff)||(u>0x7fff&&t>0x7fff&&v<0x8000))?1:0;
}
pc8001.z80.mnemonics["ADC"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t,u,v,c;
  switch(m[2].length){
    case 4:
      t=pc8001.memory[pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)]];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      if(m[2]=="n"){
        t=pc8001.memory[pc];
        pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      }
      else
        t=pc8001.z80.regs[m[2]];
  }
  u=pc8001.z80.regs[m[1]];
  c=pc8001.z80.flags["C"];
  v=t+u+c;
  pc8001.z80.flags["C"]=(v>0xff)?1:0;
  v&=0xff;
  pc8001.z80.regs[m[1]]=v;
  pc8001.z80.flags["Z"]=(v==0)?1:0;
  pc8001.z80.flags["M"]=(v>0x7f)?1:0;
  pc8001.z80.flags["V"]=((t>0x7f&&u>0x7f&&v<0x80)||(t<0x80&&u<0x80&&v>0x7f))?1:0;
  pc8001.z80.flags["H"]=((t&0x0f)+(u&0x0f)+c>0x0f)?1:0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.ops[0xed][0x44]=["NEG","A",8];
pc8001.z80.mnemonics["NEG"]=function(x,m){
  var t=(256-pc8001.z80.regs[m[1]])&0xff;
  pc8001.z80.regs[m[1]]=t;
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["C"]=(t==0)?0:1;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["V"]=(t==0x80)?1:0;
  pc8001.z80.flags["H"]=((t&0x0f)==0)?0:1;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.mnemonics["SUB"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t,u,v;
  switch(m[2].length){
    case 4:
      t=pc8001.memory[pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)]];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      if(m[2]=="n"){
        t=pc8001.memory[pc];
        pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      }
      else
        t=pc8001.z80.regs[m[2]];
  }
  u=pc8001.z80.regs[m[1]];
  v=u-t;
  pc8001.z80.flags["C"]=(v<0)?1:0;
  v=(v+256)&0xff;
  pc8001.z80.regs[m[1]]=v;
  pc8001.z80.flags["Z"]=(v==0)?1:0;
  pc8001.z80.flags["M"]=(v>0x7f)?1:0;
  pc8001.z80.flags["V"]=((u<0x80&&t>0x7f&&v>0x7f)||(u>0x7f&&t<0x80&&v<0x80))?1:0;
  pc8001.z80.flags["H"]=((u&0x0f)-(t&0x0f)<0)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.ops[0xed][0x42]=["SBC16","HL","BC",15]
pc8001.z80.ops[0xed][0x52]=["SBC16","HL","DE",15]
pc8001.z80.ops[0xed][0x62]=["SBC16","HL","HL",15]
pc8001.z80.ops[0xed][0x72]=["SBC16","HL","SP",15]
pc8001.z80.mnemonics["SBC16"]=function(x,m){
  var t,u,v;
  t=pc8001.z80.regs[m[1].substr(0,1)]*256+pc8001.z80.regs[m[1].substr(1)];
  if(m[2]=="SP")
    u=pc8001.z80.regs["SP"];
  else
    u=pc8001.z80.regs[m[2].substr(0,1)]*256+pc8001.z80.regs[m[2].substr(1)];
  v=t-u-pc8001.z80.flags["C"]
  if(v<0){
    pc8001.z80.flags["C"]=1;
    v=(v+65536)&0xffff;
  }
  else
    pc8001.z80.flags["C"]=0;
  pc8001.z80.regs[m[1].substr(0,1)]=v>>8;
  pc8001.z80.regs[m[1].substr(1)]=v&0xff;
  pc8001.z80.flags["Z"]=(v==0)?1:0;
  pc8001.z80.flags["M"]=(v>0x7fff)?1:0;
  pc8001.z80.flags["V"]=((u<0x8000&&t>0x7fff&&v>0x7fff)||(u>0x7fff&&t<0x8000&&v<0x8000))?1:0;
}
pc8001.z80.mnemonics["SBC"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t,u,v,c;
  switch(m[2].length){
    case 4:
      t=pc8001.memory[pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)]];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      if(m[2]=="n"){
        t=pc8001.memory[pc];
        pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      }
      else
        t=pc8001.z80.regs[m[2]];
  }
  u=pc8001.z80.regs[m[1]];
  c=pc8001.z80.flags["C"];
  v=u-t-c;
  pc8001.z80.flags["C"]=(v<0)?1:0;
  v=(v+256)&0xff;
  pc8001.z80.regs[m[1]]=v;
  pc8001.z80.flags["Z"]=(v==0)?1:0;
  pc8001.z80.flags["M"]=(v>0x7f)?1:0;
  pc8001.z80.flags["V"]=((u<0x80&&t>0x7f&&v>0x7f)||(u>0x7f&&t<0x80&&v<0x80))?1:0;
  pc8001.z80.flags["H"]=((u&0x0f)-(t&0x0f)-c<0)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.mnemonics["AND"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t;
  switch(m[2].length){
    case 4:
      t=pc8001.memory[pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)]];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      if(m[2]=="n"){
        t=pc8001.memory[pc];
        pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      }
      else
        t=pc8001.z80.regs[m[2]];
  }
  t&=pc8001.z80.regs[m[1]];
  pc8001.z80.regs[m[1]]=t;
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["C"]=0;
  pc8001.z80.flags["H"]=1
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.ops[0x2f]=["CPL","A",4];
pc8001.z80.mnemonics["CPL"]=function(x,m){
  pc8001.z80.regs[m[1]]^=0xff;
  pc8001.z80.flags["H"]=1;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.mnemonics["XOR"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t;
  switch(m[2].length){
    case 4:
      t=pc8001.memory[pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)]];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      if(m[2]=="n"){
        t=pc8001.memory[pc];
        pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      }
      else
        t=pc8001.z80.regs[m[2]];
  }
  t^=pc8001.z80.regs[m[1]];
  pc8001.z80.regs[m[1]]=t;
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["C"]=0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.mnemonics["OR"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t;
  switch(m[2].length){
    case 4:
      t=pc8001.memory[pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)]];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      if(m[2]=="n"){
        t=pc8001.memory[pc];
        pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      }
      else
        t=pc8001.z80.regs[m[2]];
  }
  t|=pc8001.z80.regs[m[1]];
  pc8001.z80.regs[m[1]]=t;
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["C"]=0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.mnemonics["CP"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var a,t,u,v;
  switch(m[2].length){
    case 4:
      t=pc8001.memory[pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)]];
      break;
    case 6:
      a=pc8001.memory[pc];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      if(m[2]=="n"){
        t=pc8001.memory[pc];
        pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      }
      else
        t=pc8001.z80.regs[m[2]];
  }
  u=pc8001.z80.regs[m[1]];
  v=u-t;
  pc8001.z80.flags["C"]=(v<0)?1:0;
  v=(v+256)&0xff;
  pc8001.z80.flags["Z"]=(v==0)?1:0;
  pc8001.z80.flags["M"]=(v>0x7f)?1:0;
  pc8001.z80.flags["V"]=((u<0x80&&t>0x7f&&v>0x7f)||(u>0x7f&&t<0x80&&v<0x80))?1:0;
  pc8001.z80.flags["H"]=((u&0x0f)-(t&0x0f)<0)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.ops[0x37]=["SCF",4];
pc8001.z80.mnemonics["SCF"]=function(x,m){
  pc8001.z80.flags["C"]=1;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.ops[0x3f]=["CCF",4];
pc8001.z80.mnemonics["CCF"]=function(x,m){
  pc8001.z80.flags["C"]^=1;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.ops[0x27]=["DAA",4];
pc8001.z80.mnemonics["DAA"]=function(x,m){
  var t=pc8001.z80.regs["A"];
  var v;
  if(pc8001.z80.flags["N"]==0){
    if(pc8001.z80.flags["C"]==0){
      v=((t>0x99)?0x60:0)+(((pc8001.z80.flags["H"]==1||(t&0x0f)>9))?6:0);
      pc8001.z80.flags["C"]=(t>0x99)?1:0;
    }
    else
      v=((pc8001.z80.flags["H"]==1)||((t&0x0f)>9)?0x66:0x60);
    pc8001.z80.flags["H"]=((t&0x0f)>9)?1:0;
  }
  else{
    if(pc8001.z80.flags["C"]==0){
      if(pc8001.z80.flags["H"]==0)
        v=((t>0x99)?0xa0:0)+(((t&0x0f)>9)?0xfa:0);
      else{
        v=(t>0x99)?0x9a:0xfa;
        pc8001.z80.flags["H"]=((t&0x0f)<6)?1:0;
      }
      pc8001.z80.flags["C"]=(t>0x99)?1:0;
    }
    else{
      v=(pc8001.z80.flags["H"]==0&&((t&0x0f)<10))?0xa0:0x9a;
      pc8001.z80.flags["H"]&=((t&0x0f)<6)?1:0;
    }
  }
  pc8001.z80.regs["A"]=(t+v)&0xff;
}
pc8001.z80.ops[0xc2]=["JP","NZ","nn",10];
pc8001.z80.ops[0xc3]=["JP","","nn",10];
pc8001.z80.ops[0xca]=["JP","Z","nn",10];
pc8001.z80.ops[0xd2]=["JP","NC","nn",10];
pc8001.z80.ops[0xda]=["JP","C","nn",10];
pc8001.z80.ops[0xe2]=["JP","NV","nn",10];
pc8001.z80.ops[0xea]=["JP","V","nn",10];
pc8001.z80.ops[0xf2]=["JP","NM","nn",10];
pc8001.z80.ops[0xfa]=["JP","M","nn",10];
pc8001.z80.ops[0xe9]=["JP","","(HL)",4];
pc8001.z80.ops[0xdd][0xe9]=["JP","","(JX)",8];
pc8001.z80.ops[0xfd][0xe9]=["JP","","(KY)",8];
pc8001.z80.mnemonics["JP"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var c=1;
  switch(m[1].length){
    case 1:
      c=pc8001.z80.flags[m[1]];
      break;
    case 2:
      c=1-pc8001.z80.flags[m[1].substr(1)];
  }
  if(c==0){
    if(m[2]=="nn")
      pc8001.z80.regs["PC"]=(pc+2)&0xffff;
    return;
  }
  switch(m[2].length){
    case 2:
      pc8001.z80.regs["PC"]=pc8001.memory[pc]+pc8001.memory[(pc+1)&0xffff]*256;
      return;
    case 4:
      pc8001.z80.regs["PC"]=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      return;
  }
}
pc8001.z80.ops[0x10]=["JR","DJNZ","e",13];
pc8001.z80.ops[0x18]=["JR","","e",12];
pc8001.z80.ops[0x20]=["JR","NZ","e",12];
pc8001.z80.ops[0x28]=["JR","Z","e",12];
pc8001.z80.ops[0x30]=["JR","NC","e",12];
pc8001.z80.ops[0x38]=["JR","C","e",12];
pc8001.z80.mnemonics["JR"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var c=1;
  switch(m[1].length){
    case 1:
      c=pc8001.z80.flags[m[1]];
      break;
    case 2:
      c=1-pc8001.z80.flags[m[1].substr(1)];
      break;
    case 4:
      pc8001.z80.regs["B"]=c=(pc8001.z80.regs["B"]+0xff)&0xff;
  }
  if(c==0){
    if(m[2]=="e")
      pc8001.z80.regs["PC"]=(pc+1)&0xffff;
    return;
  }
  c=pc8001.memory[pc];
  pc8001.z80.regs["PC"]=((c>0x7f)?pc+0xff01+c:pc+1+c)&0xffff;
}
pc8001.z80.ops[0xc4]=["CALL","NZ","nn",17];
pc8001.z80.ops[0xc7]=["CALL","","0000",11];
pc8001.z80.ops[0xcc]=["CALL","Z","nn",17];
pc8001.z80.ops[0xcd]=["CALL","","nn",17];
pc8001.z80.ops[0xcf]=["CALL","","0008",11];
pc8001.z80.ops[0xd4]=["CALL","NC","nn",17];
pc8001.z80.ops[0xd7]=["CALL","","0010",11];
pc8001.z80.ops[0xdc]=["CALL","C","nn",17];
pc8001.z80.ops[0xdf]=["CALL","","0018",11];
pc8001.z80.ops[0xe4]=["CALL","NV","nn",17];
pc8001.z80.ops[0xe7]=["CALL","","0020",11];
pc8001.z80.ops[0xec]=["CALL","V","nn",17];
pc8001.z80.ops[0xef]=["CALL","","0028",11];
pc8001.z80.ops[0xf4]=["CALL","NM","nn",17];
pc8001.z80.ops[0xf7]=["CALL","","0030",11];
pc8001.z80.ops[0xfc]=["CALL","M","nn",17];
pc8001.z80.ops[0xff]=["CALL","","0038",11];
pc8001.z80.mnemonics["CALL"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var sp=pc8001.z80.regs["SP"];
  var c=1;
  switch(m[1].length){
    case 1:
      c=pc8001.z80.flags[m[1]];
      break;
    case 2:
      c=1-pc8001.z80.flags[m[1].substr(1)];
  }
  if(c==0){
    if(m[2]=="nn")
      pc8001.z80.regs["PC"]=(pc+2)&0xffff;
    return;
  }
  if(m[2]=="nn"){
    a=pc8001.memory[pc]+pc8001.memory[(pc+1)&0xffff]*256;
    pc=(pc+2)&0xffff;
  }
  else
    a=parseInt(m[2],16);
  pc8001.writeMemory((sp+0xffff)&0xffff,pc>>8);
  pc8001.z80.regs["SP"]=sp=(sp+0xfffe)&0xffff;
  pc8001.writeMemory(sp,pc&0xff);
  pc8001.z80.regs["PC"]=a;
}
pc8001.z80.ops[0xc0]=["RET","NZ",11];
pc8001.z80.ops[0xc8]=["RET","Z",11];
pc8001.z80.ops[0xc9]=["RET","",10];
pc8001.z80.ops[0xd0]=["RET","NC",11];
pc8001.z80.ops[0xd8]=["RET","C",11];
pc8001.z80.ops[0xe0]=["RET","NV",11];
pc8001.z80.ops[0xe8]=["RET","V",11];
pc8001.z80.ops[0xf0]=["RET","NM",11];
pc8001.z80.ops[0xf8]=["RET","M",11];
pc8001.z80.mnemonics["RET"]=function(x,m){
  var sp=pc8001.z80.regs["SP"];
  var c=1;
  switch(m[1].length){
    case 1:
      c=pc8001.z80.flags[m[1]];
      break;
    case 2:
      c=1-pc8001.z80.flags[m[1].substr(1)];
  }
  if(c==0)
    return;
  pc8001.z80.regs["PC"]=pc8001.memory[sp]+pc8001.memory[(sp+1)&0xffff]*256;
  pc8001.z80.regs["SP"]=(sp+2)&0xffff;
}
pc8001.z80.ops[0xc5]=["PUSH","BC",11];
pc8001.z80.ops[0xd5]=["PUSH","DE",11];
pc8001.z80.ops[0xe5]=["PUSH","HL",11];
pc8001.z80.ops[0xf5]=["PUSH","AF",11];
pc8001.z80.ops[0xdd][0xe5]=["PUSH","JX",15];
pc8001.z80.ops[0xfd][0xe5]=["PUSH","KY",15];
pc8001.z80.mnemonics["PUSH"]=function(x,m){
  var sp=pc8001.z80.regs["SP"];
  pc8001.writeMemory((sp+0xffff)&0xffff,pc8001.z80.regs[m[1].substr(0,1)]);
  pc8001.z80.regs["SP"]=sp=(sp+0xfffe)&0xffff;
  if(m[1]=="AF")
    pc8001.writeMemory(sp,(pc8001.z80.flags["DUMMY"]&0x28)|pc8001.z80.flags["C"]|(pc8001.z80.flags["N"]<<1)|(pc8001.z80.flags["V"]<<2)|(pc8001.z80.flags["H"]<<4)|(pc8001.z80.flags["Z"]<<6)|(pc8001.z80.flags["M"]<<7));
  else
    pc8001.writeMemory(sp,pc8001.z80.regs[m[1].substr(1)]);
}
pc8001.z80.ops[0xc1]=["POP","BC",10];
pc8001.z80.ops[0xd1]=["POP","DE",10];
pc8001.z80.ops[0xe1]=["POP","HL",10];
pc8001.z80.ops[0xf1]=["POP","AF",10];
pc8001.z80.ops[0xdd][0xe1]=["POP","JX",14];
pc8001.z80.ops[0xfd][0xe1]=["POP","KY",14];
pc8001.z80.mnemonics["POP"]=function(x,m){
  var sp=pc8001.z80.regs["SP"];
  var t=pc8001.memory[sp];
  if(m[1]=="AF"){
    pc8001.z80.flags["C"]=((t&1)==0)?0:1;
    pc8001.z80.flags["N"]=((t&2)==0)?0:1;
    pc8001.z80.flags["V"]=((t&4)==0)?0:1;
    pc8001.z80.flags["H"]=((t&0x10)==0)?0:1;
    pc8001.z80.flags["Z"]=((t&0x40)==0)?0:1;
    pc8001.z80.flags["M"]=((t&0x80)==0)?0:1;
    pc8001.z80.flags["DUMMY"]=t;
  }
  else
    pc8001.z80.regs[m[1].substr(1)]=t;
  pc8001.z80.regs[m[1].substr(0,1)]=pc8001.memory[(sp+1)&0xffff];
  pc8001.z80.regs["SP"]=(sp+2)&0xffff;
}
pc8001.z80.ops[0x07]=["RLCA",4];
pc8001.z80.mnemonics["RLCA"]=function(x,m){
  var t=pc8001.z80.regs["A"];
  var c=(t>0x7f)?1:0;
  pc8001.z80.regs["A"]=((t<<1)+c)&0xff;
  pc8001.z80.flags["C"]=c;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.mnemonics["RLC"]=function(x,m){
  var a,t,c;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[1].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  c=(t>0x7f)?1:0;
  t=((t<<1)+c)&0xff;
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["C"]=c;
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.ops[0x0f]=["RRCA",4];
pc8001.z80.mnemonics["RRCA"]=function(x,m){
  var t=pc8001.z80.regs["A"];
  var c=t&1;
  pc8001.z80.regs["A"]=(t>>1)+c*0x80;
  pc8001.z80.flags["C"]=c;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.mnemonics["RRC"]=function(x,m){
  var a,t,c;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[1].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  c=t&1;
  t=(t>>1)+c*0x80;
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["C"]=c;
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.ops[0x17]=["RLA",4];
pc8001.z80.mnemonics["RLA"]=function(x,m){
  var t=pc8001.z80.regs["A"];
  var c=(t>0x7f)?1:0;
  pc8001.z80.regs["A"]=((t<<1)+pc8001.z80.flags["C"])&0xff;
  pc8001.z80.flags["C"]=c;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.mnemonics["RL"]=function(x,m){
  var a,t,c;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[1].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  c=(t>0x7f)?1:0;
  t=((t<<1)+pc8001.z80.flags["C"])&0xff;
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["C"]=c;
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.ops[0x1f]=["RRA",4];
pc8001.z80.mnemonics["RRA"]=function(x,m){
  var t=pc8001.z80.regs["A"];
  pc8001.z80.regs["A"]=(t>>1)+pc8001.z80.flags["C"]*0x80;
  pc8001.z80.flags["C"]=t&1;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.mnemonics["RR"]=function(x,m){
  var a,t,c;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[1].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  c=t&1;
  t=(t>>1)+pc8001.z80.flags["C"]*0x80;
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["C"]=c;
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.mnemonics["SLA"]=function(x,m){
  var a,t;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[1].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  t=t<<1;
  pc8001.z80.flags["C"]=(t>0xff)?1:0;
  t&=0xff;
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.mnemonics["SRA"]=function(x,m){
  var a,t;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[1].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  pc8001.z80.flags["C"]=t&1;
  t=((t>>1)|(t&0x80));
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.mnemonics["SLL"]=function(x,m){
  var a,t;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[1].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  t=(t<<1)|1;
  pc8001.z80.flags["C"]=(t>0xff)?1:0;
  t&=0xff;
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.mnemonics["SRL"]=function(x,m){
  var a,t;
  switch(m[1].length){
    case 4:
      a=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[1].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[1]];
  }
  pc8001.z80.flags["C"]=t&1;
  t=t>>1;
  if(a<0)
    pc8001.z80.regs[m[1]]=t;
  else
    pc8001.writeMemory(a,t);
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.mnemonics["BIT"]=function(x,m){
  var a,t;
  switch(m[2].length){
    case 4:
      a=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[2].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[2]];
  }
  pc8001.z80.flags["Z"]=((t&(1<<m[1]))==0)?1:0;
  pc8001.z80.flags["H"]=1;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.mnemonics["RES"]=function(x,m){
  var a,t
  switch(m[2].length){
    case 4:
      a=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[2].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[2]]
  }
  t&=(1<<m[1])^0xff;
  if(a<0)
    pc8001.z80.regs[m[2]]=t;
  else
    pc8001.writeMemory(a,t);
}
pc8001.z80.mnemonics["SET"]=function(x,m){
  var a,t;
  switch(m[2].length){
    case 4:
      a=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      t=pc8001.memory[a];
      break;
    case 7:
      a=parseInt(m[2].substr(4,2),16);
      if(a>0x7f)
        a+=0xff00;
      a+=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
      a&=0xffff;
      t=pc8001.memory[a];
      break;
    default:
      a=-1;
      t=pc8001.z80.regs[m[2]]
  }
  t|=1<<m[1];
  if(a<0)
    pc8001.z80.regs[m[2]]=t;
  else
    pc8001.writeMemory(a,t);
}
pc8001.z80.ops[0xed][0x67]=["RRD",18];
pc8001.z80.mnemonics["RRD"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var c=pc8001.memory[hl];
  var t=pc8001.z80.regs["A"];
  pc8001.writeMemory(hl,(c>>4)|((t<<4)&0xf0))
  pc8001.z80.regs["A"]=t=(t&0xf0)|(c&0x0f);
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.ops[0xed][0x6f]=["RLD",18];
pc8001.z80.mnemonics["RLD"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var c=pc8001.memory[hl];
  var t=pc8001.z80.regs["A"];
  pc8001.writeMemory(hl,((c<<4)&0xf0)|(t&0x0f))
  pc8001.z80.regs["A"]=t=(t&0xf0)|(c>>4);
  pc8001.z80.flags["Z"]=(t==0)?1:0;
  pc8001.z80.flags["M"]=(t>0x7f)?1:0;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
  t=(((t>>6)|4)^(t>>3)^t)&3;
  pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
}
pc8001.z80.ops[0xed][0xa0]=["LDI",16];
pc8001.z80.mnemonics["LDI"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var de=pc8001.z80.regs["D"]*256+pc8001.z80.regs["E"];
  var bc=pc8001.z80.regs["B"]*256+pc8001.z80.regs["C"];
  pc8001.writeMemory(de,pc8001.memory[hl]);
  hl=(hl+1)&0xffff;
  de=(de+1)&0xffff;
  bc=(bc+0xffff)&0xffff;
  pc8001.z80.regs["H"]=hl>>8;
  pc8001.z80.regs["L"]=hl&0xff;
  pc8001.z80.regs["D"]=de>>8;
  pc8001.z80.regs["E"]=de&0xff;
  pc8001.z80.regs["B"]=bc>>8;
  pc8001.z80.regs["C"]=bc&0xff;
  pc8001.z80.flags["V"]=(bc==0)?0:1;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.ops[0xed][0xb0]=["LDIR",21];
pc8001.z80.mnemonics["LDIR"]=function(x,m){
  pc8001.z80.mnemonics["LDI"](x,m);
  if(pc8001.z80.flags["V"]==1)
    pc8001.z80.regs["PC"]=(pc8001.z80.regs["PC"]+0xfffe)&0xffff;
}
pc8001.z80.ops[0xed][0xa8]=["LDD",16];
pc8001.z80.mnemonics["LDD"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var de=pc8001.z80.regs["D"]*256+pc8001.z80.regs["E"];
  var bc=pc8001.z80.regs["B"]*256+pc8001.z80.regs["C"];
  pc8001.writeMemory(de,pc8001.memory[hl]);
  hl=(hl+0xffff)&0xffff;
  de=(de+0xffff)&0xffff;
  bc=(bc+0xffff)&0xffff;
  pc8001.z80.regs["H"]=hl>>8;
  pc8001.z80.regs["L"]=hl&0xff;
  pc8001.z80.regs["D"]=de>>8;
  pc8001.z80.regs["E"]=de&0xff;
  pc8001.z80.regs["B"]=bc>>8;
  pc8001.z80.regs["C"]=bc&0xff;
  pc8001.z80.flags["V"]=(bc==0)?0:1;
  pc8001.z80.flags["H"]=0;
  pc8001.z80.flags["N"]=0;
}
pc8001.z80.ops[0xed][0xb8]=["LDDR",21];
pc8001.z80.mnemonics["LDDR"]=function(x,m){
  pc8001.z80.mnemonics["LDD"](x,m);
  if(pc8001.z80.flags["V"]==1)
    pc8001.z80.regs["PC"]=(pc8001.z80.regs["PC"]+0xfffe)&0xffff;
}
pc8001.z80.ops[0xed][0xa1]=["CPI",16];
pc8001.z80.mnemonics["CPI"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var bc=pc8001.z80.regs["B"]*256+pc8001.z80.regs["C"];
  var t=pc8001.z80.regs["A"];
  var u=pc8001.memory[hl];
  var v=(t-u+256)&0xff;
  hl=(hl+1)&0xffff;
  bc=(bc+0xffff)&0xffff;
  pc8001.z80.regs["H"]=hl>>8;
  pc8001.z80.regs["L"]=hl&0xff;
  pc8001.z80.regs["B"]=bc>>8;
  pc8001.z80.regs["C"]=bc&0xff;
  pc8001.z80.flags["Z"]=(v==0)?1:0;
  pc8001.z80.flags["M"]=(v>0x7f)?1:0;
  pc8001.z80.flags["V"]=(bc==0)?0:1;
  pc8001.z80.flags["H"]=((t&0x0f)-(u&0x0f)<0)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.ops[0xed][0xb1]=["CPIR",21];
pc8001.z80.mnemonics["CPIR"]=function(x,m){
  pc8001.z80.mnemonics["CPI"](x,m);
  if(pc8001.z80.flags["V"]==1&&pc8001.z80.flags["Z"]==0)
    pc8001.z80.regs["PC"]=(pc8001.z80.regs["PC"]+0xfffe)&0xffff;
}
pc8001.z80.ops[0xed][0xa9]=["CPD",16];
pc8001.z80.mnemonics["CPD"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var bc=pc8001.z80.regs["B"]*256+pc8001.z80.regs["C"];
  var t=pc8001.z80.regs["A"];
  var u=pc8001.memory[hl];
  var v=(t-u+256)&0xff;
  hl=(hl+0xffff)&0xffff;
  bc=(bc+0xffff)&0xffff;
  pc8001.z80.regs["H"]=hl>>8;
  pc8001.z80.regs["L"]=hl&0xff;
  pc8001.z80.regs["B"]=bc>>8;
  pc8001.z80.regs["C"]=bc&0xff;
  pc8001.z80.flags["Z"]=(v==0)?1:0;
  pc8001.z80.flags["M"]=(v>0x7f)?1:0;
  pc8001.z80.flags["V"]=(bc==0)?0:1;
  pc8001.z80.flags["H"]=((t&0x0f)-(u&0x0f)<0)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.ops[0xed][0xb9]=["CPDR",21];
pc8001.z80.mnemonics["CPDR"]=function(x,m){
  pc8001.z80.mnemonics["CPD"](x,m);
  if(pc8001.z80.flags["V"]==1&&pc8001.z80.flags["Z"]==0)
    pc8001.z80.regs["PC"]=(pc8001.z80.regs["PC"]+0xfffe)&0xffff;
}
pc8001.z80.ops[0xdb]=["IN","A","(n)",11];
pc8001.z80.mnemonics["IN"]=function(x,m){
  var c,t,pc;
  if(m[2]=="(n)"){
    pc=pc8001.z80.regs["PC"];
    c=pc8001.memory[pc]+pc8001.z80.regs[m[1]]*256;
    pc8001.z80.regs["PC"]=(pc+1)&0xffff;
  }
  else
    c=pc8001.z80.regs[m[2].substr(1,1)]*256+pc8001.z80.regs[m[2].substr(2,1)];
  pc8001.z80.regs[m[1]]=t=pc8001.inport16(c);
  if(m[2]!="(n)"){
    pc8001.z80.flags["Z"]=(t==0)?1:0;
    pc8001.z80.flags["M"]=(t>0x7f)?1:0;
    pc8001.z80.flags["H"]=0;
    pc8001.z80.flags["N"]=0;
    t=(((t>>6)|4)^(t>>3)^t)&3;
    pc8001.z80.flags["V"]=((t>>2)^(t>>1)^t)&1;
  }
}
pc8001.z80.ops[0xed][0xa2]=["INI",16];
pc8001.z80.mnemonics["INI"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var b=(pc8001.z80.regs["B"]+0xff)&0xff;
  pc8001.writeMemory(hl,pc8001.inport16(b*256+pc8001.z80.regs["C"]));
  hl=(hl+1)&0xffff;
  pc8001.z80.regs["H"]=hl>>8;
  pc8001.z80.regs["L"]=hl&0xff;
  pc8001.z80.regs["B"]=b;
  pc8001.z80.flags["Z"]=(b==0)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.ops[0xed][0xb2]=["INIR",21];
pc8001.z80.mnemonics["INIR"]=function(x,m){
  pc8001.z80.mnemonics["INI"](x,m);
  if(pc8001.z80.flags["Z"]==0)
    pc8001.z80.regs["PC"]=(pc8001.z80.regs["PC"]+0xfffe)&0xffff;
}
pc8001.z80.ops[0xed][0xaa]=["IND",16];
pc8001.z80.mnemonics["IND"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var b=(pc8001.z80.regs["B"]+0xff)&0xff;
  pc8001.writeMemory(hl,pc8001.inport16(b*256+pc8001.z80.regs["C"]));
  hl=(hl+0xffff)&0xffff;
  pc8001.z80.regs["H"]=hl>>8;
  pc8001.z80.regs["L"]=hl&0xff;
  pc8001.z80.regs["B"]=b;
  pc8001.z80.flags["Z"]=(b==0)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.ops[0xed][0xba]=["INDR",21];
pc8001.z80.mnemonics["INDR"]=function(x,m){
  pc8001.z80.mnemonics["IND"](x,m);
  if(pc8001.z80.flags["Z"]==0)
    pc8001.z80.regs["PC"]=(pc8001.z80.regs["PC"]+0xfffe)&0xffff;
}
pc8001.inport16=function(p){
  return pc8001.inports[p&0xff];
}
pc8001.z80.ops[0xd3]=["OUT","(n)","A",11];
pc8001.z80.mnemonics["OUT"]=function(x,m){
  var c,pc;
  if(m[1]=="(n)"){
    pc=pc8001.z80.regs["PC"];
    c=pc8001.memory[pc]+pc8001.z80.regs[m[2]]*256;
    pc8001.z80.regs["PC"]=(pc+1)&0xffff;
  }
  else
    c=pc8001.z80.regs[m[1].substr(1,1)]*256+pc8001.z80.regs[m[1].substr(2,1)];
  pc8001.outport16(c,pc8001.z80.regs[m[2]]);
}
pc8001.z80.ops[0xed][0xa3]=["OUTI",16];
pc8001.z80.mnemonics["OUTI"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var b=(pc8001.z80.regs["B"]+0xff)&0xff;
  pc8001.outport16(b*256+pc8001.z80.regs["C"],pc8001.memory[hl]);
  hl=(hl+1)&0xffff;
  pc8001.z80.regs["H"]=hl>>8;
  pc8001.z80.regs["L"]=hl&0xff;
  pc8001.z80.regs["B"]=b;
  pc8001.z80.flags["Z"]=(b==0)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.ops[0xed][0xb3]=["OTIR",21];
pc8001.z80.mnemonics["OTIR"]=function(x,m){
  pc8001.z80.mnemonics["OUTI"](x,m);
  if(pc8001.z80.flags["Z"]==0)
    pc8001.z80.regs["PC"]=(pc8001.z80.regs["PC"]+0xfffe)&0xffff;
}
pc8001.z80.ops[0xed][0xab]=["OUTD",16];
pc8001.z80.mnemonics["OUTD"]=function(x,m){
  var hl=pc8001.z80.regs["H"]*256+pc8001.z80.regs["L"];
  var b=(pc8001.z80.regs["B"]+0xff)&0xff;
  pc8001.outport16(b*256+pc8001.z80.regs["C"],pc8001.memory[hl]);
  hl=(hl+0xffff)&0xffff;
  pc8001.z80.regs["H"]=hl>>8;
  pc8001.z80.regs["L"]=hl&0xff;
  pc8001.z80.regs["B"]=b;
  pc8001.z80.flags["Z"]=(b==0)?1:0;
  pc8001.z80.flags["N"]=1;
}
pc8001.z80.ops[0xed][0xbb]=["OTDR",21];
pc8001.z80.mnemonics["OTDR"]=function(x,m){
  pc8001.z80.mnemonics["OUTD"](x,m);
  if(pc8001.z80.flags["Z"]==0)
    pc8001.z80.regs["PC"]=(pc8001.z80.regs["PC"]+0xfffe)&0xffff;
}
pc8001.outport16=function(p,d){
  var t=pc8001.outports[p&0xff];
  pc8001.outports[p&0xff]=d;
  switch(p&0xff){
    case 0x10:
      return;
    case 0x30:
      if((d^t)==1)
        pc8001.resizeDisplay(((d&1)==1)?80:40,25);
      return;
    case 0x40:
      pc8001.beep.on=((d&0x20)==0)?0:1;
      if(((d^t)&6)!=0){
        switch(d&6){
          case 2:
            t=pc8001.calendar.command(pc8001.outports[0x10]);
            break;
          case 4:
            t=pc8001.calendar.shift(pc8001.outports[0x10]);
            break;
          default:
            return;
        }
        if(t==0)
          pc8001.inports[0x40]&=0xef;
        else
          pc8001.inports[0x40]|=0x10;
      }
      return;
    case 0x51:
      switch(d){
        case 0x20:
          pc8001.reverseDisplay(0);
          return;
        case 0x21:
          pc8001.reverseDisplay(1);
          return;
      }
      console.log("OUT (51H),",d);
      return;
  }
  pc8001.z80.mnemonics["UNDEF"](p&0xff,["UNDEF","OUT",0]);
}
pc8001.z80.ops[0xdd][0xcb]=["EXTCB","DD CB dd","JX",20];
pc8001.z80.ops[0xfd][0xcb]=["EXTCB","FD CB dd","KY",20];
pc8001.z80.mnemonics["EXTCB"]=function(x,m){
  var pc=pc8001.z80.regs["PC"];
  var d=pc8001.memory[pc];
  var e=pc8001.memory[(pc+1)&0xffff];
  var f=pc8001.z80.ops[0xcb][e].slice();
  pc8001.z80.regs["PC"]=(pc+2)&0xffff;
  if(f[f.length-2]=="(HL)"){
    f[f.length-2]="("+m[2]+"+"+d.toString(16).padStart(2,"0")+")";
    pc8001.z80.mnemonics[f[0]](e,f);
    return;
  }
  pc8001.z80.mnemonics["UNDEF"](e,["UNDEF",m[1],0]);
}
pc8001.z80.run=function(){
  var i,pc,v,m,s;
  for(i=0;i<4000;i++){
    pc=pc8001.z80.regs["PC"];
    v=pc8001.memory[pc];
    m=pc8001.z80.ops[v];
    pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
    s=m[m.length-1];
    if(s<0){
      v=pc8001.memory[pc];
      m=m[v];
      pc8001.z80.regs["PC"]=pc=(pc+1)&0xffff;
      s=m[m.length-1];
    }
    pc8001.z80.states+=s;
    pc8001.z80.mnemonics[m[0]](v,m);
    if(pc8001.z80.halt==1)
      return;
    if(pc8001.beep.counter!=-1){
      v=Math.floor(pc8001.z80.states*pc8001.beep.audio.sampleRate/pc8001.z80.frequency)%pc8001.beep.refWave.length;
      if(v==pc8001.beep.counter){
        pc8001.beep.wave[v]=pc8001.beep.on*pc8001.beep.refWave[v];
        pc8001.beep.counter=(pc8001.beep.counter+1)%pc8001.beep.refWave.length;
      }
    }
    s=pc8001.z80.states-(performance.now()-pc8001.z80.millitimer)*pc8001.z80.millistates;
    if(s>1000)
      break;
  }
  if(s<0){
    pc8001.z80.states%=pc8001.z80.frequency;
    pc8001.z80.millitimer=performance.now()-pc8001.z80.states/pc8001.z80.millistates;
  }
  pc8001.z80.timer=setTimeout("clearTimeout(pc8001.z80.timer);pc8001.z80.run()",(s>1000)?s/pc8001.z80.millistates:0);
}
pc8001.run=function(){
  document.addEventListener("keydown",pc8001.keydown);
  document.addEventListener("keyup",pc8001.keyup);
  pc8001.z80.millitimer=performance.now();
  pc8001.z80.run();
}
</script>
<style>
.blink{
  animation: blink 1.5s step-end infinite
}
@keyframes blink{
  0% {opacity:1}
  75% {opacity:0}
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg"
 xmlns:xlink="http://www.w3.org/1999/xlink"
 width=984 height=624 viewBox="-2 -2 164 104"
 style="background-color:black"
 onload="pc8001.initDisplay(this);pc8001.run()">
</svg>
</body>
</html>
```