티스토리 뷰

 지난 포스트에서 Arithmetic Instruction이 주어졌을때 data의 flow가 어떻게 흐르는지를 알아보았다. 그런데 중간에 잠깐 언급했던 내용중에는 opcode에 따라서 수행되는 data flow가 천차만별이라는 것이다. 지난번 연산중에 Memory를 다루지 않았는데 이번 포스트에서는 그 Memory를 Access하는 Instruction이 수행됬을 때의 Data flow를 정리해보고자 한다.

우선 그때도 말했다시피 Memory Access에 사용되는 Instruction format은 Immediate-type format(I-type)이다.

instruction내에는 register에 들어갈 값도 포함되지만 정수를 표현할 수 있는 immediate area도 존재한다. 이 값이 instruction 내에서 주소 연산을 할 때 해당 수를 더해서 찾는 과정에 많이 이용된다.  기본적인 흐름은 지난 포스트에서 소개했던 것과 비슷하지만 아무래도 format자체가 바뀌었기 때문에 bus상에서 돌아다니는 signal이 크게 달라질 수 밖에 없다. 일단은 r-type 때 보였던 funct area가 없기 때문에 이 대신 immediate value를 집어넣는 path를 선정해줘야 할 것이다. 그래서 일단 lw(load word) 명령어에 따른 data flow를 보고자 한다.


일단 load의 역할을 짚어보면 Memory에 있는 Data를 register에 불러오는 과정이다 따라서 Memory로부터 받은 정보를 저장할 곳과 어떤 Memory에 저장된 값을 불러올 건지를 결정하는 부분이 정의되어야 할 것이다. 그래서 rs에 해당하는 I[25:21]은 Memory의 주소로써 Read input으로 들어가고 대신 저장될 곳을 나타내는 rt는 Write input으로 들어가야 할 것이다. 그리고 Memory의 정확한 위치를 찾기 위해선 앞에서 설명했던 Immediate value를 구해서 rs와 더한 결과 값을 사용할 것이다. 그런데 유의할것은 immdiate value자체가 16bit이고 실제 주소의 위치는 4byte(32bit)로 표현되어 있기 때문에 16bit을 32bit으로 바꿔주는 과정이 필요하다. 그게 바로 밑에 있는 sign extend 모듈이 하는 것이다. 또한 그렇게 뽑아온 값을 immediate value로 사용하기 위해서는 control signal에 포함된 ALUSrc 값도 1로 세팅해줘야 한다. 이렇게 하고 ALUOp으로 Add를 넣어주면 그 연산의 결과로  ALU의 Output으로 Memory Address가 나오게 된다. 



그럼 이 주소를 바탕으로 해당 값을 찾은 후에 앞에서 구한 target register인 I[20:16]에 넣어줌으로써 lw 명령이 끝나게 된다. 

sw(store word) 명령도 비슷하다. store역할 자체도 Memory에 값을 저장하는 것이기 때문에 위에서 Write Data로 표현된 것이 Read Data로부터 나온 Data를 Memory에 넣어주면 되는 것이다. 

여기서 잠깐 볼 것은 Control Signal에 들어있는 값중에 결과에 영향을 미치지 않는 것들이 발생하는 것이다. 예를 들어서 RegDst나 MemToReg같은 것은 실제로 Destination register를 사용하는 것도 아니고 다시 Register로 써지는 것도 아니기 때문에 사실 아무 값이 들어 있어서 전체 처리구조상 수행되지 않는다. 이런 경우는 보통 don`t care라고도 한다. 


자 그럼 Memory에 직접적으로 관여하는 Instruction인 load와 store의 dataflow를 살펴봤다. 그런데 사실 직접적으로 Memory Access를 하지 않으면서도 I format Instruction을 사용하는 것이 있는데 그게 바로 Branch instruction이다. branch 의 역할은 단어그대로 분기하라는 것이다. 즉 정상적으로 수행되는 instruction이라면 pc counter를 통해서 4를 더한 후에 주소를 찾아가 instruction을 읽어오지만 branch 명령어는 그런식이 아닌 그냥 주소를 지정하고 그 지점으로 이동하라는 것이다. 보통은 conditional branch라고 해서 특정 조건을 만족했을 경우에만 넘어가는 형태를 취하게 된다.  다음은 beq, 즉 값을 비교했을 때 값이 같으면 branch하는 명령어의 data flow이다.


그래서 위와 같이 PC+4의 결과를 사용한 것이 아닌 ALU와의 연산을 통한 address를 활용하게 된다. 이때 PSrc는 ALU로부터 받은 값을 활용하기 위해서 1로 세팅된다. 


역시 I-format으로부터 나온 것이기 때문에 immediate value를 활용하며 역시 extend 시킨 후에 PC와 연산을 하는 용도로 사용한다. 그런데 잘 보면 실제로 주소 연산에 기여하는 것은 imm16에 해당되는 I[15:0]이지 rs와 rt의 역할이 불분명하다. 

 rs와 rt의 역할은 두 값의 비교 용도이다. 물론 R-format이나 SW/LW 같은 형식에서는 직접적으로 Data에 영향을 주는 인자들이었지만 이 branch에서는 단순히 값을 비교하기 위한 용도이다. 지금 예시가 같을 때를 비교하는 것이므로 다르게 말해서는 두값을 뺐을 때 0이 나오는 같다고 나올 것이다. 만약 0 이 아니면 PCSrc 값도 0으로 세팅되면서 해당 Mux도 기존의 PC값을 가져가게 된다. 그래서 ALUOp에는 Sub control signal이 들어간다.

 내가 궁금했던 점은 왜 imm16의 결과에다 shift left 2를 한 결과를 연산하냐는 점이었다. 어디에도 나와있지는 않지만 대략적으로 생각해보면 다음과 같다. 

binary상에서 shift left 2를 하는 효과는 결국 4를 곱하는 효과와 동일하다. 그 말은 imm16에 32bit으로 sign extend한 결과값을 뭔가로 변환시키고 있다는 건데 4를 곱하면 딱 떠오르는게 word(4byte) addressing일 것이다. 즉 immdiate16을 32bit으로 extend한 결과는 byte type이기 때문에 이를 주소와 연산하기 위해서는 byte형으로 바꿀 필요가 있는 것이고 이때문에 4를 곱하는 것이다. 

 이밖에도 instruction format에는 unconditional branch 즉, jmp같은 instruction을 수행하기 위한 Jump-type format 도 존재하는데 이부분은 강의에서도 언급되지 않은 부분이기에 생략한다. 아무튼 두개의 포스트를 통해서 Single Cycle implementation이 어떤식으로 수행되고 data flow가 어떤식으로 진행되는 지를 확인할 수 있었다. 간단히 요약해보면 모든 instruction이 1 cycle안에서 수행되며, 보통 이전 instruction이 수행되고 난 후에 다음 것이 실행될 수 있기 때문에 전체적으로 비효율적이고 느리다. 그대신 위에서도 보다시피 data flow가 매우 간단하며 이에 따른 control signal generator의 설계도 쉬운 편이다. 하지만 전체적으로 빠른 동작을 요구하는 현재 추세에서는 이런 Single Cycle보다는 한 Cycle안에 여러개의 instruction을 수행할 수 있는 Multi Cycle implementation을 추구하는 편이다. 아무튼 그렇다.. 

댓글