对于光笔屏幕的亮度识别，要结合颜色码和mc6847 css。

光笔是一个光电感应开关，感应CRT电子束扫描位置的亮度。
模拟器要计算电子束当前精确的位置。
大概是这么一个公式，(yyy*3+95)*455/2 + 100 + xxx;


程序 LIGHT PEN.4.E742.bas

100 POKE30862,18:POKE30863,123:REM START OF LIGHTPEN SUBROUTINE
620 A=USR(X):A$=INKEY$:A$=INKEY$

调用Z80子程序 A=USR(0) 入口 7B12

流程梳理：
1、计算垂直回扫占用的时间
2、光笔未触发  bit6==1 7B10h=FFh 7B11h=FFh
3、光笔触发 bit6==0 :
    a. 判断光笔所在行（y），结果存在 7B11h
        等待垂直回扫开始，设置图形模式，CSS设置为0，（7B8D）等待垂直回扫结束，读取192+1组屏幕，每行平均227.5个周期。读取间隔时间22个CPU机器周期
        等待垂直回扫开始，设置图形模式，CSS设置为1，（7B8D）等待垂直回扫结束，读取192+1组屏幕，每行平均227.5个周期。读取间隔时间22个CPU机器周期
    b. 判断光笔所在列（x），结果存在 7B10h
       等待垂直回扫开始，设置图形模式，CSS设置为0，（7C0B）等待垂直回扫结束，保存当前行的内容到缓冲区7D5E，连续3行(0x60)
       等待垂直回扫开始，0xAA 写入光笔所在的3行 0x60，0x55 写入光笔所在的3行前半段。等待垂直回扫结束。向缓冲区写数据，能够在垂直回扫结束前完成，即/FS拉高前。
       （7B8D）等待垂直回扫开始，读取屏幕。

《LASER-310深入》徐敏1986

第二节光笔
本节介绍光笔与电脑的连接方法，以及光笔程序输入电脑主机后如何调节电视屏幕的亮度使光笔正常发臣其作用并讨论光笔程序的编写，录制等问题。
一、光笔的拆装、调试与注意事项
1.参见第一册图1一4。先关闭主机电源，再将光笔介面LI-20插进外围设备接口(PERIPH ERAL)(如果这个接口已插有打印机介面，应先拔除此介面：但应注意检查主机电源是否已关妥)，光笔介面的接口应完全插入主机接口后，再开启主机，此时屏幕应显示图1一6（第一册）所示的正常情况，若显示不正常，应即关闭主机电源，拔出光笔介面10秒钟后，再重复上述步骤。
2.调试光笔之前应先编写好光笔程序，使主机运行光笔程序后再进行。或者用录音机把光笔程序示范带的程序输入主机，先键入CRUN命令，再按下录音机上的放音键(PLAY),最后按一次输入键(RETURN键)
3,主机进入光笔程序后，即可调试光笔，方法如下：
(1)手持光笔如执笔状态，以光笔末端黑色触点接触电视屏幕，（光笔必须垂直于电视屏幕)将黑色触点轻压屏幕，此时屏幕应有水平兰线闪烁反应，电脑发声，光笔即可离开屏幕，此时，屏幕上发现光笔点过的标记（如点、图形等）这说明光笔已能正常工作，但尚须进行一些调节工作如下述2条。
(2)如果屏幕只有闪烁反应，没有水平蓝线出现，电脑不发声，此时应把屏幕亮度加大。
如果屏幕只有水平蓝线闪烁，电脑不发声，此时应把屏幕亮减小。
(3)如果在光笔垂直于屏幕的情况下，光笔感知的信号偏左，此时应把屏幕亮度稍微减小一点。
如果光笔感知的信号偏右，此时把屏幕亮度稍微加大一点。
4,注意事项：拆装光笔介面时必须先关闭主机电话；主机外用设备接口以及光笔介面都不允许接触任何液体。否则损坏主机和介面。


图象显示模式中屏幕显示的象点色彩与机器码的对应关系如下。
其中MODE(I)表示屏幕图象显示模式。MACHINE CODE是机器码的意思，MCODE
表示下面所对应的数码为机器码。COLOR一CODE表示以下所对应的数码为颜色码，颜
色码从1~4。在绿色背景下，1表示绿色，2表示黄色，3表示兰色、4表示红色，在淡黄色
背景下，1表示淡黄色，2表示淡绿色，3表示紫色、4表示橙色，每个机器码自左至右具有
4个象元（即4点颜色）


LASER310 使用的芯片是 Z80A MC6847P
晶振 17.5MHz
5分频3.54MHz供给 CPU 时钟
4分频4.375MHz供给 MC4847P 时钟

MC6847
/FS 垂直同步  每一帧结束/FS变低。PAL每秒50帧。/FS 输出到 Z80的 /INT 和 读取6800的bit7
/HS 水平同步
CSS 写6800的bit4


