关于西门子间接寻址的一些理解
今天不研究高大上的,研究一个接近底层的东西,叫间接寻址
。它很基础,基础到我们无时无刻都在用,但是同时它也很难理解,因为其实寄存器的概念已经被渐渐隐藏了。
1. 地址的概念
我们通常提到的物理输入输出印象区P,印象输入区I,印象输出区Q,位存储区M,定时器T,计数器C,数据区DB,背景数据区DI,本地数据区L。
每个区域(除T/C)都可以用BIT,BYTE,WORD,DWORD来指定它们的大小。
区域+区域位置和长度
,其实构成了我们描述一个地址的必要条件。
- 存储的区域
- 这个区域中具体的位置
1 |
|
所以一个地址的确切构成应该是<存储区符号><存储区尺寸符号><尺寸数值>.<位数值>
。把<存储区符号><存储区尺寸符号>统一看作<地址标志符>,那么地址组成又可以写成**<地址标志符><数值单元>
**。
2. 间接寻址
- 间接寻址对应的是直接寻址,那什么是直接寻址?
直接给出指令的确切操作数就叫直接寻址。
地址的最小单元是BIT。
1 |
|
- 对应的,间接给出的寻址方式。就是间接寻址。
用[ ]标明的内容,间接指代地址
其中MD100和DBW100被称为指针Pointer,它指向它们包含的数值所代表的地址
1
2
3//间接访问地址,间接寻址
A Q[MD100]
A T[DBW100] - 指针格式(存储器间接寻址)
- 存储器间接寻址具有
两个指针格式:单字和双字
。单字指针是一个16bit的结构,从0-15bit,指示一个从0-65535的数值,这个数值就是被寻址的存储区域的编号。双字指针是一个32bit的结构,从0-2bit,共三位,按照8进制指示被寻址的位编号,也就是0-7;而从3-18bit,共16位,指示一个从0-65535的数值,这个数值就是被寻址的字节编号。*这句话说明相比于单字指针,双字指针可以多表达0-7bit的位编号* - 指针可以存放在M、DI、DB和L区域中,也就是说,可以用这些区域的内容来做指针。通过上面发现:双字指针描述byte.bit的这种结构,单字指针只能描述存储区域。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17//
L DW#16#35 //将32位16进制数35存入ACC1
T MD2 //这个值再存入MD2,这是个32位的位存储区域
L +10 //将16位整数10存入ACC1,32位16进制数35自动移动到ACC2
T MW100 //这个值再存入MW100,这是个16位的位存储区域
OPN DBW[MW100] //打开DBW10。这里的[MW100]就是个单字指针,存放指针的区域是M区,MW100中的值10,就是指针间接指定的地址,它是个16位的值!
//
L L#+10 //以32位形式,把10放入ACC1,此时,ACC2中的内容为:16位整数10
T MD104 //这个值再存入MD104,这是个32位的位存储区域
A I[MD104] //对I1.2进行与逻辑操作!
=DIX[MD2] //赋值背景数据位DIX6.5!
//
A DB[MW100].DBX[MD2] //读入DB10.DBX6.5数据位状态
=Q[MD2] //赋值给Q6.5
//
A DB[MW100].DBX[MD2] //读入DB10.DBX6.5数据位状态
=Q10 //错误!!没有Q10这个元件
换句话说,单字指针不能描述P,I,Q,L这些区域,因为描述它们要精确到bit。
对双字指针而言,似乎一切都好,但是也有一个限制,对于非位区域寻址的时候,它的描述必须要保全其0-2bit都是0,也就是说对于非位区域,它的的精度到不了位
也正是由于双字指针是一个具有位的指针,因此,当对字节、字或者双字存储区地址进行寻址时,必须确保双字指针的内容是8或者8的倍数
- 存储器间接寻址具有
上诉例子中有段代码是
1 |
|
那么,为什么是I1.2呢?
1 |
|
- 指针格式(寄存器间接寻址)
存储器间接寻址
和寄存器间接寻址
有什么不一样:
在先前所说的存储器间接寻址中,间接指针用M、DB、DI和L直接指定,就是说,指针指向的存储区内容就是指令要执 行的确切地址数值单元。但在寄存器间接寻址中,指令要执行的确切地址数值单元,并非寄存器指向的存储区内容,也就是说,寄存器本身也是间接的指向真正的地址数值单元。寄存器间接寻址的途径
- 区域内寄存器间接寻址
- 区域间寄存器间接寻址
寄存器间接寻址的格式
<地址标志符><寄存器,P#byte.bit>
1 |
|
- AR的格式
地址寄存器
AR是专门用于寻址的一个特殊指针区域,西门子的地址寄存器一共2个,AR1和AR2,每个32位
。- 区域内寻址寄存器里面,AR的内容只是指代数值单元,因为其他的已经确认,所以这种情况的的AR等同于存储寄存器中的双字指针,也就是0-2指代bit,3-18指代byte字节,其中第31位固定为0。
- 区域间寻址寄存器31位固定为1,24-26bit可以被定义用于指定存储区域,它其实是一种我们常见的区域划分标志(如B#16#84表示DB区的概念就来自于此)。
1 |
|
- 区域标志符(区域间寻址寄存器24-26位)
我们一定不会陌生的知识如下:
- 数据区P,B#16#80(2#000)
- 数据区I,B#16#81(2#001)
- 数据区Q,B#16#82(2#010)
- 数据区M,B#16#83(2#011)
- 数据区DB,B#16#84(2#100)
- 数据区DI,B#16#85(2#101),表示背景DB
- 数据区L,B#16#86(2#111)
当我们把这些AR的内容全部表达出来:
- 数据区P,B#16#800xxxxx
- 数据区I,B#16#810xxxxx
- 数据区Q,B#16#820xxxxx
- 数据区M,B#16#830xxxxx
- 数据区DB,B#16#840xxxxx
- 数据区DI,B#16#850xxxxx
- 数据区L,B#16#860xxxxxx
我们从上面能得到一个初步结论:果AR中的内容是8开头,那么就一定是区域间寻址。
1 |
|
- P#指针是什么
P#中的P是Pointer,是个32位的直接指针。所谓的直接,是指P#中的#后面所跟的数值或者存储单元,是P直接给定的。1
2
3
4
5
6
7
8
L P#Q1.0 //把Q1.0这个指针存入ACC1,此时ACC1的内容=82000008(hex)=Q1.0
L P#1.0 //把1.0这个指针存入ACC1,此时ACC1的内容=00000008(hex)=1.0(这是个区域内寄存器寻址指针,如X[AR1,P#1.5])
L P#MB100 //错误!必须按照byte.bit结构给定指针。
L P#M100.0 //把M100.0这个指针存入ACC1,此时ACC1的内容=83000320(hex)=M100.0
L P#DB100.DBX26.4 //错误!DBX已经提供了存储区域,不能重复指定
L P#DBX26.4 //把DBX26.4这个指针存入ACC1,此时ACC1的内容=840000D4(hex)=DBX26.4
//对P#指定带有存储区域时,累加器中的内容和区域间寻址指针内容完全相同。事实上,把什么样的值传给AR,就决定了是以什么样的方式来进行寄存器间接寻址。
在寄存器寻址中,P#XXX作为寄存器AR指针的偏移量,用来和AR指针进行相加运算,运算的结果,才是指令真正要操作的确切地址数值单元!
P#的运算规则
1
2
3
4//运算的法则是:AR1和P#中的数值,按照BYTE位和BIT位分类相加。BIT位相加按八进制规则运算,而BYTE位相加,则按照十进制规则运算。
对于[AR1,P#2.6],若AR1=26.4 >>>AR1(26.4)+P#(2.6)=29.7,这是区域内寄存器间接寻址的最终确切地址数值单元
对于[AR1,P#2.6],若AR1=DBX26.4 >>>AR1(DBX26.4)+P#(2.6)=DBX29.7,这是区域间寄存器间接寻址的最终确切地址数值单元AR的地址运算
1
2
3
4
5
6
7
8//1.直接赋值,保证直接数是32位,包含相关区域,位置,地址信息
L DW#16#83000320
LAR1
//2.间接赋值,可以用存储器间接寻址指针给定AR1内容。具体内容存储在MD100中
L [MD100]
LAR1
//3.指针赋值,使用P#这个32位“常数”指针赋值AR。
LAR1 P#26.2
关于西门子间接寻址的一些理解
http://example.com/2024/07/21/关于西门子间接寻址的一些理解/