11. Control and status registers
Control and status registers are registers that are not part of the general-purpose registers x0-x31, but instead have "special" functions. That is, they control something or return the status of something. To read or write them, there are special instructions defined by the "Zicsr" extension.
The RISC-V specification is a bit awkward in the sense that it's a bit arbitrarily split into "unprivileged" and "privileged" volumes. Since we're implementing a very simple processor, we only have a single privilege level. But this doesn't mean that we don't have to consider the privileged architecture!
It's probably best explained in the RISC-V unprivileged architecture:
Unprivileged instructions are those that are generally usable in all privilege modes in all privileged architectures, though behavior might vary depending on privilege mode and privilege architecture.
Another confusing aspect is that for any hardware implementation, the "Zicsr" extension for control and status registers is mandatory. So, the Zicsr extension, which describes the instructions to access CSRs, is described in the unprivileged part of the manuals, while the CSRs themselves are described in the privileged part of the manuals.
The "Zicsr" extension defines 6 instructions:
CSRRW rd, csr, rs(read/write CSR) puts the value of the CSRcsrinto the general-purpose registerrd, and the value of the general-purpose registerrsintocsr.CSRRWIis similar but uses an immediate instead ofrs.CSRRS rd, csr, rs(read and set bits in CSR) puts the value of the CSRcsrinto the general-purpose registerrd, and sets the high bits of the general-purpose registerrsincsr.CSRRSis similar but uses an immediate instead ofrs.CSRRC rd, csr, rs(read and clear bits in CSR) puts the value of the CSRcsrinto the general-purpose registerrd, and clears the high bits of the general-purpose registerrsincsr.CSRRSis similar but uses an immediate instead ofrs.
The RISC-V assembly programmer's manual defines various pseudoinstructions:
CSRR rs, csris an alias forCSRRS rd, csr, x0and can be used to read a CSR.CSRW csr, rsis an alias forCSRRW x0, csr, rsand can be used to write a CSR. Similarly,CSRWI csr, immis an alias forCSRRWI x0, csr, imm.CSRS csr, rsis an alias forCSRRS x0, csr, rsand can be used to set bits in a CSR. Similarly,CSRSI csr, immis an alias forCSRRSI x0, csr, imm.CSRC csr, rsis an alias forCSRRC x0, csr, rsand can be used to clear bits in a CSR. Similarly,CSRCI csr, immis an alias forCSRRCI x0, csr, imm.
There are two kinds of CSRs: read-only CSRs, and read-write CSRs. Obviously, read-only CSRs can only be read. Read-only CSRs have an address with their most significant bits (bits 10 and 11) set to 1.
Trying to write to them will result in an "illegal instruction" exception.
The manual defines three types of fields within read-write CSRs:
- Writes preserve, reads ignore values (WPRI): these fields are reserved for future use and software should ignore the values from these fields. Writes should preserve the value of these fields. For forward compatibility, implementations that do not furnish these fields must make them read-only zero.
- Write legal, read legal values (WLRL): fields of this type should only be written with legal values (what is a legal value should be specified per CSR). Implementations are permitted but not required to raise an illegal-instruction exception if an instruction attempts to write a non-supported value to a WLRL field. Implementations can return arbitrary bit patterns on the read of a WLRL field when the last write was of an illegal value, but the value returned should deterministically depend on the illegal written value and the value of the field prior to the write.
- Write any, read legal values (WARL): Fields of this type allow any value to be written to them, but will always return a legal value when read.
Fields in read-write CSRs can also be read-only, which simply means writes to these fields are ignored (no exception happens). For some reason this doesn't get a fancy acronym (maybe read-only CSRs are considered a special case of WARL CSRs?).
For fields of the last type (WARL), the manual notes the following:
Assuming that writing the CSR has no other side effects, the range of supported values can be determined by attempting to write a desired setting then reading to see if the value was retained.
We need to read the manuals carefully to see which CSRs we need to implement for our minimal implementation. The easiest way to do this is to read chapter 3 of the privileged part of the RISC-V manual. I've gone ahead and did the research for you:
mvendoridmarchidmimpidmhartidmconfigptrmstatusmisamtvecmstatushmscratchmepcmcausemtvalmipmcycleminstretmhpmcounter3..mhpmcounter31mcyclehminstrethmhpmcounter3h..mhpmcounter31hmhpmevent3..mhpmevent31mhpmevent3h..mhpmevent31h
(I give this list as a reference, to find relevant information it's still necessary to search what the manual says about the CSRs.)
So, let's get going. First we add some placeholders in the decoder.
|
@@ -302,6 +302,22 @@ begin
|
|
| 302 |
-- ECALL
|
| 303 |
elsif i_imm = "000000000001" and rs1 = "00000" and funct3 = "000" and rd = "00000" and opcode = "1110011" then
|
| 304 |
-- EBREAK
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 305 |
elsif opcode = "1111111" and funct3 = "000" then
|
| 306 |
-- LED (custom instruction): set the LEDs to the 8 least significant bits of rs1
|
| 307 |
v_decode_output.operation := OP_LED;
|
|
|
|
| 302 |
-- ECALL
|
| 303 |
elsif i_imm = "000000000001" and rs1 = "00000" and funct3 = "000" and rd = "00000" and opcode = "1110011" then
|
| 304 |
-- EBREAK
|
| 305 |
+
elsif opcode = "1110011" then
|
| 306 |
+
if funct3 = "001" then
|
| 307 |
+
-- TODO: CSRRW
|
| 308 |
+
elsif funct3 = "010" then
|
| 309 |
+
-- TODO: CSRRS
|
| 310 |
+
elsif funct3 = "011" then
|
| 311 |
+
-- TODO: CSRRC
|
| 312 |
+
elsif funct3 = "101" then
|
| 313 |
+
-- TODO: CSRRWI
|
| 314 |
+
elsif funct3 = "110" then
|
| 315 |
+
-- TODO: CSRRSI
|
| 316 |
+
elsif funct3 = "111" then
|
| 317 |
+
-- TODO: CSRRCI
|
| 318 |
+
else
|
| 319 |
+
v_decode_output.is_invalid := '1';
|
| 320 |
+
end if;
|
| 321 |
elsif opcode = "1111111" and funct3 = "000" then
|
| 322 |
-- LED (custom instruction): set the LEDs to the 8 least significant bits of rs1
|
| 323 |
v_decode_output.operation := OP_LED;
|
In the decoder we'll set the operation to one of OP_CSRRW, OP_CSRRS, OP_CSRRC. We'll put the value of rs1 (or the immediate value, for the I-variants of the instructions) in the first operand and the address of the CSR register into the second operand.
|
@@ -303,18 +303,33 @@ begin
|
|
| 303 |
elsif i_imm = "000000000001" and rs1 = "00000" and funct3 = "000" and rd = "00000" and opcode = "1110011" then
|
| 304 |
-- EBREAK
|
| 305 |
elsif opcode = "1110011" then
|
|
|
|
|
|
|
|
|
|
| 306 |
if funct3 = "001" then
|
| 307 |
-
--
|
|
|
|
|
|
|
| 308 |
elsif funct3 = "010" then
|
| 309 |
-
--
|
|
|
|
|
|
|
| 310 |
elsif funct3 = "011" then
|
| 311 |
-
--
|
|
|
|
|
|
|
| 312 |
elsif funct3 = "101" then
|
| 313 |
-
--
|
|
|
|
|
|
|
| 314 |
elsif funct3 = "110" then
|
| 315 |
-
--
|
|
|
|
|
|
|
| 316 |
elsif funct3 = "111" then
|
| 317 |
-
--
|
|
|
|
|
|
|
| 318 |
else
|
| 319 |
v_decode_output.is_invalid := '1';
|
| 320 |
end if;
|
|
|
|
| 303 |
elsif i_imm = "000000000001" and rs1 = "00000" and funct3 = "000" and rd = "00000" and opcode = "1110011" then
|
| 304 |
-- EBREAK
|
| 305 |
elsif opcode = "1110011" then
|
| 306 |
+
v_decode_output.operand2 := "00000000000000000000" & i_imm; -- store CSR register in operand 2
|
| 307 |
+
v_decode_output.destination_reg := rd;
|
| 308 |
+
|
| 309 |
if funct3 = "001" then
|
| 310 |
+
-- CSRRW
|
| 311 |
+
v_decode_output.operation := OP_CSRRW;
|
| 312 |
+
v_decode_output.operand1 := reg(to_integer(unsigned(rs1)));
|
| 313 |
elsif funct3 = "010" then
|
| 314 |
+
-- CSRRS
|
| 315 |
+
v_decode_output.operation := OP_CSRRS;
|
| 316 |
+
v_decode_output.operand1 := reg(to_integer(unsigned(rs1)));
|
| 317 |
elsif funct3 = "011" then
|
| 318 |
+
-- CSRRC
|
| 319 |
+
v_decode_output.operation := OP_CSRRC;
|
| 320 |
+
v_decode_output.operand1 := reg(to_integer(unsigned(rs1)));
|
| 321 |
elsif funct3 = "101" then
|
| 322 |
+
-- CSRRWI
|
| 323 |
+
v_decode_output.operation := OP_CSRRW;
|
| 324 |
+
v_decode_output.operand1 := "000000000000000000000000000" & rs1;
|
| 325 |
elsif funct3 = "110" then
|
| 326 |
+
-- CSRRSI
|
| 327 |
+
v_decode_output.operation := OP_CSRRS;
|
| 328 |
+
v_decode_output.operand1 := "000000000000000000000000000" & rs1;
|
| 329 |
elsif funct3 = "111" then
|
| 330 |
+
-- CSRRCI
|
| 331 |
+
v_decode_output.operation := OP_CSRRC;
|
| 332 |
+
v_decode_output.operand1 := "000000000000000000000000000" & rs1;
|
| 333 |
else
|
| 334 |
v_decode_output.is_invalid := '1';
|
| 335 |
end if;
|
|
@@ -29,6 +29,9 @@ package core_types is
|
|
| 29 |
OP_LW,
|
| 30 |
OP_LBU,
|
| 31 |
OP_LHU,
|
|
|
|
|
|
|
|
|
|
| 32 |
OP_LED
|
| 33 |
);
|
| 34 |
|
|
|
|
| 29 |
OP_LW,
|
| 30 |
OP_LBU,
|
| 31 |
OP_LHU,
|
| 32 |
+
OP_CSRRW,
|
| 33 |
+
OP_CSRRS,
|
| 34 |
+
OP_CSRRC,
|
| 35 |
OP_LED
|
| 36 |
);
|
| 37 |
|
We'll also add constants for the mandatory CSRs.
|
@@ -30,4 +30,41 @@ package core_constants is
|
|
| 30 |
mem_size => SIZE_WORD,
|
| 31 |
mem_addr => "00"
|
| 32 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
end package core_constants;
|
|
|
|
| 30 |
mem_size => SIZE_WORD,
|
| 31 |
mem_addr => "00"
|
| 32 |
);
|
| 33 |
+
|
| 34 |
+
-- privileged CSRs
|
| 35 |
+
constant CSR_MVENDORID: std_logic_vector(11 downto 0) := X"F11";
|
| 36 |
+
constant CSR_MARCHID: std_logic_vector(11 downto 0) := X"F12";
|
| 37 |
+
constant CSR_MIMPID: std_logic_vector(11 downto 0) := X"F13";
|
| 38 |
+
constant CSR_MHARTID: std_logic_vector(11 downto 0) := X"F14";
|
| 39 |
+
constant CSR_MCONFIGPTR: std_logic_vector(11 downto 0) := X"F15";
|
| 40 |
+
|
| 41 |
+
constant CSR_MSTATUS: std_logic_vector(11 downto 0) := X"300";
|
| 42 |
+
constant CSR_MISA: std_logic_vector(11 downto 0) := X"301";
|
| 43 |
+
constant CSR_MIE: std_logic_vector(11 downto 0) := X"304";
|
| 44 |
+
constant CSR_MTVEC: std_logic_vector(11 downto 0) := X"305";
|
| 45 |
+
constant CSR_MSTATUSH: std_logic_vector(11 downto 0) := X"310";
|
| 46 |
+
|
| 47 |
+
constant CSR_MSCRATCH: std_logic_vector(11 downto 0) := X"340";
|
| 48 |
+
constant CSR_MEPC: std_logic_vector(11 downto 0) := X"341";
|
| 49 |
+
constant CSR_MCAUSE: std_logic_vector(11 downto 0) := X"342";
|
| 50 |
+
constant CSR_MTVAL: std_logic_vector(11 downto 0) := X"343";
|
| 51 |
+
constant CSR_MIP: std_logic_vector(11 downto 0) := X"344";
|
| 52 |
+
|
| 53 |
+
constant CSR_MCYCLE: std_logic_vector(11 downto 0) := X"B00";
|
| 54 |
+
constant CSR_MINSTRET: std_logic_vector(11 downto 0) := X"B02";
|
| 55 |
+
constant CSR_MHPMCOUNTER3: std_logic_vector(11 downto 0) := X"B03";
|
| 56 |
+
-- ...
|
| 57 |
+
constant CSR_MHPMCOUNTER31: std_logic_vector(11 downto 0) := X"B1F";
|
| 58 |
+
constant CSR_MCYCLEH: std_logic_vector(11 downto 0) := X"B80";
|
| 59 |
+
constant CSR_MINSTRETH: std_logic_vector(11 downto 0) := X"B82";
|
| 60 |
+
constant CSR_MHPMCOUNTER3H: std_logic_vector(11 downto 0) := X"B83";
|
| 61 |
+
-- ...
|
| 62 |
+
constant CSR_MHPMCOUNTER31H: std_logic_vector(11 downto 0) := X"B9F";
|
| 63 |
+
|
| 64 |
+
constant CSR_MHPMEVENT3: std_logic_vector(11 downto 0) := X"323";
|
| 65 |
+
-- ...
|
| 66 |
+
constant CSR_MHPMEVENT31: std_logic_vector(11 downto 0) := X"33f";
|
| 67 |
+
constant CSR_MHPMEVENT3H: std_logic_vector(11 downto 0) := X"723";
|
| 68 |
+
-- ...
|
| 69 |
+
constant CSR_MHPMEVENT31H: std_logic_vector(11 downto 0) := X"73f";
|
| 70 |
end package core_constants;
|
To reduce the amount of duplicated code (and opportunity for bugs) a bit, I chose an implementation where the final value of a CSR is determined as
csr_new_value := (csr_value or set_bits) and clear_bits;
-- somehow make csr_new_value a legal value
csr_value <= csr_new_value
So the 1 bits in set_bits are set, and the 0 bits in clear_bits are cleared.
CSRRW can now be implemented by setting
set_bits := value;
clear_bits := value;
CSRRS as
set_bits := value;
clear_bits := (others => '0');
and CSRRC as
set_bits := (others => '0');
clear_bits := not value;
|
@@ -32,6 +32,8 @@ begin
|
|
| 32 |
variable v_jump_address: std_logic_vector(31 downto 0);
|
| 33 |
variable v_mem_req: mem_req_t;
|
| 34 |
|
|
|
|
|
|
|
| 35 |
begin
|
| 36 |
if rising_edge(clk) then
|
| 37 |
v_output := DEFAULT_EXECUTE_OUTPUT;
|
|
@@ -194,6 +196,21 @@ begin
|
|
| 194 |
else
|
| 195 |
v_output.mem_size := SIZE_WORD;
|
| 196 |
end if;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
elsif input.operation = OP_LED then
|
| 198 |
led <= input.operand1(7 downto 0);
|
| 199 |
else
|
|
|
|
| 32 |
variable v_jump_address: std_logic_vector(31 downto 0);
|
| 33 |
variable v_mem_req: mem_req_t;
|
| 34 |
|
| 35 |
+
variable csr_set_bits, csr_clear_bits: std_logic_vector(31 downto 0);
|
| 36 |
+
|
| 37 |
begin
|
| 38 |
if rising_edge(clk) then
|
| 39 |
v_output := DEFAULT_EXECUTE_OUTPUT;
|
|
|
|
| 196 |
else
|
| 197 |
v_output.mem_size := SIZE_WORD;
|
| 198 |
end if;
|
| 199 |
+
elsif input.operation = OP_CSRRW or input.operation = OP_CSRRS or input.operation = OP_CSRRC then
|
| 200 |
+
if input.operation = OP_CSRRW then
|
| 201 |
+
csr_set_bits := input.operand1;
|
| 202 |
+
csr_clear_bits := input.operand1;
|
| 203 |
+
elsif input.operation = OP_CSRRS then
|
| 204 |
+
csr_set_bits := input.operand1;
|
| 205 |
+
csr_clear_bits := (others => '1');
|
| 206 |
+
elsif input.operation = OP_CSRRC then
|
| 207 |
+
csr_clear_bits := not input.operand1;
|
| 208 |
+
else
|
| 209 |
+
assert false report "Unhandled CSR operation in execute stage" severity failure;
|
| 210 |
+
end if;
|
| 211 |
+
|
| 212 |
+
-- TODO: implementations for different registers
|
| 213 |
+
|
| 214 |
elsif input.operation = OP_LED then
|
| 215 |
led <= input.operand1(7 downto 0);
|
| 216 |
else
|
Now, we are almost ready to start implementing CSRs. But first, a question: What does the RISC-V specification consider a write? The answer is:
- Any
CSRRWoperations CSRRSandCSRRCoperations withrsset tox0CSRRSIandCSRRCIoperations with the immediate value set to 0
This means that CSRRS and CSRRC operations with a non-x0 register holding 0 are still considered writes, even though they don't change the value of the CSR. Annoyingly, this means we need to determine in the decode stage if the operation is a "read-only" operation. In the execute stage, we only have the value, and we need to know where the value came from in order to know if a write is performed (in case we might need to raise an exception).
|
@@ -18,7 +18,8 @@ package core_constants is
|
|
| 18 |
operand1 => (others => '0'),
|
| 19 |
operand2 => (others => '0'),
|
| 20 |
operand3 => (others => '0'),
|
| 21 |
-
destination_reg => (others => '0')
|
|
|
|
| 22 |
);
|
| 23 |
|
| 24 |
constant DEFAULT_EXECUTE_OUTPUT: execute_output_t := (
|
|
|
|
| 18 |
operand1 => (others => '0'),
|
| 19 |
operand2 => (others => '0'),
|
| 20 |
operand3 => (others => '0'),
|
| 21 |
+
destination_reg => (others => '0'),
|
| 22 |
+
csr_read_only => '0'
|
| 23 |
);
|
| 24 |
|
| 25 |
constant DEFAULT_EXECUTE_OUTPUT: execute_output_t := (
|
|
@@ -314,10 +314,16 @@ begin
|
|
| 314 |
-- CSRRS
|
| 315 |
v_decode_output.operation := OP_CSRRS;
|
| 316 |
v_decode_output.operand1 := reg(to_integer(unsigned(rs1)));
|
|
|
|
|
|
|
|
|
|
| 317 |
elsif funct3 = "011" then
|
| 318 |
-- CSRRC
|
| 319 |
v_decode_output.operation := OP_CSRRC;
|
| 320 |
v_decode_output.operand1 := reg(to_integer(unsigned(rs1)));
|
|
|
|
|
|
|
|
|
|
| 321 |
elsif funct3 = "101" then
|
| 322 |
-- CSRRWI
|
| 323 |
v_decode_output.operation := OP_CSRRW;
|
|
@@ -326,10 +332,16 @@ begin
|
|
| 326 |
-- CSRRSI
|
| 327 |
v_decode_output.operation := OP_CSRRS;
|
| 328 |
v_decode_output.operand1 := "000000000000000000000000000" & rs1;
|
|
|
|
|
|
|
|
|
|
| 329 |
elsif funct3 = "111" then
|
| 330 |
-- CSRRCI
|
| 331 |
v_decode_output.operation := OP_CSRRC;
|
| 332 |
v_decode_output.operand1 := "000000000000000000000000000" & rs1;
|
|
|
|
|
|
|
|
|
|
| 333 |
else
|
| 334 |
v_decode_output.is_invalid := '1';
|
| 335 |
end if;
|
|
|
|
| 314 |
-- CSRRS
|
| 315 |
v_decode_output.operation := OP_CSRRS;
|
| 316 |
v_decode_output.operand1 := reg(to_integer(unsigned(rs1)));
|
| 317 |
+
if rs1 = "00000" then
|
| 318 |
+
v_decode_output.csr_read_only := '1';
|
| 319 |
+
end if;
|
| 320 |
elsif funct3 = "011" then
|
| 321 |
-- CSRRC
|
| 322 |
v_decode_output.operation := OP_CSRRC;
|
| 323 |
v_decode_output.operand1 := reg(to_integer(unsigned(rs1)));
|
| 324 |
+
if rs1 = "00000" then
|
| 325 |
+
v_decode_output.csr_read_only := '1';
|
| 326 |
+
end if;
|
| 327 |
elsif funct3 = "101" then
|
| 328 |
-- CSRRWI
|
| 329 |
v_decode_output.operation := OP_CSRRW;
|
|
|
|
| 332 |
-- CSRRSI
|
| 333 |
v_decode_output.operation := OP_CSRRS;
|
| 334 |
v_decode_output.operand1 := "000000000000000000000000000" & rs1;
|
| 335 |
+
if rs1 = "00000" then
|
| 336 |
+
v_decode_output.csr_read_only := '1';
|
| 337 |
+
end if;
|
| 338 |
elsif funct3 = "111" then
|
| 339 |
-- CSRRCI
|
| 340 |
v_decode_output.operation := OP_CSRRC;
|
| 341 |
v_decode_output.operand1 := "000000000000000000000000000" & rs1;
|
| 342 |
+
if rs1 = "00000" then
|
| 343 |
+
v_decode_output.csr_read_only := '1';
|
| 344 |
+
end if;
|
| 345 |
else
|
| 346 |
v_decode_output.is_invalid := '1';
|
| 347 |
end if;
|
|
@@ -49,6 +49,7 @@ package core_types is
|
|
| 49 |
operand2: std_logic_vector(31 downto 0);
|
| 50 |
operand3: std_logic_vector(31 downto 0);
|
| 51 |
destination_reg: std_logic_vector(4 downto 0);
|
|
|
|
| 52 |
end record decode_output_t;
|
| 53 |
|
| 54 |
type read_size_t is (SIZE_WORD, SIZE_HALFWORD, SIZE_BYTE);
|
|
|
|
| 49 |
operand2: std_logic_vector(31 downto 0);
|
| 50 |
operand3: std_logic_vector(31 downto 0);
|
| 51 |
destination_reg: std_logic_vector(4 downto 0);
|
| 52 |
+
csr_read_only: std_logic;
|
| 53 |
end record decode_output_t;
|
| 54 |
|
| 55 |
type read_size_t is (SIZE_WORD, SIZE_HALFWORD, SIZE_BYTE);
|
The mvendorid, marchid, mimpid, mhartid, and mconfigptr CSRs can legally be set to zero. However, I do want to have the ability to easily fill them later, so I will define some constants for them and simply return those.
|
@@ -68,4 +68,11 @@ package core_constants is
|
|
| 68 |
constant CSR_MHPMEVENT3H: std_logic_vector(11 downto 0) := X"723";
|
| 69 |
-- ...
|
| 70 |
constant CSR_MHPMEVENT31H: std_logic_vector(11 downto 0) := X"73f";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
end package core_constants;
|
|
|
|
| 68 |
constant CSR_MHPMEVENT3H: std_logic_vector(11 downto 0) := X"723";
|
| 69 |
-- ...
|
| 70 |
constant CSR_MHPMEVENT31H: std_logic_vector(11 downto 0) := X"73f";
|
| 71 |
+
|
| 72 |
+
-- hardwired values for some CSRs
|
| 73 |
+
constant MVENDORID_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 74 |
+
constant MARCHID_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 75 |
+
constant MIMPID_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 76 |
+
constant MHARTID_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 77 |
+
constant MCONFIGPTR_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 78 |
end package core_constants;
|
|
@@ -209,8 +209,26 @@ begin
|
|
| 209 |
assert false report "Unhandled CSR operation in execute stage" severity failure;
|
| 210 |
end if;
|
| 211 |
|
| 212 |
-
-- TODO: implementations for
|
| 213 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
elsif input.operation = OP_LED then
|
| 215 |
led <= input.operand1(7 downto 0);
|
| 216 |
else
|
|
|
|
| 209 |
assert false report "Unhandled CSR operation in execute stage" severity failure;
|
| 210 |
end if;
|
| 211 |
|
| 212 |
+
-- TODO: implementations for CSR read-write registers
|
| 213 |
+
|
| 214 |
+
if input.csr_read_only = '1' then
|
| 215 |
+
-- read-only CSRs
|
| 216 |
+
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
| 217 |
+
v_output.result := MVENDORID_VALUE;
|
| 218 |
+
elsif input.operand2(11 downto 0) = CSR_MARCHID then
|
| 219 |
+
v_output.result := MARCHID_VALUE;
|
| 220 |
+
elsif input.operand2(11 downto 0) = CSR_MIMPID then
|
| 221 |
+
v_output.result := MIMPID_VALUE;
|
| 222 |
+
elsif input.operand2(11 downto 0) = CSR_MHARTID then
|
| 223 |
+
v_output.result := MHARTID_VALUE;
|
| 224 |
+
elsif input.operand2(11 downto 0) = CSR_MCONFIGPTR then
|
| 225 |
+
v_output.result := MCONFIGPTR_VALUE;
|
| 226 |
+
else
|
| 227 |
+
-- TODO: exception; trying to read non-existent CSR
|
| 228 |
+
end if;
|
| 229 |
+
else
|
| 230 |
+
-- TODO: exception; trying to write to non-existent or read-only CSR
|
| 231 |
+
end if;
|
| 232 |
elsif input.operation = OP_LED then
|
| 233 |
led <= input.operand1(7 downto 0);
|
| 234 |
else
|
Now, on to mstatus. This is a complicated CSR, but for a minimal implementation we only need the mie and mpie bits as read-write; most other bits/fields can be read-only zero. The only exception is mpp, which holds the previous privilige mode. Since our implementation only has the "machine" privilege mode, which corresponds to 11, so we hardcode mpp to 11.
|
@@ -23,6 +23,7 @@ end execute;
|
|
| 23 |
|
| 24 |
|
| 25 |
architecture rtl of execute is
|
|
|
|
| 26 |
begin
|
| 27 |
|
| 28 |
process (clk)
|
|
@@ -211,7 +212,11 @@ begin
|
|
| 211 |
|
| 212 |
-- TODO: implementations for CSR read-write registers
|
| 213 |
|
| 214 |
-
if input.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 215 |
-- read-only CSRs
|
| 216 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
| 217 |
v_output.result := MVENDORID_VALUE;
|
|
|
|
| 23 |
|
| 24 |
|
| 25 |
architecture rtl of execute is
|
| 26 |
+
signal mstatus_mpie, mstatus_mie: std_logic := '0';
|
| 27 |
begin
|
| 28 |
|
| 29 |
process (clk)
|
|
|
|
| 212 |
|
| 213 |
-- TODO: implementations for CSR read-write registers
|
| 214 |
|
| 215 |
+
if input.operand2(11 downto 0) = CSR_MSTATUS then
|
| 216 |
+
v_output.result := "000000000000000000011000" & mstatus_mpie & "000" & mstatus_mie & "000";
|
| 217 |
+
mstatus_mie <= (mstatus_mie or csr_set_bits(3)) and csr_clear_bits(3);
|
| 218 |
+
mstatus_mpie <= (mstatus_mpie or csr_set_bits(7)) and csr_clear_bits(7);
|
| 219 |
+
elsif input.csr_read_only = '1' then
|
| 220 |
-- read-only CSRs
|
| 221 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
| 222 |
v_output.result := MVENDORID_VALUE;
|
On to misa. This CSR indicates what the bit width of the ISA is (32 or 64), and which extensions are active. It is a WARL CSR, meaning writes are allowed, but only legal values are returned on reading. The idea behind is that you can enable extensions by writing a one to the bit in misa that corresponds to that extension. If the bit stays zero, this means the implementation does not support the extension.
We are not implementing any extensions. For the RV32I subset, we return x40000100 (the encoding is explained in the manual in the section for the misa CSR). I load this value from a constant so that we can easily change it if we do implement more extensions later.
|
@@ -75,4 +75,6 @@ package core_constants is
|
|
| 75 |
constant MIMPID_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 76 |
constant MHARTID_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 77 |
constant MCONFIGPTR_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
|
|
|
|
|
|
| 78 |
end package core_constants;
|
|
|
|
| 75 |
constant MIMPID_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 76 |
constant MHARTID_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 77 |
constant MCONFIGPTR_VALUE: std_logic_vector(31 downto 0) := X"00000000";
|
| 78 |
+
|
| 79 |
+
constant MISA_VALUE: std_logic_vector(31 downto 0) := X"40000100"; -- 32-bit RVI
|
| 80 |
end package core_constants;
|
|
@@ -216,6 +216,8 @@ begin
|
|
| 216 |
v_output.result := "000000000000000000011000" & mstatus_mpie & "000" & mstatus_mie & "000";
|
| 217 |
mstatus_mie <= (mstatus_mie or csr_set_bits(3)) and csr_clear_bits(3);
|
| 218 |
mstatus_mpie <= (mstatus_mpie or csr_set_bits(7)) and csr_clear_bits(7);
|
|
|
|
|
|
|
| 219 |
elsif input.csr_read_only = '1' then
|
| 220 |
-- read-only CSRs
|
| 221 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 216 |
v_output.result := "000000000000000000011000" & mstatus_mpie & "000" & mstatus_mie & "000";
|
| 217 |
mstatus_mie <= (mstatus_mie or csr_set_bits(3)) and csr_clear_bits(3);
|
| 218 |
mstatus_mpie <= (mstatus_mpie or csr_set_bits(7)) and csr_clear_bits(7);
|
| 219 |
+
elsif input.operand2(11 downto 0) = CSR_MISA then
|
| 220 |
+
v_output.result := MISA_VALUE;
|
| 221 |
elsif input.csr_read_only = '1' then
|
| 222 |
-- read-only CSRs
|
| 223 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mie CSR contains "interrupt enable" bits for all the interrupts. There are 16 interrupts mandated by RISC-V, spanning the lower 16 bits of mie. The rest of them are custom and for now I make them read-only zeros.
(Note that we don't implement the functionality of any CSRs yet, just the reading and writing of them.)
|
@@ -24,6 +24,7 @@ end execute;
|
|
| 24 |
|
| 25 |
architecture rtl of execute is
|
| 26 |
signal mstatus_mpie, mstatus_mie: std_logic := '0';
|
|
|
|
| 27 |
begin
|
| 28 |
|
| 29 |
process (clk)
|
|
@@ -218,6 +219,9 @@ begin
|
|
| 218 |
mstatus_mpie <= (mstatus_mpie or csr_set_bits(7)) and csr_clear_bits(7);
|
| 219 |
elsif input.operand2(11 downto 0) = CSR_MISA then
|
| 220 |
v_output.result := MISA_VALUE;
|
|
|
|
|
|
|
|
|
|
| 221 |
elsif input.csr_read_only = '1' then
|
| 222 |
-- read-only CSRs
|
| 223 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 24 |
|
| 25 |
architecture rtl of execute is
|
| 26 |
signal mstatus_mpie, mstatus_mie: std_logic := '0';
|
| 27 |
+
signal mie: std_logic_vector(15 downto 0) := (others => '0');
|
| 28 |
begin
|
| 29 |
|
| 30 |
process (clk)
|
|
|
|
| 219 |
mstatus_mpie <= (mstatus_mpie or csr_set_bits(7)) and csr_clear_bits(7);
|
| 220 |
elsif input.operand2(11 downto 0) = CSR_MISA then
|
| 221 |
v_output.result := MISA_VALUE;
|
| 222 |
+
elsif input.operand2(11 downto 0) = CSR_MIE then
|
| 223 |
+
v_output.result := x"0000" & mie;
|
| 224 |
+
mie <= (mie or csr_set_bits(15 downto 0)) and csr_clear_bits(15 downto 0);
|
| 225 |
elsif input.csr_read_only = '1' then
|
| 226 |
-- read-only CSRs
|
| 227 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mtvec CSR has to do with the address of the interrupts handler. The lower two bits define a "mode"; only 00 and 01 are allowed.
|
@@ -25,6 +25,8 @@ end execute;
|
|
| 25 |
architecture rtl of execute is
|
| 26 |
signal mstatus_mpie, mstatus_mie: std_logic := '0';
|
| 27 |
signal mie: std_logic_vector(15 downto 0) := (others => '0');
|
|
|
|
|
|
|
| 28 |
begin
|
| 29 |
|
| 30 |
process (clk)
|
|
@@ -222,6 +224,10 @@ begin
|
|
| 222 |
elsif input.operand2(11 downto 0) = CSR_MIE then
|
| 223 |
v_output.result := x"0000" & mie;
|
| 224 |
mie <= (mie or csr_set_bits(15 downto 0)) and csr_clear_bits(15 downto 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
elsif input.csr_read_only = '1' then
|
| 226 |
-- read-only CSRs
|
| 227 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 25 |
architecture rtl of execute is
|
| 26 |
signal mstatus_mpie, mstatus_mie: std_logic := '0';
|
| 27 |
signal mie: std_logic_vector(15 downto 0) := (others => '0');
|
| 28 |
+
signal mtvec_address: std_logic_vector(29 downto 0) := (others => '0');
|
| 29 |
+
signal mtvec_mode: std_logic := '0';
|
| 30 |
begin
|
| 31 |
|
| 32 |
process (clk)
|
|
|
|
| 224 |
elsif input.operand2(11 downto 0) = CSR_MIE then
|
| 225 |
v_output.result := x"0000" & mie;
|
| 226 |
mie <= (mie or csr_set_bits(15 downto 0)) and csr_clear_bits(15 downto 0);
|
| 227 |
+
elsif input.operand2(11 downto 0) = CSR_MTVEC then
|
| 228 |
+
v_output.result := mtvec_address & "0" & mtvec_mode;
|
| 229 |
+
mtvec_address <= (mtvec_address or csr_set_bits(31 downto 2)) and csr_clear_bits(31 downto 2);
|
| 230 |
+
mtvec_mode <= (mtvec_mode or csr_set_bits(0)) and csr_clear_bits(0);
|
| 231 |
elsif input.csr_read_only = '1' then
|
| 232 |
-- read-only CSRs
|
| 233 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
For our implementation, the mstatush register can be read-only zero.
|
@@ -228,6 +228,8 @@ begin
|
|
| 228 |
v_output.result := mtvec_address & "0" & mtvec_mode;
|
| 229 |
mtvec_address <= (mtvec_address or csr_set_bits(31 downto 2)) and csr_clear_bits(31 downto 2);
|
| 230 |
mtvec_mode <= (mtvec_mode or csr_set_bits(0)) and csr_clear_bits(0);
|
|
|
|
|
|
|
| 231 |
elsif input.csr_read_only = '1' then
|
| 232 |
-- read-only CSRs
|
| 233 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 228 |
v_output.result := mtvec_address & "0" & mtvec_mode;
|
| 229 |
mtvec_address <= (mtvec_address or csr_set_bits(31 downto 2)) and csr_clear_bits(31 downto 2);
|
| 230 |
mtvec_mode <= (mtvec_mode or csr_set_bits(0)) and csr_clear_bits(0);
|
| 231 |
+
elsif input.operand2(11 downto 0) = CSR_MSTATUSH then
|
| 232 |
+
v_output.result := (others => '0');
|
| 233 |
elsif input.csr_read_only = '1' then
|
| 234 |
-- read-only CSRs
|
| 235 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mscratch CSR is a read-write scratch CSR that can be used for anything.
|
@@ -27,6 +27,7 @@ architecture rtl of execute is
|
|
| 27 |
signal mie: std_logic_vector(15 downto 0) := (others => '0');
|
| 28 |
signal mtvec_address: std_logic_vector(29 downto 0) := (others => '0');
|
| 29 |
signal mtvec_mode: std_logic := '0';
|
|
|
|
| 30 |
begin
|
| 31 |
|
| 32 |
process (clk)
|
|
@@ -230,6 +231,9 @@ begin
|
|
| 230 |
mtvec_mode <= (mtvec_mode or csr_set_bits(0)) and csr_clear_bits(0);
|
| 231 |
elsif input.operand2(11 downto 0) = CSR_MSTATUSH then
|
| 232 |
v_output.result := (others => '0');
|
|
|
|
|
|
|
|
|
|
| 233 |
elsif input.csr_read_only = '1' then
|
| 234 |
-- read-only CSRs
|
| 235 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 27 |
signal mie: std_logic_vector(15 downto 0) := (others => '0');
|
| 28 |
signal mtvec_address: std_logic_vector(29 downto 0) := (others => '0');
|
| 29 |
signal mtvec_mode: std_logic := '0';
|
| 30 |
+
signal mscratch: std_logic_vector(31 downto 0) := (others => '0');
|
| 31 |
begin
|
| 32 |
|
| 33 |
process (clk)
|
|
|
|
| 231 |
mtvec_mode <= (mtvec_mode or csr_set_bits(0)) and csr_clear_bits(0);
|
| 232 |
elsif input.operand2(11 downto 0) = CSR_MSTATUSH then
|
| 233 |
v_output.result := (others => '0');
|
| 234 |
+
elsif input.operand2(11 downto 0) = CSR_MSCRATCH then
|
| 235 |
+
v_output.result := mscratch;
|
| 236 |
+
mscratch <= (mscratch or csr_set_bits) and csr_clear_bits;
|
| 237 |
elsif input.csr_read_only = '1' then
|
| 238 |
-- read-only CSRs
|
| 239 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mepc CSR holds the address of an instruction that was being executed when a trap (exception or interrupt) occurred. Again, we don't implement that functionality now, only the reading and writing.
|
@@ -28,6 +28,7 @@ architecture rtl of execute is
|
|
| 28 |
signal mtvec_address: std_logic_vector(29 downto 0) := (others => '0');
|
| 29 |
signal mtvec_mode: std_logic := '0';
|
| 30 |
signal mscratch: std_logic_vector(31 downto 0) := (others => '0');
|
|
|
|
| 31 |
begin
|
| 32 |
|
| 33 |
process (clk)
|
|
@@ -234,6 +235,9 @@ begin
|
|
| 234 |
elsif input.operand2(11 downto 0) = CSR_MSCRATCH then
|
| 235 |
v_output.result := mscratch;
|
| 236 |
mscratch <= (mscratch or csr_set_bits) and csr_clear_bits;
|
|
|
|
|
|
|
|
|
|
| 237 |
elsif input.csr_read_only = '1' then
|
| 238 |
-- read-only CSRs
|
| 239 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 28 |
signal mtvec_address: std_logic_vector(29 downto 0) := (others => '0');
|
| 29 |
signal mtvec_mode: std_logic := '0';
|
| 30 |
signal mscratch: std_logic_vector(31 downto 0) := (others => '0');
|
| 31 |
+
signal mepc: std_logic_vector(29 downto 0) := (others => '0');
|
| 32 |
begin
|
| 33 |
|
| 34 |
process (clk)
|
|
|
|
| 235 |
elsif input.operand2(11 downto 0) = CSR_MSCRATCH then
|
| 236 |
v_output.result := mscratch;
|
| 237 |
mscratch <= (mscratch or csr_set_bits) and csr_clear_bits;
|
| 238 |
+
elsif input.operand2(11 downto 0) = CSR_MEPC then
|
| 239 |
+
v_output.result := mepc & "00";
|
| 240 |
+
mepc <= (mepc or csr_set_bits(31 downto 2)) and csr_clear_bits(31 downto 2);
|
| 241 |
elsif input.csr_read_only = '1' then
|
| 242 |
-- read-only CSRs
|
| 243 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mcause CSR is written when a trap happens and holds a code indicating the cause of the trap. The MSB holds a bit that indicates if the trap was an interrupt. Codes up to 64 are defined, so I just use 6 bits for the code.
|
@@ -29,6 +29,8 @@ architecture rtl of execute is
|
|
| 29 |
signal mtvec_mode: std_logic := '0';
|
| 30 |
signal mscratch: std_logic_vector(31 downto 0) := (others => '0');
|
| 31 |
signal mepc: std_logic_vector(29 downto 0) := (others => '0');
|
|
|
|
|
|
|
| 32 |
begin
|
| 33 |
|
| 34 |
process (clk)
|
|
@@ -238,6 +240,10 @@ begin
|
|
| 238 |
elsif input.operand2(11 downto 0) = CSR_MEPC then
|
| 239 |
v_output.result := mepc & "00";
|
| 240 |
mepc <= (mepc or csr_set_bits(31 downto 2)) and csr_clear_bits(31 downto 2);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
elsif input.csr_read_only = '1' then
|
| 242 |
-- read-only CSRs
|
| 243 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 29 |
signal mtvec_mode: std_logic := '0';
|
| 30 |
signal mscratch: std_logic_vector(31 downto 0) := (others => '0');
|
| 31 |
signal mepc: std_logic_vector(29 downto 0) := (others => '0');
|
| 32 |
+
signal mcause_int: std_logic := '0';
|
| 33 |
+
signal mcause_code: std_logic_vector(5 downto 0) := (others => '0');
|
| 34 |
begin
|
| 35 |
|
| 36 |
process (clk)
|
|
|
|
| 240 |
elsif input.operand2(11 downto 0) = CSR_MEPC then
|
| 241 |
v_output.result := mepc & "00";
|
| 242 |
mepc <= (mepc or csr_set_bits(31 downto 2)) and csr_clear_bits(31 downto 2);
|
| 243 |
+
elsif input.operand2(11 downto 0) = CSR_MCAUSE then
|
| 244 |
+
v_output.result := mcause_int & "0000000000000000000000000" & mcause_code;
|
| 245 |
+
mcause_int <= (mcause_int or csr_set_bits(31)) and csr_clear_bits(31);
|
| 246 |
+
mcause_code <= (mcause_code or csr_set_bits(5 downto 0)) and csr_clear_bits(5 downto 0);
|
| 247 |
elsif input.csr_read_only = '1' then
|
| 248 |
-- read-only CSRs
|
| 249 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mtval CSR is written when a trap happens and contains extra information about the trap, when applicable. What exactly is in mtval is dependent on the trap. For example, for illegal memory accesses, mtval holds the address of the memory for which an access was attempted.
|
@@ -31,6 +31,7 @@ architecture rtl of execute is
|
|
| 31 |
signal mepc: std_logic_vector(29 downto 0) := (others => '0');
|
| 32 |
signal mcause_int: std_logic := '0';
|
| 33 |
signal mcause_code: std_logic_vector(5 downto 0) := (others => '0');
|
|
|
|
| 34 |
begin
|
| 35 |
|
| 36 |
process (clk)
|
|
@@ -244,6 +245,9 @@ begin
|
|
| 244 |
v_output.result := mcause_int & "0000000000000000000000000" & mcause_code;
|
| 245 |
mcause_int <= (mcause_int or csr_set_bits(31)) and csr_clear_bits(31);
|
| 246 |
mcause_code <= (mcause_code or csr_set_bits(5 downto 0)) and csr_clear_bits(5 downto 0);
|
|
|
|
|
|
|
|
|
|
| 247 |
elsif input.csr_read_only = '1' then
|
| 248 |
-- read-only CSRs
|
| 249 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 31 |
signal mepc: std_logic_vector(29 downto 0) := (others => '0');
|
| 32 |
signal mcause_int: std_logic := '0';
|
| 33 |
signal mcause_code: std_logic_vector(5 downto 0) := (others => '0');
|
| 34 |
+
signal mtval: std_logic_vector(31 downto 0) := (others => '0');
|
| 35 |
begin
|
| 36 |
|
| 37 |
process (clk)
|
|
|
|
| 245 |
v_output.result := mcause_int & "0000000000000000000000000" & mcause_code;
|
| 246 |
mcause_int <= (mcause_int or csr_set_bits(31)) and csr_clear_bits(31);
|
| 247 |
mcause_code <= (mcause_code or csr_set_bits(5 downto 0)) and csr_clear_bits(5 downto 0);
|
| 248 |
+
elsif input.operand2(11 downto 0) = CSR_MTVAL then
|
| 249 |
+
v_output.result := mtval;
|
| 250 |
+
mtval <= (mtval or csr_set_bits) and csr_clear_bits;
|
| 251 |
elsif input.csr_read_only = '1' then
|
| 252 |
-- read-only CSRs
|
| 253 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mip CSR is a lot like mie, but holds pending bits to indicate that interrupts are pending.
|
@@ -32,6 +32,7 @@ architecture rtl of execute is
|
|
| 32 |
signal mcause_int: std_logic := '0';
|
| 33 |
signal mcause_code: std_logic_vector(5 downto 0) := (others => '0');
|
| 34 |
signal mtval: std_logic_vector(31 downto 0) := (others => '0');
|
|
|
|
| 35 |
begin
|
| 36 |
|
| 37 |
process (clk)
|
|
@@ -248,6 +249,9 @@ begin
|
|
| 248 |
elsif input.operand2(11 downto 0) = CSR_MTVAL then
|
| 249 |
v_output.result := mtval;
|
| 250 |
mtval <= (mtval or csr_set_bits) and csr_clear_bits;
|
|
|
|
|
|
|
|
|
|
| 251 |
elsif input.csr_read_only = '1' then
|
| 252 |
-- read-only CSRs
|
| 253 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 32 |
signal mcause_int: std_logic := '0';
|
| 33 |
signal mcause_code: std_logic_vector(5 downto 0) := (others => '0');
|
| 34 |
signal mtval: std_logic_vector(31 downto 0) := (others => '0');
|
| 35 |
+
signal mip: std_logic_vector(15 downto 0) := (others => '0');
|
| 36 |
begin
|
| 37 |
|
| 38 |
process (clk)
|
|
|
|
| 249 |
elsif input.operand2(11 downto 0) = CSR_MTVAL then
|
| 250 |
v_output.result := mtval;
|
| 251 |
mtval <= (mtval or csr_set_bits) and csr_clear_bits;
|
| 252 |
+
elsif input.operand2(11 downto 0) = CSR_MIP then
|
| 253 |
+
v_output.result := x"0000" & mip;
|
| 254 |
+
mip <= (mip or csr_set_bits(15 downto 0)) and csr_clear_bits(15 downto 0);
|
| 255 |
elsif input.csr_read_only = '1' then
|
| 256 |
-- read-only CSRs
|
| 257 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mcycle CSR holds the number of cycles that the processor went through. The RISC-V specification implies you can also write to it (although it does a really poor job of actually specifying what should happen).
|
@@ -33,6 +33,7 @@ architecture rtl of execute is
|
|
| 33 |
signal mcause_code: std_logic_vector(5 downto 0) := (others => '0');
|
| 34 |
signal mtval: std_logic_vector(31 downto 0) := (others => '0');
|
| 35 |
signal mip: std_logic_vector(15 downto 0) := (others => '0');
|
|
|
|
| 36 |
begin
|
| 37 |
|
| 38 |
process (clk)
|
|
@@ -252,6 +253,9 @@ begin
|
|
| 252 |
elsif input.operand2(11 downto 0) = CSR_MIP then
|
| 253 |
v_output.result := x"0000" & mip;
|
| 254 |
mip <= (mip or csr_set_bits(15 downto 0)) and csr_clear_bits(15 downto 0);
|
|
|
|
|
|
|
|
|
|
| 255 |
elsif input.csr_read_only = '1' then
|
| 256 |
-- read-only CSRs
|
| 257 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 33 |
signal mcause_code: std_logic_vector(5 downto 0) := (others => '0');
|
| 34 |
signal mtval: std_logic_vector(31 downto 0) := (others => '0');
|
| 35 |
signal mip: std_logic_vector(15 downto 0) := (others => '0');
|
| 36 |
+
signal mcycle: std_logic_vector(31 downto 0) := (others => '0');
|
| 37 |
begin
|
| 38 |
|
| 39 |
process (clk)
|
|
|
|
| 253 |
elsif input.operand2(11 downto 0) = CSR_MIP then
|
| 254 |
v_output.result := x"0000" & mip;
|
| 255 |
mip <= (mip or csr_set_bits(15 downto 0)) and csr_clear_bits(15 downto 0);
|
| 256 |
+
elsif input.operand2(11 downto 0) = CSR_MCYCLE then
|
| 257 |
+
v_output.result := mcycle;
|
| 258 |
+
mcycle <= (mcycle or csr_set_bits) and csr_clear_bits;
|
| 259 |
elsif input.csr_read_only = '1' then
|
| 260 |
-- read-only CSRs
|
| 261 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The minstret CSR is very similar but counts retired instructions.
|
@@ -34,6 +34,7 @@ architecture rtl of execute is
|
|
| 34 |
signal mtval: std_logic_vector(31 downto 0) := (others => '0');
|
| 35 |
signal mip: std_logic_vector(15 downto 0) := (others => '0');
|
| 36 |
signal mcycle: std_logic_vector(31 downto 0) := (others => '0');
|
|
|
|
| 37 |
begin
|
| 38 |
|
| 39 |
process (clk)
|
|
@@ -256,6 +257,9 @@ begin
|
|
| 256 |
elsif input.operand2(11 downto 0) = CSR_MCYCLE then
|
| 257 |
v_output.result := mcycle;
|
| 258 |
mcycle <= (mcycle or csr_set_bits) and csr_clear_bits;
|
|
|
|
|
|
|
|
|
|
| 259 |
elsif input.csr_read_only = '1' then
|
| 260 |
-- read-only CSRs
|
| 261 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 34 |
signal mtval: std_logic_vector(31 downto 0) := (others => '0');
|
| 35 |
signal mip: std_logic_vector(15 downto 0) := (others => '0');
|
| 36 |
signal mcycle: std_logic_vector(31 downto 0) := (others => '0');
|
| 37 |
+
signal minstret: std_logic_vector(31 downto 0) := (others => '0');
|
| 38 |
begin
|
| 39 |
|
| 40 |
process (clk)
|
|
|
|
| 257 |
elsif input.operand2(11 downto 0) = CSR_MCYCLE then
|
| 258 |
v_output.result := mcycle;
|
| 259 |
mcycle <= (mcycle or csr_set_bits) and csr_clear_bits;
|
| 260 |
+
elsif input.operand2(11 downto 0) = CSR_MINSTRET then
|
| 261 |
+
v_output.result := minstret;
|
| 262 |
+
minstret <= (minstret or csr_set_bits) and csr_clear_bits;
|
| 263 |
elsif input.csr_read_only = '1' then
|
| 264 |
-- read-only CSRs
|
| 265 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
There are 29 counters, mhpmcounter3 up to mhpmcounter31, which are mandatory to implement, but it's legal to implement them as read-only zero.
|
@@ -260,6 +260,8 @@ begin
|
|
| 260 |
elsif input.operand2(11 downto 0) = CSR_MINSTRET then
|
| 261 |
v_output.result := minstret;
|
| 262 |
minstret <= (minstret or csr_set_bits) and csr_clear_bits;
|
|
|
|
|
|
|
| 263 |
elsif input.csr_read_only = '1' then
|
| 264 |
-- read-only CSRs
|
| 265 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 260 |
elsif input.operand2(11 downto 0) = CSR_MINSTRET then
|
| 261 |
v_output.result := minstret;
|
| 262 |
minstret <= (minstret or csr_set_bits) and csr_clear_bits;
|
| 263 |
+
elsif unsigned(CSR_MHPMCOUNTER3) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31) then
|
| 264 |
+
v_output.result := (others => '0');
|
| 265 |
elsif input.csr_read_only = '1' then
|
| 266 |
-- read-only CSRs
|
| 267 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mcycleh and minstreth CSRs are like the mcycle and minstret CSRs but hold the upper 32 bits.
|
@@ -35,6 +35,8 @@ architecture rtl of execute is
|
|
| 35 |
signal mip: std_logic_vector(15 downto 0) := (others => '0');
|
| 36 |
signal mcycle: std_logic_vector(31 downto 0) := (others => '0');
|
| 37 |
signal minstret: std_logic_vector(31 downto 0) := (others => '0');
|
|
|
|
|
|
|
| 38 |
begin
|
| 39 |
|
| 40 |
process (clk)
|
|
@@ -262,6 +264,12 @@ begin
|
|
| 262 |
minstret <= (minstret or csr_set_bits) and csr_clear_bits;
|
| 263 |
elsif unsigned(CSR_MHPMCOUNTER3) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31) then
|
| 264 |
v_output.result := (others => '0');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 265 |
elsif input.csr_read_only = '1' then
|
| 266 |
-- read-only CSRs
|
| 267 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 35 |
signal mip: std_logic_vector(15 downto 0) := (others => '0');
|
| 36 |
signal mcycle: std_logic_vector(31 downto 0) := (others => '0');
|
| 37 |
signal minstret: std_logic_vector(31 downto 0) := (others => '0');
|
| 38 |
+
signal mcycleh: std_logic_vector(31 downto 0) := (others => '0');
|
| 39 |
+
signal minstreth: std_logic_vector(31 downto 0) := (others => '0');
|
| 40 |
begin
|
| 41 |
|
| 42 |
process (clk)
|
|
|
|
| 264 |
minstret <= (minstret or csr_set_bits) and csr_clear_bits;
|
| 265 |
elsif unsigned(CSR_MHPMCOUNTER3) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31) then
|
| 266 |
v_output.result := (others => '0');
|
| 267 |
+
elsif input.operand2(11 downto 0) = CSR_MCYCLEH then
|
| 268 |
+
v_output.result := mcycleh;
|
| 269 |
+
mcycleh <= (mcycleh or csr_set_bits) and csr_clear_bits;
|
| 270 |
+
elsif input.operand2(11 downto 0) = CSR_MINSTRETH then
|
| 271 |
+
v_output.result := minstreth;
|
| 272 |
+
minstreth <= (minstreth or csr_set_bits) and csr_clear_bits;
|
| 273 |
elsif input.csr_read_only = '1' then
|
| 274 |
-- read-only CSRs
|
| 275 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
The mphmcounters also have variants that hold the higher bits.
|
@@ -270,6 +270,8 @@ begin
|
|
| 270 |
elsif input.operand2(11 downto 0) = CSR_MINSTRETH then
|
| 271 |
v_output.result := minstreth;
|
| 272 |
minstreth <= (minstreth or csr_set_bits) and csr_clear_bits;
|
|
|
|
|
|
|
| 273 |
elsif input.csr_read_only = '1' then
|
| 274 |
-- read-only CSRs
|
| 275 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 270 |
elsif input.operand2(11 downto 0) = CSR_MINSTRETH then
|
| 271 |
v_output.result := minstreth;
|
| 272 |
minstreth <= (minstreth or csr_set_bits) and csr_clear_bits;
|
| 273 |
+
elsif unsigned(CSR_MHPMCOUNTER3H) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31H) then
|
| 274 |
+
v_output.result := (others => '0');
|
| 275 |
elsif input.csr_read_only = '1' then
|
| 276 |
-- read-only CSRs
|
| 277 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
Finally, we have mhpmevent and mhpmeventh counters, which can be read-only zero.
|
@@ -272,6 +272,10 @@ begin
|
|
| 272 |
minstreth <= (minstreth or csr_set_bits) and csr_clear_bits;
|
| 273 |
elsif unsigned(CSR_MHPMCOUNTER3H) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31H) then
|
| 274 |
v_output.result := (others => '0');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 275 |
elsif input.csr_read_only = '1' then
|
| 276 |
-- read-only CSRs
|
| 277 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
|
|
|
| 272 |
minstreth <= (minstreth or csr_set_bits) and csr_clear_bits;
|
| 273 |
elsif unsigned(CSR_MHPMCOUNTER3H) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31H) then
|
| 274 |
v_output.result := (others => '0');
|
| 275 |
+
elsif unsigned(CSR_MHPMEVENT3) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMEVENT31) then
|
| 276 |
+
v_output.result := (others => '0');
|
| 277 |
+
elsif unsigned(CSR_MHPMEVENT3H) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMEVENT31H) then
|
| 278 |
+
v_output.result := (others => '0');
|
| 279 |
elsif input.csr_read_only = '1' then
|
| 280 |
-- read-only CSRs
|
| 281 |
if input.operand2(11 downto 0) = CSR_MVENDORID then
|
Now, we have defined most CSRs that need to exist. Most of them are either read-only registers, or have to do with interrupts, and we'll look at them later. Exceptions are mcycle (and mcycleh) and minstret (and minstreth). These are incrementing counters, but we need to overwrite them when writing to them. This is most easily implemented by using variables.
|
@@ -45,8 +45,10 @@ begin
|
|
| 45 |
variable v_jump: std_logic;
|
| 46 |
variable v_jump_address: std_logic_vector(31 downto 0);
|
| 47 |
variable v_mem_req: mem_req_t;
|
|
|
|
| 48 |
|
| 49 |
variable csr_set_bits, csr_clear_bits: std_logic_vector(31 downto 0);
|
|
|
|
| 50 |
|
| 51 |
begin
|
| 52 |
if rising_edge(clk) then
|
|
@@ -56,6 +58,10 @@ begin
|
|
| 56 |
v_jump := '0';
|
| 57 |
v_jump_address := (others => '0');
|
| 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
if input.is_active = '1' and input.is_invalid = '0' then
|
| 60 |
if input.operation = OP_ADD then
|
| 61 |
v_output.result := std_logic_vector(unsigned(input.operand1) + unsigned(input.operand2));
|
|
@@ -258,7 +264,7 @@ begin
|
|
| 258 |
mip <= (mip or csr_set_bits(15 downto 0)) and csr_clear_bits(15 downto 0);
|
| 259 |
elsif input.operand2(11 downto 0) = CSR_MCYCLE then
|
| 260 |
v_output.result := mcycle;
|
| 261 |
-
|
| 262 |
elsif input.operand2(11 downto 0) = CSR_MINSTRET then
|
| 263 |
v_output.result := minstret;
|
| 264 |
minstret <= (minstret or csr_set_bits) and csr_clear_bits;
|
|
@@ -266,7 +272,7 @@ begin
|
|
| 266 |
v_output.result := (others => '0');
|
| 267 |
elsif input.operand2(11 downto 0) = CSR_MCYCLEH then
|
| 268 |
v_output.result := mcycleh;
|
| 269 |
-
|
| 270 |
elsif input.operand2(11 downto 0) = CSR_MINSTRETH then
|
| 271 |
v_output.result := minstreth;
|
| 272 |
minstreth <= (minstreth or csr_set_bits) and csr_clear_bits;
|
|
@@ -309,6 +315,9 @@ begin
|
|
| 309 |
|
| 310 |
jump <= v_jump;
|
| 311 |
jump_address <= v_jump_address(31 downto 1) & "0";
|
|
|
|
|
|
|
|
|
|
| 312 |
end if;
|
| 313 |
end process;
|
| 314 |
|
|
|
|
| 45 |
variable v_jump: std_logic;
|
| 46 |
variable v_jump_address: std_logic_vector(31 downto 0);
|
| 47 |
variable v_mem_req: mem_req_t;
|
| 48 |
+
variable v_mcycle_next, v_mcycleh_next: std_logic_vector(31 downto 0);
|
| 49 |
|
| 50 |
variable csr_set_bits, csr_clear_bits: std_logic_vector(31 downto 0);
|
| 51 |
+
variable v_temp: unsigned(63 downto 0);
|
| 52 |
|
| 53 |
begin
|
| 54 |
if rising_edge(clk) then
|
|
|
|
| 58 |
v_jump := '0';
|
| 59 |
v_jump_address := (others => '0');
|
| 60 |
|
| 61 |
+
v_temp := unsigned(mcycleh & mcycle) + 1;
|
| 62 |
+
v_mcycle_next := std_logic_vector(v_temp(31 downto 0));
|
| 63 |
+
v_mcycleh_next := std_logic_vector(v_temp(63 downto 32));
|
| 64 |
+
|
| 65 |
if input.is_active = '1' and input.is_invalid = '0' then
|
| 66 |
if input.operation = OP_ADD then
|
| 67 |
v_output.result := std_logic_vector(unsigned(input.operand1) + unsigned(input.operand2));
|
|
|
|
| 264 |
mip <= (mip or csr_set_bits(15 downto 0)) and csr_clear_bits(15 downto 0);
|
| 265 |
elsif input.operand2(11 downto 0) = CSR_MCYCLE then
|
| 266 |
v_output.result := mcycle;
|
| 267 |
+
v_mcycle_next := (mcycle or csr_set_bits) and csr_clear_bits;
|
| 268 |
elsif input.operand2(11 downto 0) = CSR_MINSTRET then
|
| 269 |
v_output.result := minstret;
|
| 270 |
minstret <= (minstret or csr_set_bits) and csr_clear_bits;
|
|
|
|
| 272 |
v_output.result := (others => '0');
|
| 273 |
elsif input.operand2(11 downto 0) = CSR_MCYCLEH then
|
| 274 |
v_output.result := mcycleh;
|
| 275 |
+
v_mcycleh_next := (mcycleh or csr_set_bits) and csr_clear_bits;
|
| 276 |
elsif input.operand2(11 downto 0) = CSR_MINSTRETH then
|
| 277 |
v_output.result := minstreth;
|
| 278 |
minstreth <= (minstreth or csr_set_bits) and csr_clear_bits;
|
|
|
|
| 315 |
|
| 316 |
jump <= v_jump;
|
| 317 |
jump_address <= v_jump_address(31 downto 1) & "0";
|
| 318 |
+
|
| 319 |
+
mcycle <= v_mcycle_next;
|
| 320 |
+
mcycleh <= v_mcycleh_next;
|
| 321 |
end if;
|
| 322 |
end process;
|
| 323 |
|
For minstret and minstreth the approach is similar, but we need to know when an instruction retires. I implement this by connecting the pipeline_ready signal from the writeback stage to the execute stage, and only incrementing the retired instruction count when this signal is high.
|
@@ -57,6 +57,7 @@ architecture rtl of core is
|
|
| 57 |
port (
|
| 58 |
clk: in std_logic;
|
| 59 |
input: in decode_output_t;
|
|
|
|
| 60 |
output: out execute_output_t;
|
| 61 |
mem_req: out mem_req_t;
|
| 62 |
jump: out std_logic := '0';
|
|
@@ -78,7 +79,7 @@ begin
|
|
| 78 |
|
| 79 |
decode_write_inst: decode_write port map(clk => clk, decode_input => fetch_output, decode_output => decode_output, write_input => memory_output, mem_res => mem_res_1, pipeline_ready => pipeline_ready);
|
| 80 |
|
| 81 |
-
execute_inst: execute port map(clk => clk, input => decode_output, output => execute_output, mem_req => mem_req_1, jump => jump, jump_address => jump_address, led => led);
|
| 82 |
|
| 83 |
memory_inst: memory port map(clk => clk, input => execute_output, output => memory_output);
|
| 84 |
|
|
|
|
| 57 |
port (
|
| 58 |
clk: in std_logic;
|
| 59 |
input: in decode_output_t;
|
| 60 |
+
instr_retire: in std_logic;
|
| 61 |
output: out execute_output_t;
|
| 62 |
mem_req: out mem_req_t;
|
| 63 |
jump: out std_logic := '0';
|
|
|
|
| 79 |
|
| 80 |
decode_write_inst: decode_write port map(clk => clk, decode_input => fetch_output, decode_output => decode_output, write_input => memory_output, mem_res => mem_res_1, pipeline_ready => pipeline_ready);
|
| 81 |
|
| 82 |
+
execute_inst: execute port map(clk => clk, input => decode_output, instr_retire => pipeline_ready, output => execute_output, mem_req => mem_req_1, jump => jump, jump_address => jump_address, led => led);
|
| 83 |
|
| 84 |
memory_inst: memory port map(clk => clk, input => execute_output, output => memory_output);
|
| 85 |
|
|
@@ -13,6 +13,7 @@ entity execute is
|
|
| 13 |
port (
|
| 14 |
clk: in std_logic;
|
| 15 |
input: in decode_output_t;
|
|
|
|
| 16 |
output: out execute_output_t := DEFAULT_EXECUTE_OUTPUT;
|
| 17 |
mem_req: out mem_req_t := DEFAULT_MEM_REQ;
|
| 18 |
jump: out std_logic := '0';
|
|
@@ -46,6 +47,7 @@ begin
|
|
| 46 |
variable v_jump_address: std_logic_vector(31 downto 0);
|
| 47 |
variable v_mem_req: mem_req_t;
|
| 48 |
variable v_mcycle_next, v_mcycleh_next: std_logic_vector(31 downto 0);
|
|
|
|
| 49 |
|
| 50 |
variable csr_set_bits, csr_clear_bits: std_logic_vector(31 downto 0);
|
| 51 |
variable v_temp: unsigned(63 downto 0);
|
|
@@ -62,6 +64,14 @@ begin
|
|
| 62 |
v_mcycle_next := std_logic_vector(v_temp(31 downto 0));
|
| 63 |
v_mcycleh_next := std_logic_vector(v_temp(63 downto 32));
|
| 64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
if input.is_active = '1' and input.is_invalid = '0' then
|
| 66 |
if input.operation = OP_ADD then
|
| 67 |
v_output.result := std_logic_vector(unsigned(input.operand1) + unsigned(input.operand2));
|
|
@@ -267,7 +277,7 @@ begin
|
|
| 267 |
v_mcycle_next := (mcycle or csr_set_bits) and csr_clear_bits;
|
| 268 |
elsif input.operand2(11 downto 0) = CSR_MINSTRET then
|
| 269 |
v_output.result := minstret;
|
| 270 |
-
|
| 271 |
elsif unsigned(CSR_MHPMCOUNTER3) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31) then
|
| 272 |
v_output.result := (others => '0');
|
| 273 |
elsif input.operand2(11 downto 0) = CSR_MCYCLEH then
|
|
@@ -275,7 +285,7 @@ begin
|
|
| 275 |
v_mcycleh_next := (mcycleh or csr_set_bits) and csr_clear_bits;
|
| 276 |
elsif input.operand2(11 downto 0) = CSR_MINSTRETH then
|
| 277 |
v_output.result := minstreth;
|
| 278 |
-
|
| 279 |
elsif unsigned(CSR_MHPMCOUNTER3H) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31H) then
|
| 280 |
v_output.result := (others => '0');
|
| 281 |
elsif unsigned(CSR_MHPMEVENT3) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMEVENT31) then
|
|
@@ -318,6 +328,9 @@ begin
|
|
| 318 |
|
| 319 |
mcycle <= v_mcycle_next;
|
| 320 |
mcycleh <= v_mcycleh_next;
|
|
|
|
|
|
|
|
|
|
| 321 |
end if;
|
| 322 |
end process;
|
| 323 |
|
|
|
|
| 13 |
port (
|
| 14 |
clk: in std_logic;
|
| 15 |
input: in decode_output_t;
|
| 16 |
+
instr_retire: in std_logic;
|
| 17 |
output: out execute_output_t := DEFAULT_EXECUTE_OUTPUT;
|
| 18 |
mem_req: out mem_req_t := DEFAULT_MEM_REQ;
|
| 19 |
jump: out std_logic := '0';
|
|
|
|
| 47 |
variable v_jump_address: std_logic_vector(31 downto 0);
|
| 48 |
variable v_mem_req: mem_req_t;
|
| 49 |
variable v_mcycle_next, v_mcycleh_next: std_logic_vector(31 downto 0);
|
| 50 |
+
variable v_minstret_next, v_minstreth_next: std_logic_vector(31 downto 0);
|
| 51 |
|
| 52 |
variable csr_set_bits, csr_clear_bits: std_logic_vector(31 downto 0);
|
| 53 |
variable v_temp: unsigned(63 downto 0);
|
|
|
|
| 64 |
v_mcycle_next := std_logic_vector(v_temp(31 downto 0));
|
| 65 |
v_mcycleh_next := std_logic_vector(v_temp(63 downto 32));
|
| 66 |
|
| 67 |
+
v_temp := unsigned(minstreth & minstret);
|
| 68 |
+
if instr_retire = '1' then
|
| 69 |
+
v_temp := v_temp + 1;
|
| 70 |
+
end if;
|
| 71 |
+
|
| 72 |
+
v_minstret_next := std_logic_vector(v_temp(31 downto 0));
|
| 73 |
+
v_minstreth_next := std_logic_vector(v_temp(63 downto 32));
|
| 74 |
+
|
| 75 |
if input.is_active = '1' and input.is_invalid = '0' then
|
| 76 |
if input.operation = OP_ADD then
|
| 77 |
v_output.result := std_logic_vector(unsigned(input.operand1) + unsigned(input.operand2));
|
|
|
|
| 277 |
v_mcycle_next := (mcycle or csr_set_bits) and csr_clear_bits;
|
| 278 |
elsif input.operand2(11 downto 0) = CSR_MINSTRET then
|
| 279 |
v_output.result := minstret;
|
| 280 |
+
v_minstret_next := (minstret or csr_set_bits) and csr_clear_bits;
|
| 281 |
elsif unsigned(CSR_MHPMCOUNTER3) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31) then
|
| 282 |
v_output.result := (others => '0');
|
| 283 |
elsif input.operand2(11 downto 0) = CSR_MCYCLEH then
|
|
|
|
| 285 |
v_mcycleh_next := (mcycleh or csr_set_bits) and csr_clear_bits;
|
| 286 |
elsif input.operand2(11 downto 0) = CSR_MINSTRETH then
|
| 287 |
v_output.result := minstreth;
|
| 288 |
+
v_minstreth_next := (minstreth or csr_set_bits) and csr_clear_bits;
|
| 289 |
elsif unsigned(CSR_MHPMCOUNTER3H) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMCOUNTER31H) then
|
| 290 |
v_output.result := (others => '0');
|
| 291 |
elsif unsigned(CSR_MHPMEVENT3) <= unsigned(input.operand2(11 downto 0)) and unsigned(input.operand2(11 downto 0)) <= unsigned(CSR_MHPMEVENT31) then
|
|
|
|
| 328 |
|
| 329 |
mcycle <= v_mcycle_next;
|
| 330 |
mcycleh <= v_mcycleh_next;
|
| 331 |
+
|
| 332 |
+
minstret <= v_minstret_next;
|
| 333 |
+
minstreth <= v_minstreth_next;
|
| 334 |
end if;
|
| 335 |
end process;
|
| 336 |
|