7BAE 00 0 ( 13,10) ( 323 2) 15779 0000 0 0 : 1
7BAE 00 0 ( 13,10) ( 323 2) 59459 00C0 0 0 : 1


第1行和第127行时间差
59459 - 15779 = 43680
43680/192= 227.5

15779/227.5= 69.36



70980/341 = 208


7B12: [046A 0028 0890 7B12] di
7B13: [046A 0028 0890 7B12] call (7D36h) # 计算  068A - 垂直回扫循环 结果放在 HL
7B16: [0002 0028 0029 0661] in a,(40h)      # 读取光笔是否触发
7B18: [7F02 0028 0029 0661] bit 6,a
7B1A: [7F38 0028 0029 0661] jr nz,(pc+40h)

#触发  bit6==0
7B1C: [BF7C 7D36 0890 7B12] call (7BFBh)  # 等待垂直回扫开始
7B1F: [7F28 7D36 0890 7B12] ld a,08h
7B21: [0828 7D36 0890 7B12] ld (6800h),a  # css=0
7B24: [0828 7D36 0890 7B12] jr (pc+5h)
7B29: [0828 7D36 0890 7B12] call (7B8Dh)
7B2C: [C142 0040 0890 00C1] jr nc,(pc+38h)
7B64: [C142 0040 0890 00C1] in a,(40h)
7B66: [BF42 0040 0890 00C1] bit 6,a
7B68: [BF7C 0040 0890 00C1] jr nz,(pc-11h)
7B6A: [BF7C 0040 0890 00C1] call (7BFBh)   # 等待垂直回扫开始
7B6D: [7F28 0040 0890 00C1] ld a,18h
7B6F: [1828 0040 0890 00C1] ld (6800h),a # css=1
7B72: [1828 0040 0890 00C1] call (7B8Dh)
7B75: [0045 0003 0890 FFFD] jr nc,(pc-1Eh)
7B77: [0045 0003 0890 FFFD] call (7BFBh)   # 等待垂直回扫开始
7B7A: [7F28 0003 0890 FFFD] ld a,08h
7B7C: [0828 0003 0890 FFFD] ld (6800h),a # css=0
7B7F: [0828 0003 0890 FFFD] jr (pc-51h)
7B2E: [0828 0003 0890 FFFD] call (7C0Bh)
7B31: [0044 0001 0020 701F] in a,(40h)
7B33: [BF44 0001 0020 701F] bit 6,a
7B35: [BF7C 0001 0020 701F] jr nz,(pc+1Ah)
7B37: [BF7C 0001 0020 701F] call (7C49h)
7B3A: [7F28 0040 0020 00C1] jr z,(pc+7h)
7B3C: [7F28 0040 0020 00C1] ex af,af'
7B3D: [C142 0040 0020 00C1] jr c,(pc+12h)
7B3F: [C142 0040 0020 00C1] jr (pc+5h)
7B44: [C142 0040 0020 00C1] call (7C68h)
7B47: [7F28 0000 7060 7DBE] call (7B83h)
7B4A: [2828 0000 7060 7DBE] call (7D08h)
7B4D: [2838 7C00 7060 701F] jr (pc+34h)

7BE4: [3F2C 0040 0890 0000] ld bc,0003h
7BE7: [3F2C 0003 0890 0000] xor a


#未触发  bit6==1 7B10h=FFh 7B10h=FFh
7B5A: [7F38 0028 0029 0661] ld a,FFh	
7B5C: [FF38 0028 0029 0661] ld (7B10h),a
7B5F: [FF38 0028 0029 0661] ld (7B11h),a
7B62: [FF38 0028 0029 0661] jr (pc+1Fh)
7B81: [FF38 0028 0029 0661] ei
7B82: [FF38 0028 0029 0661] ret


计算 068A - 垂直回扫循环 结果放在 HL
7D36: [046A 0028 0890 7B12] call (7BFBh) # 等待垂直回扫开始
7D39: [7F28 0028 0890 7B12] ld de,0000h
7D3C: [7F28 0028 0000 7B12] ld hl,068Ah
7D3F: [7F28 0028 0000 068A] call (7C03h) # 等待垂直回扫结束
7D42: [FFAC 0028 0000 068A] inc de
7D43: [FFAC 0028 0001 068A] ld a,(6800h)
7D46: [FFAC 0028 0001 068A] or a
7D47: [FFAC 0028 0001 068A] jp m,(7D42h)
7D4A: [7F28 0028 0029 068A] ld a,01h
7D4C: [0128 0028 0029 068A] ld (7B13h),a
7D4F: [0128 0028 0029 068A] xor a
7D50: [0044 0028 0029 068A] sbc hl,de
7D52: [0002 0028 0029 0661] jp c,(7D59h)
7D55: [0002 0028 0029 0661] ld (7DC3h),a
7D58: [0002 0028 0029 0661] ret
7D59: [00BB 0028 07E4 FEA6] cpl
7D5A: [FFBB 0028 07E4 FEA6] ld (7DC3h),a
7D5D: [FFBB 0028 07E4 FEA6] ret


