Dear rhoads: Plasma is an excellent project. I am enjoying hacking it. I have understood all the modules of mlite_cpu except mem_control.vhd. Assume the pipeline is two stage. Can it output opcode every clk cycle? Will memory read/write take two cycles? when input pause_in can get its value and what's its function in FSM? Can you give me a description about how a LW instruction works? um, in fact I have got tangled in them for many days, help! Thank you!
Ok, I think my questions make you confused. Let me make it clear.
Question 1: Assume the pipeline is two stages. The first instruction in the ram is LW $1,50($0) and What I want to know is how it works especially in the mem_control part.
I have done some analysis as follow: First, the pc_next module output a pc address(X'00000000). Then the pc address pass to mem_control's address_pc. Because the control output MEM_FETCH at the beginning, address_pc is assigned to address_next which passes to ram and ram retures value data_r. Data_r is the first opcode(LW) and would be in opcode_reg from the next rising clock edge(let's call it the first rising clock edge). The FSM becomes STATE_ADDR.
Then I confused. The FSM becomes STATE_ADDR, which means address_next get value form address_in. Because of this, data_r get the data in address 50. However, you store is the next_opcode_reg! In the next rising cycle edge (the second cycle rising edge), FSM become state_access, in this state, next_opcode_reg would be assigned to opcode_next and opcode_next would be outputted as opcode. But, it the data in address 50, not the second instruction we need.
Where I went wrong?
Question 2: what's the function of pause_in and pause_out in your entire design. I think this is another bottleneck for me to understand your project.
Thank you for your time.
Corrections:
However, you store is the next_opcode_reg! == However, you store it in the next_opcode_reg!
But, it the data in address 50, not the second instruction we need. == But, it is the data in address 50, not the second instruction we need.
sorry for my typing errors.
The section "Bus Interface" on the overview page shows the signals when doing a write. The memory accesses are confusing because of the pipeline. Lets assume that each memory location contains the value of its address plus 0xab000000.
Program: address opcode 00000000 ab000000 //add $1,$2,$3 00000004 ab000004 //lw $1,0x50($0) 00000008 ab000008 //add $2,$3,$4 0000000c ab00000c 00000010 ab000010
cycle stage-1 stage-1 stage0 stage0 stage0 stage1
pc_next address_next address data_r next_opcode opcode
1 00000000 00000000 ???????? ???????? ???????? ????????
2 00000004 00000004 00000000 ab000000 ab000000 ????????
3 00000008 00000008 00000004 ab000004 ab000004 ab000000 //add
4 0000000c 00000050 00000008 ab000008 ab000008 ab000004 //lw
5 0000000c 0000000c 00000050 ab000050 ab000008 ab000004 //paused
6 00000010 00000010 0000000c ab00000c ab00000c ab000008 //add
The address_next signal is valid before the clock rising edge and address is valid after the clock.
Lets follow the "lw" opcode through the different stages. The pc_next is requesting the address in cycle 2. In cycle 3, the SRAM returns the opcode. In cycle 4, the opcode after the "lw" is fetched and stored in next_opcode_reg and the "lw" opcode is executed and the address to fetch is calculated and placed into signal address_next. In cycle 5 the address is used to fetch the data. In cycle 6, the next_opcode_reg is used as the opcode.
The pipeline stages pc_next and opcode were paused between cycles 4 and 5 so that the address and data bus could do the read.
Different blocks can cause a pause_out signal. For example a memory read or write can pause the pipeline. Accessing external memory can cause the pipeline. Reading the result of a multiplication can pause the pipeline.
Did I answer the question?
Thank you! Your explanation is very clear. I have understood most of them.
I added mem_Source mem_State_reg and mem_state next, can you help me check them? Program: address opcode 00000000 ab000000 //add $1,$2,$3 00000004 ab000004 //lw $1,0x50($0) 00000008 ab000008 //add $2,$3,$4 0000000c ab00000c 00000010 ab000010
cycle stage-1 stage-1 stage0 stage0 stage0 stage1 pc_next address_next address data_r next_opcode opcode mem_source mem_state_reg mem_state_next 1 00000000 00000000 ???????? ???????? ???????? ???????? MEM_FETCH STATE_ADDR STATE_ADDR 2 00000004 00000004 00000000 ab000000 ab000000 ???????? MEM_FETCH STATE_ADDR STATE_ADDR 3 00000008 00000008 00000004 ab000004 ab000004 ab000000 MEM_FECTH STATE_ADDR STATE_ADDR //add 4 0000000c 00000050 00000008 ab000008 ab000008 ab000004 MEM_READ32 STATE_ADDR STATE_ACCESS //lw 5 0000000c 0000000c 00000050 ab000050 ab000008 <strong>ab000004</strong> MEM_READ32 STATE_ACCESS STATE_ADDR //paused 6 00000010 00000010 0000000c ab00000c ab00000c ab000008 <strong>??????????</strong> STATE_ADDR ?????????? //add
Questions: 1. In every clk rising edge, opcode_next would be assigned to opcode. So,I think the opcode in cycle 5 should be the value of opcode_next in cycle 4(ab000008). why the opcode didn't change in your table?
In cycle 6, the instruction is add. There is no mem_source assignment in control.vhd. Will the mem_source holds the value MEM_READ32??
If mem_source holds the value MEM_READ32, will add(cycle 6) work in FSM?
Thank you! Your explanation is very clear. I have understood most of them.
I added mem_Source mem_State_reg and mem_state next, can you help me check them? Program: address opcode 00000000 ab000000 //add $1,$2,$3 00000004 ab000004 //lw $1,0x50($0) 00000008 ab000008 //add $2,$3,$4 0000000c ab00000c 00000010 ab000010
cycle stage-1 stage-1 stage0 stage0 stage0 stage1 pc_next address_next address data_r next_opcode opcode mem_source mem_state_reg mem_state_next 1 00000000 00000000 ???????? ???????? ???????? ???????? MEM_FETCH STATE_ADDR STATE_ADDR 2 00000004 00000004 00000000 ab000000 ab000000 ???????? MEM_FETCH STATE_ADDR STATE_ADDR 3 00000008 00000008 00000004 ab000004 ab000004 ab000000 MEM_FECTH STATE_ADDR STATE_ADDR //add 4 0000000c 00000050 00000008 ab000008 ab000008 ab000004 MEM_READ32 STATE_ADDR STATE_ACCESS //lw 5 0000000c 0000000c 00000050 ab000050 ab000008 ab000004 MEM_READ32 STATE_ACCESS STATE_ADDR //paused 6 00000010 00000010 0000000c ab00000c ab00000c ab000008 ?????????? STATE_ADDR ?????????? //add
Questions: 1. In every clk rising edge, opcode_next would be assigned to opcode. So,I think the opcode in cycle 5 should be the value of opcode_next in cycle 4(ab000008). why the opcode didn't change in your table?
In cycle 6, the instruction is add. There is no mem_source assignment in control.vhd. Will the mem_source holds the value MEM_READ32??
If mem_source holds the value MEM_READ32, will add(cycle 6) work in FSM?
I tried to add dashes to keep the columns aligned.
Program: address- opcode 00000000 ab000000 //add $1,$2,$3 00000004 ab000004 //lw $1,0x50($0) 00000008 ab000008 //add $2,$3,$4 0000000c ab00000c 00000010 ab000010
cycle stage-1- stage-1 ---- stage0-- stage0-- stage1----- stage1 ----- pc_next- address_next address- data_r-- next_opcode opcode-- mem_source mem_state_reg mem_state_next ----1 00000000 00000000 --- ???????? ???????? ???????? -- ???????? MEM_FETCH- STATE_ADDR--- STATE_ADDR ----2 00000004 00000004 --- 00000000 ab000000 ???????? -- ???????? MEM_FETCH- STATE_ADDR--- STATE_ADDR ----3 00000008 00000008 --- 00000004 ab000004 ab000000 -- ab000000 MEM_FETCH- STATE_ADDR--- STATE_ADDR //add ----4 0000000c 00000050 --- 00000008 ab000008 ab000004 -- ab000004 MEM_READ32 STATE_ADDR--- STATE_ACCESS //lw ----5 0000000c 0000000c --- 00000050 ab000050 ab000008 -- ab000004 MEM_READ32 STATE_ACCESS- STATE_ADDR //paused ----6 00000010 00000010 --- 0000000c ab00000c ab000008 -- ab000008 MEM_FETCH- STATE_ADDR--- STATE_ADDR //add
Questions: 1. In every clk rising edge, opcode_next would be assigned to opcode. So, I think the opcode in cycle 5 should be the value of opcode_next in cycle 4(ab000008). Why the opcode didn't change in your table?
Answer: I think that I should have shown next_opcode_reg in stage 1 instead of stage 0. This means that normally next_opcode_reg will normally change at the same time that opcode changes and will have the same value. If there is a memory read or write, the next_opcode_reg will be updated but the opcode won't change until after the read or write:
opcode_next := opcode_reg; //nothing changes the signal opcode_next in this case
Answer: Since the opcode doesn't change from cycle 5 to 6, mem_source should stay at MEM_READ32.
Answer: The opcode_next := opcode_next_reg in line 151 should provide the correct opcode.
<o:shapedefaults v:ext="edit" spidmax="2049"/>
</xml><--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1"/>
</o:shapelayout></xml><![endif]-->
Line 73 in control.vhd sets the variable mem_source to MEM_FETCH. If the opcode is a load or store then mem_source is set to something else.
Thank you very much! I understand. The mem_source is a variable instead of a register, so it can't store the value of last time. Thank you!