Sunday, 20 November 2011

Differences between ASIC, ASSP and ASIP


ASIC (Application Specified Integrated Circuit) is a customized integrated circuit. It is usually used by a person or company for a very limited usage. So when it is developed, only the person or company who orders it can use it. It is not useful for other usages, for example, an IC designed for a specific line of cellular phones of a company, whereby no other products can use it except the cell phones belonging to that product line.
- ASIC is just built for one and only one customer.
- ASIC is used only in one product line
- Only volume production of ASICs for one product can make sense which means low unit cost for high volume products, otherwise the cost is not efficient.
- Can exploit parallelism to achieve high performance
- Low power consumption

ASSP (Application Specified Standard Processor) is an integrated circuit that implements a specific function that appeals to a wide market, which means its function is specified for example a motor drive chip. But it is used widely, not limited to only one customer as ASIC does. So ASSPs are available as off-the-shelf components which means you can go to electronic shops and just buy it directly from the "shelf". It means ASSPs have been developed well and you can just buy it without designing it from scratch.
- It addresses the product space between ASIC and generic processor based products
- Extremely useful for low to medium volume applications because it help reduce cost and design overheads.

ASIP (application specific instruction processor) is usually used in SoC (System on a Chip). ASIP is an architecture including two parts which are a minimum ISA (Instruction Set Archietecture) and a configurable logic which you can use to design your own instruction set. So it provides relatively high flexibility compared to ASIC and better performance compared to FPGA (Field Programmable Gate Array). Also, it is cheaper than FPGA, but slightly more expensive than ASIC.
- ASIP can help build your own instruction set to meet your specific requirement.
- It provide a minimum ISA, which can make shorter TTM (Time to Market).

How to choose ASIC or ASSP?
- Whether TTM (Time-To-Marker) allows to design an ASIC
- Whether you have special requirement for your design which is not common in ASSPs, for example, you can exploit parallelism to achieve high performance
- Whether your products can have a big volume in market
- Power consumption requirement
- Whether software development tools are available
- How is the skill of the developers, whether they are capable for designing an ASIC
- Whether you can burden the technology risk for designing AISC
- How much is your plan for NRE (Non-Recurring Expense) cost to the project: ASIC needs relatively large NRE cost, and ASSP needs no NRE cost.

Saturday, 19 November 2011

Common commands in Linux

VI operations:
dd is used to delete one line
yy is used to copy one line
p is used to paste one line

GCC some useful operations:
-g is used to compile the program so that the debug program GDB can debug the execution.
-l is used to link the library, for example, -lm means to link "math" library.
-o used to name the execution file.

GDB some useful commands:
list : used to list the program in the source code.
break (line number) : used to set the break point.
run : run the program in GDB.
next(or n) : used to execute program step by step.
continue : execute the program until the end.
quit(or q) : exit GDB.
(press ENTER) : reexecute the last command.

Thursday, 17 November 2011

关于2440init.s之一(转载)


2440的初始化程序,也可以说是bootloader中的精华部分,承载着程序执行的第一条指令
的重要任务,所有得程序要想执行,那么首先必须过Init.s这一关啊。

那么Init究竟做了些什么呢,咳,这的确是一个头大的问题,起初真的是一头雾水啊

首先,定义了入口地址,一般处理器上电以后,都会从存储器的0地址开始执行,好了,现
在就有第一个问题出现了,这个存储器的0地址是个什么概念;

要解决这个问题,首先必须弄清楚你的系统有哪些存储器。一般来说,不外乎rom和ram,
还有flash,flash是很重要的,因为我们的程序就放在那儿。可是我们知道,flash的物理
地址一般不会是从0开始啊,呵呵,的确是这么回事,那这个0到底是什么呢,很简单,偏
移量啊,就是flash的base+xx,这个xx就是0,^_^,就这么简单

接下来,出现第二个问题,程序从0地址执行,那么下一个要执行的代码是什么呢,他是通
过什么跳转到第二个代码呢?

这个问题的回答要针对具体的处理器了,一般代码的存放都是连续存放的,就是第一个地
址,第二个地址,代码占多大空间,那么第二个地址就是第一个地址+第一条指令占居的
空间
比如说我们现在使用的2440,它是32位宽的,就是说每条指令译码后,为一个32位的二进
制数,它的不同的位分别代表了这个指令要做什么。那么这样一条代码在存储器中就要占
据32位。那我们知道现在一般存储器都是按字节存放的,如此算来,一条指令要占据4个字
节,事实上也确实如此。

由此我们得知,假如说我们的第一条指令存放在0x00000000处,那么第二条指令就应该存
放在0x00000004处了。^_^一点都不假。并且,这里还要说明一点,由于它每条指令都是4
字节,也即一个字的宽度,同时arm在寻址的时候,是字对齐的,所以,arm的地址位的低
两位(如A1,A0)在到存储器中寻找的时候,是没有效的,因为存储器按字节存取,而一
条指令占4个字节,所以呢,处理器每次都是4个字节的拿或放,因而2^2=4,所以A1和A0的
变化,只会出现0x00000001,0x00000002,0x00000003这样的数,而这样的数在寻址的时
候,都是指向了0x00000000起始的四个字节,所以啊,即使出现这样的数,都会自动对齐
到0x00000000了,因而才有上面一说。如此,也应该能够明白,在我们读写ram的时候,地
址的结尾只能是0,4,8,c了啊,^_^

那么究竟这个第二个地址的读取是通过一种什么机制呢,那就是PC,也就是Program Coun
t,程序计数器,就是它,在复位或者上电时刻,指向了0地址,即PC=0x00000000,然后
,在指向第二条指令的时候,它做了这样一个运算,PC=PC+4,很简单吧;但是!,因为
2440是三级流水线结构,PC的值就一定小心啊,下面来讲讲为什么
三级流水线,故名思义,就是一个时刻做三件事情,对于2440来说,那就是取指,译码,
执行
取指 译码 执行。。。
   取指 译码 执行。。。
             取指 译码 执行。。。
那么问一个问题,PC究竟是指向取指呢,译码呢,还是执行,^_^,对了,取指令!!由此
便带来一个问题,当前指令执行的时候,PC的值已经不是当前指令所在的地址了,而是
当前地址+8
   0x00000000
   0x00000004        ---假设为当前执行的指令地址
   0x00000008
PC-> 0x0000000c        PC指向的是这儿

上电之时,PC便首先指向了flash的0地址,这个地方的指令将被执行。那么我们的程序如
何才能被放在这个0地址呢,当然不能随便写,汇编中,这些都是有固定格式的,如下 :

   AREA Init,CODE,READONLY
   ENTRY
这个ENTRY便是表明,下面的程序为整个工程代码的入口点,至于如何放到flash的0地址,
那个就是flash烧写的工作了,不归我管,^_^