7BFB 等待垂直回扫开始 读取 6800 bit7 ==0
7C03 等待垂直回扫结束 读取 6800 bit7 ==1

7BFB: [046A 0028 0890 7B12] ld a,(6800h)
7BFE: [7F6A 0028 0890 7B12] or a
7BFF: [7F28 0028 0890 7B12] jp m,(7BFBh)
7C02: [7F28 0028 0890 7B12] ret

7C03: [7F28 0028 0000 068A] ld a,(6800h)
7C06: [7F28 0028 0000 068A] or a
7C07: [7F28 0028 0000 068A] jp p,(7C03h)
7C0A: [FFAC 0028 0000 068A] ret


7B8D: [0828 7D36 0890 7B12] ld hl,0000h
7B90: [0828 7D36 0890 0000] call (7C03h) # 等待垂直回扫结束
7B93: [FFAC 7D36 0890 0000] ld a,(7DC3h)
7B96: [00AC 7D36 0890 0000] or a
7B97: [0044 7D36 0890 0000] jr z,(pc+Ah)
7BA1: [0044 7D36 0890 0000] ld bc,014Ch
7BA4: [0044 014C 0890 0000] dec bc
7BA5: [0044 014B 0890 0000] ld a,b
7BA6: [0144 014B 0890 0000] or c
7BA7: [4B0C 014B 0890 0000] jr nz,(pc-3h)
7BA9: [0044 0000 0890 0000] ld c,40h
7BAB: [0044 0040 0890 0000] nop
7BAC: [0044 0040 0890 0000] nop
7BAD: [0044 0040 0890 0000] nop
7BAE: [0044 0040 0890 0000] in a,(c)
7BB0: [BFA8 0040 0890 0000] jp p,(7BE4h)
7BB3: [BFA8 0040 0890 0000] in a,(c)
7BB5: [BFA8 0040 0890 0000] jp p,(7BE4h)
7BB8: [BFA8 0040 0890 0000] in a,(c)
7BBA: [BFA8 0040 0890 0000] jp p,(7BE4h)
7BBD: [BFA8 0040 0890 0000] in a,(c)
7BBF: [BFA8 0040 0890 0000] jp p,(7BE4h)
7BC2: [BFA8 0040 0890 0000] in a,(c)
7BC4: [BFA8 0040 0890 0000] jp p,(7BE4h)
7BC7: [BFA8 0040 0890 0000] in a,(c)
7BC9: [BFA8 0040 0890 0000] jp p,(7BE4h)
7BCC: [BFA8 0040 0890 0000] in a,(c)
7BCE: [BFA8 0040 0890 0000] jp p,(7BE4h)
7BD1: [BFA8 0040 0890 0000] inc l
7BD2: [BF00 0040 0890 0001] ld a,l
7BD3: [0100 0040 0890 0001] cp C1h       # 0xC1 = 193
7BD5: [0103 0040 0890 0001] jp nc,(7BFAh)
7BD8: [0103 0040 0890 0001] bit 0,l
7BDA: [0111 0040 0890 0001] jr z,(pc+3h)
7BDC: [0111 0040 0890 0001] nop
7BDD: [0111 0040 0890 0001] jr (pc+2h)
7BDF: [0111 0040 0890 0001] ld c,40h
7BE1: [0111 0040 0890 0001] jp (7BAEh)

7BE4: [3F2C 0040 0890 0000] ld bc,0003h
7BE7: [3F2C 0003 0890 0000] xor a
7BE8: [0044 0003 0890 0000] sbc hl,bc
7BEA: [00BB 0003 0890 FFFD] jr c,(pc+5h)
7BEF: [00BB 0003 0890 FFFD] cp 3Eh
7BF1: [00BB 0003 0890 FFFD] jr c,(pc+4h)
7BF5: [00BB 0003 0890 FFFD] ld (7B11h),a
7BF8: [00BB 0003 0890 FFFD] xor a
7BF9: [0044 0003 0890 FFFD] ccf

7BFA: [C142 0040 0890 00C1] ret


#判断光笔位置所在的列(x)
计算当前行内存位置7000h+(7B11h)*32
等待垂直回扫开始
保存当前行的内容到缓冲区7D5E，连续3行(0x60)

