JavaScriptによるZ80エミュレータでの「手抜き」直線

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428317/425b375d-6e48-4532-b8a7-178752da9ed7.gif" width="100%" />

40年前の私(安岡孝一)が、PC-8001向けゲーム『[4次元迷路](https://qiita.com/KoichiYasuoka/items/c2df39df012f256199fa)』(cf.第1回アスキーソフトウェアコンテスト審査発表, ASCII, Vol.8, No.3 (1984年3月), pp.165-172)を設計した際に、うまく実装できなかった機能として、上に示すような「視点のπ/2回転」がある。今さら実装するのも何なのだが、ちょっと考えてみることにしよう。

画面中心を(0,0)とするとき、壁縁の垂直線端を(h×tanθ, ±h)とおくと、左側の消失点は(h×(tanθ+tan(θ/2-3π/8)), 0)、右側の消失点は(h×(tanθ+tan(θ/2+3π/8)), 0)となる。h=6<sup>2</sup>=36で考えると、θ=0で左右の消失点は(±86.9, 0)となり、PC-8001の160×100ドット画面に収まらない。つまり－π/4≦θ≦π/4において、少なくとも左右どちらかの消失点が画面外にあるので、垂直線端(36tanθ, ±36)を始点として、傾きが(sin(θ/2±3π/8), ∓cos(θ/2±3π/8))の斜線を引く、という手法の方が安全だと考えられる。その場合、消失点の外側の斜線は、傾きが(sin(-θ/2±π/8), ±cos(-θ/2±π/8))となるはずである。

Cレジスタで角度(2π/256刻み)を渡すと、tan(C)をDEレジスタ(Dレジスタに符号付整数、Eレジスタに256を分母とする分数)に返すZ80プログラムは、表をE800H～E881Hに準備すれば、以下のように書ける。

```
E800 00 00 06 00 0D 00 13 00 19 00 20 00 26 00 2C 00
E810 33 00 39 00 40 00 47 00 4E 00 55 00 5C 00 63 00
E820 6A 00 71 00 79 00 81 00 89 00 91 00 99 00 A2 00
E830 AB 00 B4 00 BE 00 C8 00 D2 00 DD 00 E8 00 F4 00
E840 00 01 0D 01 1A 01 29 01 38 01 48 01 59 01 6B 01
E850 7F 01 94 01 AB 01 C4 01 DF 01 FD 01 1D 02 42 02
E860 6A 02 98 02 CB 02 07 03 4C 03 9D 03 FE 03 74 04
E870 07 05 C3 05 BE 06 1C 08 27 0A 8F 0D 5B 14 BC 28
E880 FF 7F

E890 26E8     LD H,E8H
E892 CB71    BIT 6,C
E894 280D     JR Z,E8A3H
E896 AF      XOR A,A
E897 91      SUB A,C
E898 87      ADD A,A
E899 6F       LD L,A
E89A 7E       LD A,(HL)
E89B 2F      CPL
E89C 5F       LD E,A
E89D 2C      INC L
E89E 7E       LD A,(HL)
E89F 2F      CPL
E8A0 57       LD D,A
E8A1 13      INC DE
E8A2 C9      RET
E8A3 69       LD L,C
E8A4 CB25    SLA L
E8A6 5E       LD E,(HL)
E8A7 2C      INC L
E8A8 56       LD D,(HL)
E8A9 C9      RET
```

Cレジスタで角度を渡すと、斜線の傾きのX成分・Y成分をそれぞれHLレジスタ・DEレジスタに返すZ80プログラムは、上の表を流用すれば、以下のように書ける。

```
E7C0 79       LD A,C
E7C1 E63F    AND A,3FH
E7C3 FE21     CP A,21H
E7C5 3803     JR C,E7CAH
E7C7 2F      CPL
E7C8 C641    ADD A,41H
E7CA 87      ADD A,A
E7CB 6F       LD L,A
E7CC 26E8     LD H,E8H
E7CE 5E       LD E,(HL)
E7CF 2C      INC L
E7D0 56       LD D,(HL)
E7D1 210001   LD HL,0100H
E7D4 79       LD A,C
E7D5 D620    SUB A,20H
E7D7 E640    AND A,40H
E7D9 2001     JR NZ,E7DCH
E7DB EB       EX DE,HL
E7DC CB79    BIT 7,C
E7DE 2807     JR Z,E7E7H
E7E0 7B       LD A,E
E7E1 2F      CPL
E7E2 5F       LD E,A
E7E3 7A       LD A,D
E7E4 2F      CPL
E7E5 57       LD D,A
E7E6 13      INC DE
E7E7 79       LD A,C
E7E8 C640    ADD A,40H
E7EA 87      ADD A,A
E7EB D0      RET NC
E7EC 7D       LD A,L
E7ED 2F      CPL
E7EE 6F       LD L,A
E7EF 7C       LD A,H
E7F0 2F      CPL
E7F1 67       LD H,A
E7F2 23      INC HL
E7F3 C9      RET
```

HLレジスタで始点のXY座標(いずれも符号付き整数)、Cレジスタで角度を渡すと、直線の描画をおこなうZ80プログラムは、上のプログラムを呼び出しつつ、以下のように書ける。なお、描画の終了条件は、Hレジスタ(X座標)がDレジスタと一致した時、Lレジスタ(Y座標)がEレジスタと一致した時、あるいは画面の端まで達した時である。

```
E740 7C       LD A,H
E741 DD67     LD J,A
E743 DD2E80   LD X,80H
E746 7D       LD A,L
E747 FD67     LD K,A
E749 FD2E80   LD Y,80H
E74C 79       LD A,C
E74D D9      EXX
E74E 4F       LD C,A
E74F CDC0E7 CALL E7C0H
E752 224CEF   LD (EF4CH),HL
E755 ED534EEF LD (EF4EH),DE
E759 D9      EXX
E75A 3EB0     LD A,B0H
E75C 84      ADD A,H
E75D D660    SUB A,60H
E75F D8      RET C
E760 D9      EXX
E761 1F      RRA
E762 5F       LD E,A
E763 9F      SBC A,A
E764 E60F    AND A,0FH
E766 3C      INC A
E767 47       LD B,A
E768 D9      EXX
E769 3ECE     LD A,CEH
E76B 95      SUB A,L
E76C D69C    SUB A,9CH
E76E D8      RET C
E76F D9      EXX
E770 CB47    BIT 0,A
E772 2802     JR Z,E776H
E774 CB20    SLA B
E776 CB4F    BIT 1,A
E778 2804     JR Z,E77EH
E77A CB20    SLA B
E77C CB20    SLA B
E77E E67C    AND A,7CH
E780 57       LD D,A
E781 CB22    SLA D
E783 0F     RRCA
E784 0F     RRCA
E785 1F      RRA
E786 67       LD H,A
E787 9F      SBC A,A
E788 E680    AND A,80H
E78A 92      SUB A,D
E78B 6F       LD L,A
E78C 3001     JR NC,E78FH
E78E 25      DEC H
E78F 16F3     LD D,F3H
E791 19      ADD HL,DE
E792 7E       LD A,(HL)
E793 B0       OR A,B
E794 77       LD (HL),A
E795 ED5B4CEF LD DE,(EF4CH)
E799 DD19    ADD JX,DE
E79B ED5B4EEF LD DE,(EF4EH)
E79F FD19    ADD KY,DE
E7A1 D9      EXX
E7A2 7C       LD A,H
E7A3 BA       CP A,D
E7A4 C8      RET Z
E7A5 7D       LD A,L
E7A6 BB       CP A,E
E7A7 C8      RET Z
E7A8 DD7C     LD A,J
E7AA 67       LD H,A
E7AB FD7C     LD A,K
E7AD 6F       LD L,A
E7AE 18AA     JR E75AH
```

しかしながら、この直線描画プログラムは、遅い。1ドット描くのに400ステート以上かかってしまうので、長さ50の直線を1本引くだけで20000ステートもかかってしまう。とりあえず、以下のPC-8001エミュレータで実装してみたので、テンキーの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 18, 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",

 "E600 31 FF FF 21 00 B8 22 5A EA 01 19 50 CD 3A 09 3E",
 "E610 20 32 D0 E8 CD E0 E6 CD 40 E6 DB 00 F6 AF FE BF",
 "E620 28 0F FE EF 20 F4 3A D0 E8 FE 20 28 ED C6 02 18",
 "E630 E0 3A D0 E8 FE E0 28 E2 D6 02 18 D5",

 "E640 3A D0 E8 4F CB 2F 32 D1 E8 CD 90 E8 62 6B 29 29",
 "E650 29 19 29 29 2E 2C 22 D2 E8 11 D4 80 0E C0 CD 40",
 "E660 E7 3A D1 E8 D6 10 4F 2A D2 E8 11 00 80 CD 40 E7",
 "E670 3A D1 E8 2F C6 11 4F 2A D2 E8 2E D4 11 00 80 CD",
 "E680 40 E7 38 1B E5 3A D1 E8 C6 30 4F 11 80 80 CD 40",
 "E690 E7 E1 3A D1 E8 2F D6 2F 4F 11 80 80 CD 40 E7 3A",
 "E6A0 D1 E8 D6 70 4F 2A D2 E8 11 00 80 CD 40 E7 3A D1",
 "E6B0 E8 2F C6 71 4F 2A D2 E8 2E D4 11 00 80 CD 40 E7",
 "E6C0 D8 E5 3A D1 E8 C6 50 4F 11 80 80 CD 40 E7 E1 3A",
 "E6D0 D1 E8 2F D6 4F 4F 11 80 80 C3 40 E7",

 "E6E0 21 00 00 39 D9 31 50 F3 11 00 00 06 19 D5 D5 D5",
 "E6F0 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5",
 "E700 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5 D5",
 "E710 D5 D5 D5 D5 D5 21 C8 00 39 F9 10 D1 D9 F9 C9",

 "E740 7C DD 67 DD 2E 80 7D FD 67 FD 2E 80 79 D9 4F CD",
 "E750 C0 E7 22 4C EF ED 53 4E EF D9 3E B0 84 D6 60 D8",
 "E760 D9 1F 5F 9F E6 0F 3C 47 D9 3E CE 95 D6 9C D8 D9",
 "E770 CB 47 28 02 CB 20 CB 4F 28 04 CB 20 CB 20 E6 7C",
 "E780 57 CB 22 0F 0F 1F 67 9F E6 80 92 6F 30 01 25 16",
 "E790 F3 19 7E B0 77 ED 5B 4C EF DD 19 ED 5B 4E EF FD",
 "E7A0 19 D9 7C BA C8 7D BB C8 DD 7C 67 FD 7C 6F 18 AA",

 "E7C0 79 E6 3F FE 21 38 03 2F C6 41 87 6F 26 E8 5E 2C",
 "E7D0 56 21 00 01 79 D6 20 E6 40 20 01 EB CB 79 28 07",
 "E7E0 7B 2F 5F 7A 2F 57 13 79 C6 40 87 D0 7D 2F 6F 7C",
 "E7F0 2F 67 23 C9",

 "E800 00 00 06 00 0D 00 13 00 19 00 20 00 26 00 2C 00",
 "E810 33 00 39 00 40 00 47 00 4E 00 55 00 5C 00 63 00",
 "E820 6A 00 71 00 79 00 81 00 89 00 91 00 99 00 A2 00",
 "E830 AB 00 B4 00 BE 00 C8 00 D2 00 DD 00 E8 00 F4 00",
 "E840 00 01 0D 01 1A 01 29 01 38 01 48 01 59 01 6B 01",
 "E850 7F 01 94 01 AB 01 C4 01 DF 01 FD 01 1D 02 42 02",
 "E860 6A 02 98 02 CB 02 07 03 4C 03 9D 03 FE 03 74 04",
 "E870 07 05 C3 05 BE 06 1C 08 27 0A 8F 0D 5B 14 BC 28",
 "E880 FF 7F",

 "E890 26 E8 CB 71 28 0D AF 91 87 6F 7E 2F 5F 2C 7E 2F",
 "E8A0 57 13 C9 69 CB 25 5E 2C 56 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>
```

しかも、迷路の曲がり角や行き止まりを表現しようとすると、h=6<sup>2</sup>のみならず、h=5<sup>2</sup>、h=4<sup>2</sup>、h=3<sup>2</sup>、h=2<sup>2</sup>も表示しなければならない。もっと高速な直線描画が必要となるが、40年前の私には思いつかなかった。さて、今なら、どうするだろう。