有了这样的入口,Init都要做些什么,先大概说说,包括几个部分吧,这些,也就是对
2440的初始化了
%定义入口地址
%建立异常向量表
%初始化存储器系统
%初始化堆栈
%初始化必要IO
%初始化中断系统要求的RAM向量
%开中断
%如有必要,改变处理器模式
%如有必要,改变处理器状态
%初始化C语言要求的存储器空间
%跳转到C去执行

建立异常向量表
我们知道,中断机制是PC机中一个非常重要的地方,中断节省CPU资源,加快了突发事件
的处理速度。在arm中,也差不多采取了类似的机制。PC中我们叫中断向量表,中断向量
表存放了一系列的跳转指令,当有中断产生的时候,系统便会自动到中断向量表查找相应
的中断向量号,然后根据中断号跳转到相应的地址去执行。
对于异常向量表,其实也是类似的功能,只不过对于一个arm来说,它上升到了工作模式
的高度,也就是说我们通常用的是用户模式,当有情况发生的时候,它要切换到相应的模
式下进行工作,比如中断,就是其中的一种!其他的还有管理模式,未定义指令模式,快
速中断模式,系统模式等等

异常向量表通常如下所示

b ResetHandler
b HandlerUndef
b HandlerSWI
b HandlerPabort
b HandlerDabort
b .
b IsrIRQ
b HandlerFIQ

那么,当有情况发生的时候,程序便会跳转到这个异常向量表的相应位置,执行相应的
跳转,如IRQ发生的时候,它就跳转到b IsrIRQ,进而执行这个跳转,去执行IsrIRQ标号
的代码

好了,知道了这个机制,便要关心这个表放在什么地方,才能让异常发生的时候,跳转
到这个表去执行相应的指令呢,呵呵,这肯定是放在一个特殊的地方,那就是0地址,
不过要注意了,这里0地址是哪里的0地址呢,呵呵
我们知道,异常的发生肯定是操作系统正在进行工作的时候,操作系统的工作是在
哪里进行??^_^,知道了,就是SDRAM,好了,操作系统在工作的时候,是不会在
返回到Nand Flash中去寻找咚咚的,明白了,这个异常向量表就是放在SDRAM的0地
址处,而且,一定要放在这个地方,这个地方也不能放别的东西,它就是放异常向量表

呵呵,插一段,我们要说说对于2440,它的启动流程是什么样子的,PC是怎么变化
的,简单说说吧

在Nand Flash中,bootloader,内核启动参数,内核,根文件系统是顺序存放的,并且,
bootloader是存放在0地址的,上电之后,PC就是指向这个0地址,并且开始执行,
bootloader要做很多事情,并且这些指令都是对CPU进行操作的,所以,很重要。而Init
就是bootloader中的一个部分,它的任务可以说是bootloader的子集;PC顺序执行,
首先关中断啊,初始化时钟啊等等,然后,将bootloader第二阶段的内容复制到SDRAM中
,包括Main主函数、内核和文件系统等复制过去,然后跳转到SDRAM中去执行,在执行
到跳转到内核去执行的时候,它要做一件事情,就是内存重映射,将PC重新定向到0地址
,并执行放在那儿的跳转指令……

转自http://space.baidu.com/%D2%FE%D0%CE%C8%CBlaigo/blog/item/7c2caadc02b87faacd1166b2.html

ARM指令中如何判断一个立即数是有效立即数(转载)


arm指令 立即数(一)
2011-04-13 16:55
在ARM处理器的汇编语言中,对指令语法格式中的<shifter_operand>的常数表达式有这样的规定:“该常数必须对应8位位图,即常数是由一个8位的常数循环移位偶数位得到的。
首先从ARM指令系统的语法格式说起。
一条ARM指令语法格式分为如下几个部分:
<opcode>{<cond>}{S} <Rd>,<Rn>{,<shifter_operand>}
其中,<>内的项是必须的,{}内的项是可选的,如<opcode>是指令助记符,是必须的,而{<cond>}为指令执行条件,是可选的,如果不写则使用默认条件AL(无条件执行)。
Opcode   指令助记符,如LDR,STR 
Cond       执行条件,如EQ,NE 
                 是否影响CPSR 寄存器的值,书写时影响CPSR,否则不影响
       Rd          目标寄存器
Rn          第一个操作数的寄存器
shifter_operand      第二个操作数

其指令编码格式如下:

31-28
27-25
24-21
20  
19-16
15-12
11-0 (12位)
cond
001
opcode
S
Rn
Rd
shifter_operand

当第2 个操作数的形式为:#immed_8r常数表达式时“该常数必须对应8位位图,即常数是由一个8位的常数循环移位偶数位得到的。”
其意思是这样:
#immed_8r在芯片处理时表示一个32位数,但是它是由一个8位数(比如:01011010,即0x5A)通过循环移位偶数位得到(1000 0000 0000 0000 0000 0000 0001 0110,就是0x5A通过循环右移2位(偶数位)的到的)。
而1010 0000 0000 0000 0000 0000 0001 0110,就不符合这样的规定,编译时一定出错。因为你可能通过将1011 0101循环右移位得到它,但是不可能通过循环移位偶数位得到。1011 0000 0000 0000 0000 0000 0001 0110,也不符合这样的规定,很明显:1 0110 1011 有9位。
为什么要有这样的规定?
要从指令编码格式来解释(这就是我为什么一开始讲的是指令编码格式),仔细看表格中的shifter_operand所占的位数:12位。要用一个12位的编码来表示任意的32位数是绝对不可能的(12位数有2^12种可能,而32位数有2^32种)。
但是又要用12位的编码来表示32位数,怎么办?
只有在表示数的数量上做限制。通过编码来实现用12位的编码来表示32位数。
在12位的shifter_operand中:8位存数据,4位存移位的次数。
8位存数据:解释了“该常数必须对应8位位图”。
4位存移位的次数:解释了为什么只能移偶数位。4位只有16种可能值,而32位数可以循环移位32次(32种可能),那就只好限制:只能移偶数位(两位两位地移,好像一个16位数在移位,16种移位可能)。这样就解决了能表示的情况是实际情况一半的矛盾。
所以对#immed_8r常数表达式的限制是解决指令编码的第二个操作数位数不足以表示32位操作数的无奈之举,但在我看来:这个可以说是聪明的做法。因为如果直接用12位数来表示32位操作数,只能表示0 到(2^12-1)。大于(2^12-1)的数就没办法表示了。而且细细想来“8位存数据,4位存移位的次数”,应该是最好的组合了(我并未想过所有的组合,只是顺便试了几个)。