7C0B: [0828 0003 0890 FFFD] ld a,(7B11h)
7C0E: [1928 0003 0890 FFFD] dec a
7C0F: [180A 0003 0890 FFFD] jp p,(7C13h)
7C13: [180A 0003 0890 FFFD] ld l,a
7C14: [180A 0003 0890 FF18] ld h,00h
7C16: [180A 0003 0890 0018] add hl,hl
7C17: [1800 0003 0890 0030] add hl,hl
7C18: [1800 0003 0890 0060] add hl,hl
7C19: [1800 0003 0890 00C0] add hl,hl
7C1A: [1800 0003 0890 0180] add hl,hl
7C1B: [1800 0003 0890 0300] ld de,7000h
7C1E: [1800 0003 7000 0300] add hl,de
7C1F: [1820 0003 7000 7300] ld (7DC0h),hl
7C22: [1820 0003 7000 7300] ld (7DBEh),hl
7C25: [1820 0003 7000 7300] call (7BFBh)  # 等待垂直回扫开始
7C28: [7F28 0003 7000 7300] ld de,7D5Eh
7C2B: [7F28 0003 7D5E 7300] call (7CA8h) # 保存当前行的内容到缓冲区7D5E，连续3行(0x60)
7C2E: [7F28 0000 7DBE 7360] ld b,10h
7C30: [7F28 1000 7DBE 7360] call (7CDCh)
7C33: [0045 1000 0020 FFFD] ld b,08h
7C35: [0045 0800 0020 FFFD] call (7CD9h)
7C38: [C160 0008 0020 7308] ld b,04h
7C3A: [C160 0408 0020 7308] call (7CD9h)
7C3D: [0045 0408 0020 FFFD] ld b,02h
7C3F: [0045 0208 0020 FFFD] call (7CD9h)
7C42: [0045 0208 0020 FFFD] ld b,01h
7C44: [0045 0108 0020 FFFD] call (7CD9h)
7C47: [0045 0108 0020 FFFD] xor a
7C48: [0044 0108 0020 FFFD] ret



7CA8: [7F28 0003 7D5E 7300] ld bc,0060h
7CAB: [7F28 0060 7D5E 7300] ldir	# (DE) <-- (HL)  BC计数器
7CAD: [7F28 0000 7DBE 7360] ret


7CDC: [7F28 1000 7DBE 7360] push bc
7CDD: [7F28 1000 7DBE 7360] call (7CC6h) # 0xAA = 1010 1010 写入行光笔所在行缓冲区，长度 0x60
7CE0: [7F28 0000 7DBE 7360] pop bc
7CE1: [7F28 1000 7DBE 7360] ld hl,(7DBEh)
7CE4: [7F28 1000 7DBE 7300] push hl
7CE5: [7F28 1000 7DBE 7300] call (7CD1h) # 0x55 = 0101 0101 写入行光笔所在行缓冲区，长度 0x10
7CE8: [7F28 1000 7DBE 7310] pop hl
7CE9: [7F28 1000 7DBE 7300] ld de,0020h
7CEC: [7F28 1000 0020 7300] add hl,de
7CED: [7F20 1000 0020 7320] push hl
7CEE: [7F20 1000 0020 7320] call (7CD1h) # 0x55 = 0101 0101 写入行光笔所在行缓冲区+0x20，长度 0x10
7CF1: [7F20 1000 0020 7330] pop hl
7CF2: [7F20 1000 0020 7320] add hl,de
7CF3: [7F20 1000 0020 7340] call (7CD1h) # 0x55 = 0101 0101 写入行光笔所在行缓冲区+0x40，长度 0x10
7CF6: [7F20 1000 0020 7350] push bc
7CF7: [7F20 1000 0020 7350] call (7B8Dh)
7CFA: [0045 0003 0020 FFFD] pop bc
7CFB: [0045 1000 0020 FFFD] jr c,(pc+Ch)
7D07: [0045 1000 0020 FFFD] ret

# 0xAA = 1010 1010 写入行光笔所在行缓冲区，长度 0x60
7CC6: [7F28 1000 7DBE 7360] ld hl,(7DC0h)
7CC9: [7F28 1000 7DBE 7300] ld b,60h
7CCB: [7F28 6000 7DBE 7300] ld (hl),AAh
7CCD: [7F28 6000 7DBE 7300] inc hl
7CCE: [7F28 6000 7DBE 7301] djnz (pc-3h)
7CD0: [7F28 0000 7DBE 7360] ret

# 0x55 = 0101 0101 写入行光笔所在行缓冲区，长度 0x10
7CD1: [7F28 1000 7DBE 7300] push bc
7CD2: [7F28 1000 7DBE 7300] ld (hl),55h
7CD4: [7F28 1000 7DBE 7300] inc hl
7CD5: [7F28 1000 7DBE 7301] djnz (pc-3h)
7CD7: [7F28 0000 7DBE 7310] pop bc
7CD8: [7F28 1000 7DBE 7310] ret

===========================================================================