ARM指令第二操作数#immed_8r详解
大多数ARM通用数据处理指令有一个灵活的第2操作数(flexible second operand),这里这解释一下其中的一种格式,#immed_8r常量的表达式。常量必须对应于8位位图(pattern)。该位图在32位字中,被循环移位偶数位(0,2,4,...28,30)。合法常量0xff,0xff000,0xf000000f。非法常量:0x101,0xff04
ARM 在32位模式下,一条指令长度为32位,在上述数据处理指令中,操作数2为12位。所以像0x7f02这样的数,要两条指令才能完成。
MOV     R3, #0x7F00    ;E3 A0 3C 7F 该指令自己完成0x7f移位
ORR     R1, R3, #2
所以直接是找不到0x7f02的
关于循环移位,其实arm中只有循环右移(ROR)。0x7f到0x7f00是通过循环右移24次才实现的,这里每次移动2位所以是12次(0xc)
在 ARM 数据处理指令中, 当参与操作的第二操作数为立即数时, 每个立即数都是采用一个8位的常数循环右移偶数位而间接得到, 其中循环右移的位数有一个4位二进制的2倍表示. 则有效立即数可表示为: <immediate> := immed_8; 循环右移(2×rotate_imm). 其中: <immediate> 代表立即数, immed_8 代表8位常数,  即所谓的"8位图", rotate_imm 代表4位的循环右移值. 这样一来出现了一个问题: 尽管表示的范围变大了, 但是12位所能表现的数字的个数是一定的. 因此, ARM 规定并不是所有的32位常数都是合法的立即数, 只有通过上面的构造方法得到的才是合法的立即数, 编译的时候才不会报错.
举个例子吧.
0x3FC(0000 0000 0000 0000 0000 0011 1111 1100) 是由 0xff 循环右移 2 位得到的;
200(0000 0000 0000 0000 0000 0000 1100 1000) 是由 0xc8 循环右移 2 位得到的, 它们都是合法的.
而 0x1FE(0000 0000 0000 0000 0000 0001 1111 1110) 和
511(0000 0000 0000 0000 0000 0001 1111 1111) 无法看成是8位的常数循环右移偶数位而得到的, 因此是非法的.
指令操作数立即数时候,每个立即数由一个8位的常数循环右移偶数位得到。

<immediate>= immed_8 循环右移( 2*rotate_imm)

打个比如:
1.立即数0xF200是由0xCF2间接表示的,即是由8位的0xF2循环右移24(2*12)得到的
immed_8 == 0xF2;   rotate_imm == 0xC

2.立即数0x3F0是由0xE3F间接表示的,即是由8位的0x3F循环右移28(2*14)得到的
immed_8 == 0x3F;   rotate_imm == 0xE
或者
立即数0x3F0是由0xFFC间接表示的,即是由8位的0xFC循环右移30(2*15)得到的
immed_8 == 0xFC;   rotate_imm == 0xF

表示方法有好几种

PS:其实你没必要一个一个的算,只要利用LDR伪指令就可以了,例如:
ldr r1, =12345678
编译器自然会给你做工作,现实的编程中应该也是这个居多吧

比较下来, 我们可以这样总结:
  1. 判断一个数是否符合8位位图的原则, 首先看这个数的二进制表示中1的个数是否不超过8个. 如果不超过8个, 再看这n个1(n<=8)是否能同时放到8个二进制位中, 如果可以放进去, 再看这八个二进制位是否可以循环右移偶数位得到我们欲使用的数. 如果可以, 则此数符合8位位图原理, 是合法的立即数. 否则, 不符合.
  2. 无法表示的32位数, 只有通过逻辑或算术运算等其它途径获得了. 比如0xffffff00, 可以通过0x000000ff按位取反得到.
因此以后的编程中, 时刻检查用到的第二操作数是否符合8位位图是一件千万不能疏忽的事. 至于为什么要将这12位 operand2 "八四开", 这个问题就要请教大牛了.

计算机中的存储段类型

计算机中的存储管理中有三个数据段: 代码段(.text)、数据段(.data)以及BSS段(.bss).
这里首先区分一下.data与.bss,两个段存放的都是数据,区别是data段中的数据是带有初始化的,所以运行前其在代码段中的存储要包括段的大小以及初始化值,而bss段中的数据是不带有初始化值的,所以其在运行前在代码段中只包含段的大小信息,故未初始化的变量如果定义多了,代码会很小(其实仔细想想这是一句废话,变量不初始化,代码段中就不包含初始化信息,代码自然就小了).

note:其实仔细想想,编译器这样做是有一定的道理的。如果只用bss的话,有时候我们需要在变量中放入一些非常重要的初始化数据。如果我们都是用data段的话,本来一些不需要初始化的变量都要被迫地初始化一些值,这是对程序存储空间的浪费。

ARM中的RO、RW、ZI的内容

RO = 代码段(.text) + 常量数据段(.constdata) + ...(something I don't know now)
RW = 变量数据段(.data)
ZI = BSS数据段(.bss)

这里RO运行前运行后都只保存在flash中;RW运行前保存在flash中,运行后copy至RAM;ZI同RW一样,只是ZI在flash中没有初始化值。

arm汇编中的literal pools

        literal pools是一个用于存储32bit数据的字池,由于机器码的操作数operand2只有12位,所以其能操作的立即数是及其有限的,因此不得不使用一个literal pools来配合指令执行操作。这样一个ldr指令就有可能需要两个32bit的存储空间来完成一个任务。 如果一段代码中需要访问字池时,编译器首先寻找现有的字池,看看里面是否有想要的数据,如果没有则自动在代码段结尾处创建一个字池,当然也可以使用伪指令LTORG来自行创建一个字池。下面说一下字池的位置:
1、字池的位置一般是放在一个代码段的结束位置(一个代码段一般用AREA来定义),一般是在END的后面,或者下一个段(即下一个AREA指令)之前。
2、也可以使用伪指令LTORG自定义一个位置,但一般是在无条件跳转指令的后面,以保证literal pools不会被误当做可执行指令被执行。
3、还有一点,字池的位置要在指令的可执行位置范围内,即要在距离PC指针4k的范围内
(原因同样是因为operand2只有12位,即可寻址范围只有4k)
    举例如下:
        start
                bl func1
                bl func2
        stop
                mov r0,#0x18
                ldr r1,=0x20026
        ;        SVC #0x123456
        func1
                ldr r0,=42
                ldr r1,=0x55555555
                ldr r2,=0xffffffff
                bx lr
                LTORG
        func2
                ldr r3,=0x55555555
                ldr r4,=0x66666666
                bx lr
        LargeTable
                SPACE 4200
                END
    反汇编可以看见
           29 00000018 E3E02000        ldr     r2,=0xffffffff
           30 0000001C E12FFF1E        bx      lr
           31 00000020 00020026
                      55555555         LTORG
           32 00000028         func2
     subroutine结尾处,bx lr后面使用了两个32bit的存储单元用来存放stop中的0x20026以及func1中的0x55555555.(0xffffffff可以用指令mvn解决),但是该段代码编译后会在指令ldr r4,=0x66666666处产生一个错误,即literal pools is too distant, use LTORG to assemble it within 4KB。即literal pools超出可寻址范围4kB。
     如果此时将LargeTable后面的SPACE 4200改成4092(因为bx lr要占用一个32bit空间).
                LargeTable
                SPACE 4092
                END
     就不会出现上面的错误了。

adr与ldr的区别

adr与ldr r0, =label的区别:
adr 和 ldr r0, =label(这里不包括ldr的一般用法)都是pseudo-instruction
adr r0, label与ldr r0, =label实际上实现的功能都是一样儿的,都是将label的地址存放到r0中,但是由于adr中用的是相对地址且使用一个汇编指令完成,故其寻址范围限制在4k的范围内。但是ldr则不同,由于其使用了literal pools,寻址范围可以在4G的任意范围(但是切记literal pools的位置仍然要在4k之内)。如果说两者之间有什么不同的话,那就是:使用ldr要比使用adr浪费一些存储空间(如果label距离PC不是很远的情况下,使用adr是合理的)。

使用arm的启动代码2440init.s来举例如下:
代码未作任何修改的代码如下:
copy_proc_beg
        adr        r0, ResetEntry
        ldr        r2, BaseOfROM
        cmp        r0, r2
        ldreq      r0, TopOfROM
        beq        InitRam      
        ldr        r3, TopOfROM
其反汇编结果如下:
   copy_proc_beg
        0x00000268:    e24f0f9c    ..O.    SUB      r0,pc,#0x270 ; #0
        0x0000026c:    e59f2140    @!..    LDR      r2,0x3b4
        0x00000270:    e1500002    ..P.    CMP      r0,r2
        0x00000274:    059f013c    <...    LDREQ    r0,0x3b8
        0x00000278:    0afffffe    ....    BEQ      InitRam  ; 0x298
        0x0000027c:    e59f3134    41..    LDR      r3,0x3b8
可见此时r0的值正好是(pc+8-270)=0x0(至于这里为什么加8请看后面),即ResetEntry的位置。
将adr r0, ResetEntry改写成ldr r0, =ResetEntry后代码如下:
copy_proc_beg
        ldr            r0, =ResetEntry
        ldr            r2, BaseOfROM
        cmp        r0, r2
        ldreq       r0, TopOfROM
        beq         InitRam      
        ldr            r3, TopOfROM
反汇编结果如下:
   copy_proc_beg
        0x00000268:    e59f00f0    ....    LDR      r0,0x360
        0x0000026c:    e59f2144    D!..    LDR      r2,0x3b8
        0x00000270:    e1500002    ..P.    CMP      r0,r2
        0x00000274:    059f0140    @...    LDREQ    r0,0x3bc
        0x00000278:    0afffffe    ....    BEQ      InitRam  ; 0x298
        0x0000027c:    e59f3138    81..    LDR      r3,0x3bc
可见这里是将0x360处的值赋给了r0,而0x360处在literal pools中,如下:
    $d(表示literal pools位置)
        0x00000328:    4a000008    ...J    DCD    1241513992
        0x0000032c:    4a00001c    ...J    DCD    1241514012
        0x00000330:    00007fff    ....    DCD    32767
        0x00000334:    4c000014    ...L    DCD    1275068436
        0x00000338:    4c000008    ...L    DCD    1275068424
        0x0000033c:    00038022    "...    DCD    229410
        0x00000340:    4c000004    ...L    DCD    1275068420
        0x00000344:    0005c011    ....    DCD    376849
        0x00000348:    560000b4    ...V    DCD    1442840756
        0x0000034c:    56000050    P..V    DCD    1442840656
        0x00000350:    56000058    X..V    DCD    1442840664
        0x00000354:    56000054    T..V    DCD    1442840660
        0x00000358:    000055aa    .U..    DCD    21930
        0x0000035c:    00000268    h...    DCD    616
        0x00000360:    00000000    ....    DCD    0
        0x00000364:    000002c8    ....    DCD    712
        0x00000368:    00000000    ....    DCD    0
        0x0000036c:    000000d8    ....    DCD    216
        0x00000370:    33ff5c00    .\.3    DCD    872373248
        0x00000374:    33ff6000    .`.3    DCD    872374272
        0x00000378:    33ff7000    .p.3    DCD    872378368
        0x0000037c:    33ff8000    ...3    DCD    872382464
        0x00000380:    33ff5800    .X.3    DCD    872372224
此处的值正好位0x0,即ResetEntry的位置。
在程序的423行,可以看到有一个LTORG伪指令,正是由于这个原因,编译器才会在0x00000328位置开始建立literal pools。有关literal pools可以参考http://blog.csdn.net/caimingda1987/article/details/6662893




前面提到pc指针默认加8的原因如下(转载):


2440是三级流水线结构,下面来讲讲为什么三级流水线,故名思义,就是一个时刻做三件事情,对于2440来说,那就是取指,译码,执行
取指 译码 执行。。。
   取指 译码 执行。。。
             取指 译码 执行。。。
那么问一个问题,PC究竟是指向取指呢,译码呢,还是执行,由此便带来一个问题,当前指令执行的时候,PC的值已经不是当前指令所在的地址了,而是
当前地址+8
   0x00000000
   0x00000004        ---假设为当前执行的指令地址
   0x00000008
PC-> 0x0000000c        PC指向的是这儿

Playing game Blockbreaker in hyperterminal through 8051(Assembly language)

Use keyboard to send move orders to 8051 microcontroller through RS232.
8051 calculate the position of paddle and the ball, check if the bricks are hit. Then 8051 return the result to hyperterminal to display the game interface through RS232.
All written in assembly language.

You can refer to the following website to learn how to control the cursor and display colour in hyperterminal.
http://ascii-table.com/ansi-escape-sequences-vt-100.php

The serial port configuration is:

        Baud rate: 19200
        Data bits: 8
        Parity check: none
        Stop bits: 1
        Flow control: none

Game is shown below:





Source code:
#include <sfr51.inc>             ; 8051 sfr and ports are defined here

HONR            EQU 95           ; ASCII of "_"
VERT            EQU 124          ; ASCII of "|"
SPACE           EQU 32           ; ASCII of space

FRAME_TOPLEFT_X EQU 23           ; the x value of left top of the frame
FRAME_TOPLEFT_Y EQU 05           ; the y value of left top of the frame
FRAME_L         EQU 24           ; length of frame
FRAME_H         EQU 10            ; height of frame
FRAME_COLOUR    EQU 33H
HONR_BRICKS     EQU 5            ; number of bricks in a line
VERT_BRICKS     EQU 4            ; number of bricks in a column
BRICKS_COLOUR   EQU 35H

BRICK_L         EQU 4            ; the length of a brick
BOARD_L         EQU 6            ; the length of the board
BOARD_ORIG_X    EQU FRAME_TOPLEFT_X+8           ; the original X position of the board
BOARD_ORIG_Y    EQU FRAME_TOPLEFT_Y+8           ; the original Y position of the board
BOARD_COLOUR    EQU 34H
LEFT            EQU 97           ; Left direction ASCII ('a')
RIGHT           EQU 100          ; Right direction ASCII ('b')
STEP            EQU 2            ; Steps the board move


BALL            EQU 42           ; The ASCII of ball ('*')
BALL_ORIG_X     EQU 13           ; the original X position of the ball
BALL_ORIG_Y     EQU 8            ; the original Y position of the ball
SPEED           EQU 01           ; The speed of the ball

RED             EQU 31H
GREEN           EQU 32H
BLUE            EQU 34H
YELLOW          EQU 33H
WHITE           EQU 37H
MAGENTA         EQU 35H


STACK         EQU 70H                  ; stack pointer starting address(growing upward)

        DSEG    AT  08H
        LOCATE_IN0:     DS       1
        LOCATE_IN1:     DS       1
        ASCII_HONR:     DS       1       ; 
        ASCII_VERT:     DS       1
        TEMP:           DS       1
        TEMP1:          DS       1
        TEMP2:          DS       1
        END

        BSEG    AT  00H
        DATA_RX:        DBIT     1
        ONE_SEC:        DBIT     1
        END

        DSEG    AT  18H
        MYSTACK:        DS       8       ; my working stack
        END

        DSEG AT 30h                 
        BRICKS_X:       DS       20     ; This is unnecessary
        BRICKS_KEY:     DS       20
        DIRECTION:      DS       1
        BOARD_X:        DS       1
        TIMER_COUNT:    DS       1
        BALL_X:         DS       1
        BALL_Y:         DS       1
        BALL_X_STEP:    DS       1
        BALL_Y_STEP:    DS       1
        IN0:            DS       1
        IN1:            DS       1
        IN2:            DS       1
        IN3:            DS       1
        IN4:            DS       1
        IN5:            DS       1
        IN6:            DS       1
        IN7:            DS       1
        SCORE:          DS       1
        END

;-------------------------------------------------------------------------
;       Beginning of the main program
;-------------------------------------------------------------------------
        CSEG AT 0000h      ; absolute code segment starting at 0000h
        LJMP START       ; reset vector - first instruction is to jump to user program
        END
        CSEG AT 23H  ; serial port interrupt vector address 
        LJMP SERIAL_ISR
        END
        CSEG AT 0BH
        LJMP TIMER_ISR
        END
        CSEG AT 0100H      ; absolute code segment starting at 0100h
        TITLE:   DB "BLOCKBREAKER"              ; Position X: 34 Y: 3
        GAMEOVER: DB    "GAME OVER!"                ; Position X: 35 Y: 9
        YOUWIN:   DB    "CONGRATULATIONS! YOU WIN!" ; Position X: 28 Y: 9
START:
        NOP
        NOP

        MOV SP, #STACK          ; set up the stack pointer
        LCALL INIT_SERIAL
        LCALL INIT_TIMER0

        MOV   A, #0CH            ;clear hyperterminal
        LCALL TX_DATA
        MOV   A, #0CH
        LCALL TX_DATA

        LCALL CLEAR
        LCALL INIT_BRICKS

        MOV BOARD_X, #BOARD_ORIG_X
        MOV IN0, BOARD_X
        MOV IN1, #BOARD_ORIG_Y
        MOV IN2, #BOARD_L
        MOV IN3, #1
        MOV IN4, #BOARD_COLOUR
        MOV ASCII_HONR, #HONR
        MOV ASCII_VERT, #VERT
        LCALL DRAW_SQUARE
        MOV A, #BALL_ORIG_X
        ADD A, #FRAME_TOPLEFT_X
        MOV BALL_X, A
        MOV A, #BALL_ORIG_Y
        ADD A, #FRAME_TOPLEFT_Y
        MOV BALL_Y, A
        MOV BALL_X_STEP, #FFH
        MOV BALL_Y_STEP, #01H  
;;;;;;;;;;;;;;;;;Draw the main frame;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV IN0, #18
        MOV IN1, #1
        MOV IN2, #44
        MOV IN3, #17
        MOV IN4, #GREEN
        LCALL DRAW_SQUARE
;;;;;;;;;;;;;;;;;Draw title;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV R2, #12
        MOV LOCATE_IN0, #34
        MOV LOCATE_IN1, #3
        LCALL LOCATE
        MOV DPTR, #TITLE
LABEL0:        
        CLR     A
        MOVC A, @A+DPTR
        INC     DPTR
        ACALL TX_DATA
        DJNZ R2, LABEL0

LOOP:

        LCALL FRAME_WORK
        LCALL CHECK_KEY
        LCALL BALL_MOVE
        
        LJMP LOOP
;----------------------------------------------------------------------------
;       The movement of ball
;----------------------------------------------------------------------------
BALL_MOVE:
        LCALL PUSHSTACK
        JB ONE_SEC, BALL_LABEL1
        LJMP BALL_LABEL0
BALL_LABEL1:
        CLR ONE_SEC
        MOV TIMER_COUNT, #SPEED
;;;;;;;;;;;;;;;;;;;;;;;;;judge if the ball hit the frame;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        CLR C
        MOV A, BALL_X
        SUBB A, #FRAME_TOPLEFT_X
        JZ MOVE_LABEL0
        CLR C
        MOV A, #FRAME_TOPLEFT_X-1
        ADD A, #FRAME_L
        MOV R2, A
        MOV A, BALL_X
        SUBB A, R2                      ;#FRAME_L+#FRAME_TOPLEFT_X-1
        JZ MOVE_LABEL0
        SJMP MOVE_LABEL1
MOVE_LABEL0:
        XRL BALL_X_STEP, #11111110B
MOVE_LABEL1:
        CLR C
        MOV A, BALL_Y
        SUBB A, #FRAME_TOPLEFT_Y+1
        JZ MOVE_LABEL2
        CLR C
        MOV A, #FRAME_TOPLEFT_Y
        ADD A, #BALL_ORIG_Y
        MOV R2, A
        MOV A, BALL_Y
        SUBB A, R2                   ;#BALL_ORIG_Y+#FRAME_TOPLEFT_Y
        JZ MOVE_LABEL2
        SJMP MOVE_LABEL3
MOVE_LABEL2:
        XRL BALL_Y_STEP, #11111110B
MOVE_LABEL3:
        MOV IN0, BALL_X
        MOV IN1, BALL_Y
        MOV IN2, #SPACE
        MOV IN3, #RED
        LCALL PIXELDISP
        MOV A, BALL_X_STEP
        ADD A, BALL_X
        MOV BALL_X, A
        MOV A, BALL_Y_STEP
        ADD A, BALL_Y
        MOV BALL_Y, A
        MOV IN0, BALL_X
        MOV IN1, BALL_Y
        MOV IN2, #BALL
        MOV IN3, #RED
        LCALL PIXELDISP
;;;;;;;;;;;;;;;;;;;;;;;;;judge if the ball hit the bricks;;;;;;;;;;;;;;;;;;;;;;;;
        MOV R0, #BRICKS_KEY+20                      ; pointer that points to BRICKS_KEY+20 position
        MOV R1, #BRICKS_X+5                         ; pointer that points to BRICKS_X+5
        MOV R3, #VERT_BRICKS                        ; j count
        MOV R4, #HONR_BRICKS                        ; i count
MOVE_LABEL4:
        MOV R4, #HONR_BRICKS                        ; i count
        MOV R1, #BRICKS_X+5                         ; pointer that points to BRICKS_X+5
MOVE_LABEL5:
        DEC R1
        DEC R0        
        MOV A, BALL_X
        INC A
        CLR C
        SUBB A, @R1                                 ; if(BALL_X+1>=@R1)
        JC MOVE_LABEL6        
        MOV A, @R1
        ADD A, #BRICK_L+1
        MOV R6, A
        MOV A, BALL_X
        CLR C
        SUBB A, R6                                  ; if(BALL_X<@R1+#BRICK_L+1)
        JNC MOVE_LABEL6        
        CLR C
        MOV A, R3
        ADD A, #FRAME_TOPLEFT_Y
        MOV R6, A
        INC R6
        MOV A, BALL_Y
        SUBB A, R6                                  ; if(BALL_Y==R6+1)
        JNZ MOVE_LABEL6        
        MOV A, @R0
        CLR C
        SUBB A, #1
        JNZ MOVE_LABEL6
        SJMP DESTROY
MOVE_LABEL6:
        DJNZ R4, MOVE_LABEL5
        DJNZ R3, MOVE_LABEL4
        SJMP MOVE_LABEL7
DESTROY:        
        XRL BALL_Y_STEP, #11111110B
        MOV @R0, #0
        MOV A, R4
        DEC A
        MOV B, #BRICK_L+1
        MUL AB
        ADD A, #FRAME_TOPLEFT_X
        MOV IN0, A
        MOV A, R3
        ADD A, #FRAME_TOPLEFT_Y-1
        MOV IN1, A
        LCALL DELETE_SQUARE
        INC SCORE
        LCALL DISPSCORE
        MOV A, #20
        CJNE A, SCORE, MOVE_LABEL7
        LCALL WIN_GAME
MOVE_LABEL7:
;;;;;;;;;;;;;;;;;;;;;;;;;judge if the ball hit the board;;;;;;;;;;;;;;;;;;;;;;;;;
        CLR C
        MOV A, BALL_Y
        SUBB A, #BOARD_ORIG_Y
        JNZ BALL_LABEL0
        CLR C
        MOV R6, BOARD_X
        DEC R6
        MOV A, BALL_X
        SUBB A, R6
        JC MOVE_LABEL8
        CLR C
        MOV R6, BOARD_X
        MOV A, R6
        ADD A, #BOARD_L+1
        MOV R6, A
        MOV A, BALL_X
        SUBB A, R6
        JNC MOVE_LABEL8
        SJMP BALL_LABEL0
MOVE_LABEL8:
        LCALL LOSE_GAME
BALL_LABEL0:   

        LCALL POPSTACK
        XRL P1, #FFH
        RET
;-------------------------------------------------------------------------------
;       Win game
;       --Position X: 28 Y:9
;       --Num: 25
;-------------------------------------------------------------------------------
WIN_GAME:
        MOV A, #0CH
        LCALL TX_DATA
        MOV A, #0CH
        LCALL TX_DATA
;;;;;;;;;;;;;;;;;Draw the main frame;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV IN0, #18
        MOV IN1, #1
        MOV IN2, #44
        MOV IN3, #17
        MOV IN4, #GREEN
        LCALL DRAW_SQUARE
;;;;;;;;;;;;;;;;;Draw win notification;;;;;;;;;;;;;;;;;;;;;;;;
        MOV R2, #25
        MOV LOCATE_IN0, #28
        MOV LOCATE_IN1, #9
        LCALL LOCATE
        MOV DPTR, #YOUWIN
WIN_LABEL0:        
     CLR     A
     MOVC A, @A+DPTR
     INC     DPTR
     LCALL TX_DATA
     DJNZ R2, WIN_LABEL0
        
        SJMP $+0
        RET
;--------------------------------------------------------------------------------
;       Lose game
;       --Position X: 35 Y:9
;       --Num: 10
;--------------------------------------------------------------------------------
LOSE_GAME:
        MOV A, #0CH
        LCALL TX_DATA
        MOV A, #0CH
        LCALL TX_DATA
;;;;;;;;;;;;;;;;;Draw the main frame;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV IN0, #18
        MOV IN1, #1
        MOV IN2, #44
        MOV IN3, #17
        MOV IN4, #GREEN
        LCALL DRAW_SQUARE
;;;;;;;;;;;;;;;;;Draw fail notification;;;;;;;;;;;;;;;;;;;;;;
        MOV R2, #10
        MOV LOCATE_IN0, #35
        MOV LOCATE_IN1, #9
        LCALL LOCATE
        MOV DPTR, #GAMEOVER
LOSE_LABEL0:        
        CLR     A
        MOVC A, @A+DPTR
        INC     DPTR
        LCALL TX_DATA
        DJNZ R2, LOSE_LABEL0
        
        SJMP $+0
        RET
;--------------------------------------------------------------------------------
;       Display score
;--------------------------------------------------------------------------------
DISPSCORE:

        MOV A, #1BH              ; 'ESC'
        LCALL TX_DATA
        MOV A, #5BH              ; '['
        LCALL TX_DATA
        MOV A, #GREEN
        SWAP A
        ANL A, #0FH
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #GREEN
        ANL A, #0FH
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #6DH              ; 'm'
        LCALL TX_DATA

        MOV LOCATE_IN0, #55
        MOV LOCATE_IN1, #9
        LCALL LOCATE
        MOV A, SCORE
        MOV B, #10
        DIV AB
        ADD A, #30H
        LCALL TX_DATA  
        MOV A, B
        ADD A, #30H
        LCALL TX_DATA

        RET
;--------------------------------------------------------------------------------
;       Check the key board
;--------------------------------------------------------------------------------
CHECK_KEY:
        LCALL PUSHSTACK

        MOV C, DATA_RX
        JNC CHECK_LABEL2
        MOV IN0, BOARD_X
        MOV IN1, #BOARD_ORIG_Y
        MOV IN2, #BOARD_L
        MOV IN3, #1
        MOV IN4, #BOARD_COLOUR
        MOV ASCII_HONR, #SPACE
        MOV ASCII_VERT, #SPACE
        LCALL DRAW_SQUARE
        CLR C
        MOV DATA_RX, C
        MOV A, #LEFT
        CLR C
        SUBB A, DIRECTION
        JNZ CHECK_LABEL1
        MOV A, BOARD_X
        CLR C
        SUBB A, #STEP
        MOV BOARD_X, A
CHECK_LABEL1:
        MOV A, #RIGHT
        CLR C
        SUBB A, DIRECTION
        JNZ CHECK_LABEL0
        MOV A, #STEP
        ADD A, BOARD_X
        MOV BOARD_X, A
CHECK_LABEL0:
        MOV IN0, BOARD_X
        MOV IN1, #BOARD_ORIG_Y
        MOV IN2, #BOARD_L
        MOV IN3, #1
        MOV IN4, #BOARD_COLOUR
        MOV ASCII_HONR, #HONR
        MOV ASCII_VERT, #VERT
        LCALL DRAW_SQUARE
CHECK_LABEL2:

        LCALL POPSTACK
        RET
;--------------------------------------------------------------------------------
;       Initialization of some variables
;--------------------------------------------------------------------------------
CLEAR:
        MOV SCORE, #0
        CLR C
        MOV DATA_RX, C
        RET
;-------------------------------------------------------------------------------
;       Initialization of brick position and life value
;-------------------------------------------------------------------------------
INIT_BRICKS:
        LCALL PUSHSTACK

        MOV R0, #BRICKS_X               ; Initialize X of bricks
        MOV R2, #HONR_BRICKS
        MOV A, #FRAME_TOPLEFT_X
BRICKS_X_LABEL:
        MOV @R0, A
        ADD A, #BRICK_L+1
        INC R0
        DJNZ R2, BRICKS_X_LABEL

        MOV R0, #BRICKS_KEY             ; Initialize the life of bricks
        MOV R2, #20
BRICKS_KEY_LABEL:
        MOV @R0, #1
        INC R0
        DJNZ R2, BRICKS_KEY_LABEL
 
        LCALL POPSTACK
        RET
;--------------------------------------------------------------------------------
;       Delete a certain square
;       --IN0-The position of square in line
;       --IN1-The position of square in column
;--------------------------------------------------------------------------------
DELETE_SQUARE:
        LCALL PUSHSTACK
        
        MOV IN2, #BRICK_L
        MOV IN3, #1
        MOV IN4, #WHITE
        MOV ASCII_HONR, #SPACE
        MOV ASCII_VERT, #SPACE
        LCALL DRAW_SQUARE

        LCALL POPSTACK
        RET
;--------------------------------------------------------------------------------
;       Frame work of game
;       --IN0-left top X of frame
;       --IN1-left top Y of frame
;--------------------------------------------------------------------------------
FRAME_WORK:
        LCALL PUSHSTACK

        MOV IN0, #FRAME_TOPLEFT_X
        MOV IN1, #FRAME_TOPLEFT_Y
        MOV IN2, #FRAME_L
        MOV IN3, #FRAME_H
        MOV ASCII_HONR, #HONR
        MOV ASCII_VERT, #VERT
        MOV IN4, #FRAME_COLOUR
        LCALL DRAW_SQUARE   
;;;;;;;;;;;;;;;;;;;;;;;;;;;DISPLAY COLOUR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;     
        MOV A, #1BH              ; 'ESC'
        LCALL TX_DATA
        MOV A, #5BH              ; '['
        LCALL TX_DATA
        MOV A, #BRICKS_COLOUR
        SWAP A
        ANL A, #0FH
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #BRICKS_COLOUR
        ANL A, #0FH
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #6DH              ; 'm'
        LCALL TX_DATA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV R1, #HONR_BRICKS
        MOV R2, #BRICK_L
        MOV R4, #VERT_BRICKS
        MOV R0, #BRICKS_KEY
        MOV LOCATE_IN0, #FRAME_TOPLEFT_X
        MOV LOCATE_IN1, #FRAME_TOPLEFT_Y+1
        LCALL LOCATE

FRAME_LABEL2:
        MOV R1, #HONR_BRICKS
FRAME_LABEL3:
        MOV R2, #BRICK_L
        MOV A, @R0
        INC R0
        JZ FRAME_LABEL7
        LCALL MOVE_L
        MOV A, #VERT
        LCALL TX_DATA
FRAME_LABEL4:
        MOV A, #HONR
        LCALL TX_DATA
        DJNZ R2, FRAME_LABEL4
        MOV A, #VERT
        LCALL TX_DATA
        SJMP FRAME_LABEL8
FRAME_LABEL7:
        LCALL MOVE_R
        DJNZ R2, FRAME_LABEL7
        LCALL MOVE_R
FRAME_LABEL8:
        DJNZ R1, FRAME_LABEL3
        INC LOCATE_IN1
        LCALL LOCATE
        DJNZ R4, FRAME_LABEL2

        LCALL POPSTACK
        RET

;-------------------------------------------------------------------------
;      Move action
;-------------------------------------------------------------------------
MOVE_R:
        MOV A, #1BH
        LCALL TX_DATA
        MOV A, #5BH
        LCALL TX_DATA
        MOV A, #43H
        LCALL TX_DATA
        RET
MOVE_L:
        MOV A, #1BH
        LCALL TX_DATA
        MOV A, #5BH
        LCALL TX_DATA
        MOV A, #44H
        LCALL TX_DATA
        RET
;--------------------------------------------------------------------------------
;       Push working registers into my stack
;--------------------------------------------------------------------------------
PUSHSTACK:
        MOV TEMP, R0
        MOV R0, #MYSTACK
        MOV @R0, TEMP
        INC R0
        MOV A, R1
        MOV @R0, A
        INC R0
        MOV A, R2
        MOV @R0, A
        INC R0
        MOV A, R3
        MOV @R0, A
        INC R0
        MOV A, R4
        MOV @R0, A
        INC R0
        MOV A, R5
        MOV @R0, A
        INC R0
        MOV A, R6
        MOV @R0, A
        INC R0
        MOV A, R7
        MOV @R0, A
        MOV R0, TEMP
        RET
;--------------------------------------------------------------------------------
;       Pop working registers back from my stack
;--------------------------------------------------------------------------------

POPSTACK:
        MOV R0, #MYSTACK
        INC R0
        MOV A, @R0
        MOV R1, A
        INC R0
        MOV A, @R0
        MOV R2, A
        INC R0
        MOV A, @R0
        MOV R3, A
        INC R0
        MOV A, @R0
        MOV R4, A
        INC R0
        MOV A, @R0
        MOV R5, A
        INC R0
        MOV A, @R0
        MOV R6, A
        INC R0
        MOV A, @R0
        MOV R7, A
        MOV R0, #MYSTACK
        MOV A, @R0
        MOV R0, A
        RET

;--------------------------------------------------------------------------------
;       Initialization of serial
;--------------------------------------------------------------------------------
INIT_SERIAL:        ; initialize serial port (& timer 1) for serial communication 
        CLR EA
        CLR ES              ; disable serial port interrupt 
        ORL PCON, #80H          ; set baudrate 19200
        MOV SCON, #50h      ; set serial port(mode 1 : 8-bit variable baudrate) 
        MOV TMOD, #20h      ; timer 1 mode 2 : 8-bit auto reload mode 
        MOV TH1, #0fdh      ; reload value for baudrate 
        MOV IE, #10010010B      ; enable time interrupt, enable serial interrupt and enable the mother interrupt bit
        SETB TR1       ; start timer 1 
        RET
;---------------------------------------------------------
;                       init timer                       ;
;---------------------------------------------------------

INIT_TIMER0:            ; routine to initialize timer 0 (complete the following routine) 
        CLR   EA               ; disable all interrupt 
        CLR   ET0             ; disable timer0 interrupt 
        CLR   TR0              ; stop timer0  
        CLR   ONE_SEC
        MOV   TL0, #0fch        ; load timer value 
        MOV   TH0, #0fh 
        MOV  TIMER_COUNT,  #SPEED
        MOV    TMOD,#21h       ; timer 0 in 16 bit internal mode , timer1 is used to provide one second
        SETB   ET0             ; timer 0 interrupt enabled 
        SETB   EA              ; enable cpu to be interrupted 
        SETB   TR0                ; start timer 0 鈥?i.e. run
        RET 
;--------------------------------------------------------------------------------
;       Locate cursor subroutine
;       --LOCATE_IN0-X position
;       --LOCATE_IN1-Y position
;--------------------------------------------------------------------------------
LOCATE:       
        LCALL PUSHSTACK
        MOV A, #1BH              ; 'ESC'
        LCALL TX_DATA
        MOV A, #5BH              ; '['
        LCALL TX_DATA
        MOV A, LOCATE_IN1
        MOV B, #10
        DIV AB
        ADD A, #30H
        LCALL TX_DATA  
        MOV A, B
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #3BH              ; ';'
        LCALL TX_DATA
        MOV A, LOCATE_IN0
        MOV B, #10
        DIV AB
        ADD A, #30H
        LCALL TX_DATA
        MOV A, B
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #48H              ; 'H'
        LCALL TX_DATA
        LCALL POPSTACK
        RET       
;--------------------------------------------------------------------------------
;       Cursor control subroutine
;       --IN0-X position(from 1)
;       --IN1-Y position(from 1)
;       --IN2-ASCII(BALL or SPACE)
;       --IN3-Colour
;--------------------------------------------------------------------------------
PIXELDISP: 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;DISPLAY COLOUR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;       
        LCALL PUSHSTACK

        MOV A, #1BH              ; 'ESC'
        LCALL TX_DATA
        MOV A, #5BH              ; '['
        LCALL TX_DATA
        MOV A, IN3
        SWAP A
        ANL A, #0FH
        ADD A, #30H
        LCALL TX_DATA
        MOV A, IN3
        ANL A, #0FH
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #6DH              ; 'm'
        LCALL TX_DATA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;LOCATE AND DISPLAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV A, #1BH              ; 'ESC'
        LCALL TX_DATA
        MOV A, #5BH              ; '['
        LCALL TX_DATA
        MOV A, IN1
        MOV B, #10
        DIV AB
        ADD A, #30H
        LCALL TX_DATA  
        MOV A, B
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #3BH              ; ';'
        LCALL TX_DATA
        MOV A, IN0
        MOV B, #10
        DIV AB
        ADD A, #30H
        LCALL TX_DATA
        MOV A, B
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #48H              ; 'H'
        LCALL TX_DATA
        MOV A, IN2
        LCALL TX_DATA

        LCALL POPSTACK

        RET


;--------------------------------------------------------------------------------
; Draw a square (move right at least one time whatever, different from PIXELDISP)
;       --IN0-Left top X (use hex)
;       --IN1-Left top Y (use hex)
;       --IN2-Longth of square
;       --IN3-Height of square
;       --IN4-Colour of square
;       --ASCII_HONR-The ASCII display in line
;       --ASCII_VERT-The ASCII display in column
;--------------------------------------------------------------------------------
DRAW_SQUARE:
        LCALL PUSHSTACK
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;DISPLAY COLOUR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;       
        LCALL PUSHSTACK

        MOV A, #1BH              ; 'ESC'
        LCALL TX_DATA
        MOV A, #5BH              ; '['
        LCALL TX_DATA
        MOV A, IN4
        SWAP A
        ANL A, #0FH
        ADD A, #30H
        LCALL TX_DATA
        MOV A, IN4
        ANL A, #0FH
        ADD A, #30H
        LCALL TX_DATA
        MOV A, #6DH              ; 'm'
        LCALL TX_DATA
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Draw up lines;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV LOCATE_IN0, IN0
        MOV LOCATE_IN1, IN1
        LCALL LOCATE
        MOV R2, IN2
UP_HONR:
        MOV A, ASCII_HONR
        LCALL TX_DATA
        DJNZ R2, UP_HONR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Draw down lines;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV A, IN1
        ADD A, IN3
        MOV LOCATE_IN1, A
        LCALL LOCATE
        MOV R2, IN2
DOWN_HONR:
        MOV A, ASCII_HONR
        LCALL TX_DATA
        DJNZ R2, DOWN_HONR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Draw left lines;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        DEC LOCATE_IN0
        LCALL LOCATE
        MOV R2, IN3
LEFT_VERT:
        MOV A, ASCII_VERT
        LCALL TX_DATA
        DEC LOCATE_IN1
        LCALL LOCATE
        DJNZ R2, LEFT_VERT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Draw right lines;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        MOV A, IN2
        ADD A, IN0
        MOV LOCATE_IN0, A
        INC LOCATE_IN1
        LCALL LOCATE
        MOV R2, IN3
RIGHT_VERT:
        MOV A, ASCII_VERT
        LCALL TX_DATA
        INC LOCATE_IN1
        LCALL LOCATE
        DJNZ R2, RIGHT_VERT

        LCALL POPSTACK
        RET

;-------------------------------------------------------------------------
;      Serial deliver
;-------------------------------------------------------------------------
TX_DATA:            ; transmit data that is passed through the accumulator 
        CLR TI           
        MOV SBUF, A        
        JNB TI, $+0                 ; loop here until data is sent(ti will be set) 
        CLR TI      
        RET
;-------------------------------------------------------------------------
;       Serial isr
;-------------------------------------------------------------------------
SERIAL_ISR:

        JB RI, RX
        RETI

RX:
        MOV TEMP1, A
        MOV A, SBUF
        MOV DIRECTION, A
        SETB DATA_RX
        CLR RI
        MOV A, TEMP1
        RETI

;---------------------------------------
;      timer isr
;---------------------------------------
TIMER_ISR:
        CLR TR0
        MOV TEMP2, R7
        MOV R7, TIMER_COUNT
        MOV TL0, #0fch ; load timer value 
        MOV TH0, #0fh
        DJNZ R7, NOT_ONE_SEC
        SETB ONE_SEC
NOT_ONE_SEC:
        MOV TIMER_COUNT, R7
        MOV R7, TEMP2
        SETB TR0
        RETI 

END

Difference between "docker stop" and "docker kill"

 To stop a running container, you can use either "docker stop" or "docker kill" command to do so. Although it seems doin...