Skip to content

Commit d9a6d92

Browse files
riscv multi cycle design 4 cycles seems working, split decode and exe at reg rd
1 parent d2a0024 commit d9a6d92

File tree

5 files changed

+102
-34
lines changed

5 files changed

+102
-34
lines changed

examples/risc-v/mem_decl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
#include "arrays.h"
66
#include "mem_map.h"
77

8+
// Helper macro to rename wrapped user type
9+
#ifndef riscv_mmio_mod_out_t
10+
#define riscv_mmio_mod_out_t riscv_mem_map_mod_out_t(riscv_mem_map_outputs_t)
11+
#endif
12+
813
// Instruction and data memory initialized from gcc compile
914

1015
// RAM with one read port for instructions

examples/risc-v/multi_cycle_risc-v.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
#pragma PART "xc7a35ticsg324-1l" //LFE5U-85F-6BG381C" //xc7a35ticsg324-1l"
1+
#pragma PART "LFE5U-85F-6BG381C" //LFE5U-85F-6BG381C" //xc7a35ticsg324-1l"
22
#include "uintN_t.h"
33
#include "intN_t.h"
44

5-
// RISC-V components
6-
#include "risc-v.h"
7-
85
// Include test gcc compiled program
6+
#include "gcc_test/mem_map.h"
97
#include "gcc_test/text_mem_init.h"
108
#include "gcc_test/data_mem_init.h"
119

12-
// Declare memory map information
13-
// Starts with shared with software memory map info
14-
#include "gcc_test/mem_map.h"
15-
// Define inputs and outputs
10+
// Helpers macros for building mmio modules
11+
#include "mem_map.h"
12+
// Define MMIO inputs and outputs
1613
typedef struct my_mmio_in_t{
1714
uint1_t button;
1815
}my_mmio_in_t;

examples/risc-v/multi_cycle_risc-v_decl.h

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@
22
#include "uintN_t.h"
33
#include "intN_t.h"
44

5-
// Support old single core using mem_map_out_t
6-
#include "mem_map.h"
7-
#ifdef riscv_mem_map_outputs_t
8-
#define riscv_mmio_mod_out_t riscv_mem_map_mod_out_t(riscv_mem_map_outputs_t)
9-
#else
10-
#define riscv_mmio_mod_out_t mem_map_out_t
11-
#endif
5+
// RISC-V components
6+
#define RISCV_REGFILE_1_CYCLE
7+
#include "risc-v.h"
128

139
// Declare instruction and data memory
1410
// also includes memory mapped IO
@@ -17,10 +13,10 @@
1713
// Multi cycle is not a pipeline
1814
#define RISCV_IMEM_NO_AUTOPIPELINE
1915
#define RISCV_DMEM_NO_AUTOPIPELINE
20-
#define N_CYCLES 3
2116
#include "mem_decl.h"
2217

2318
// CPU top level
19+
#define N_CYCLES 4 // 3 pipeline reg delays: imem, regfile, dmem = 4 cycles
2420
#define riscv_out_t PPCAT(riscv_name,_out_t)
2521
typedef struct riscv_out_t{
2622
// Debug IO
@@ -90,6 +86,8 @@ riscv_out_t riscv_name(
9086
}
9187

9288
// Boundary shared between cycle0 and cycle1
89+
// TODO IMEM is stateless shouldnt need if(state) logic
90+
// can do like DMEM and be always in use
9391
if(state[0]|state[1]){
9492
// Instruction memory
9593
imem_out = riscv_imem_ram(pc>>2, 1);
@@ -113,9 +111,10 @@ riscv_out_t riscv_name(
113111
ARRAY_1ROT_UP(uint1_t, next_state, N_CYCLES)
114112
}
115113

116-
// Cycle1+2: Register file reads and writes
117-
// Reads are done during cycle1
118-
// Write back is next clock, cycle2
114+
// Cycle1+2+3: Register file reads and writes
115+
// Reads start during cycle1
116+
// Read finish during cycle2
117+
// Write back is next clock, cycle3
119118
// Register file write signals are not driven until later in code
120119
// but are used now, requiring FEEDBACK pragma
121120
uint5_t reg_wr_addr;
@@ -124,7 +123,9 @@ riscv_out_t riscv_name(
124123
#pragma FEEDBACK reg_wr_addr
125124
#pragma FEEDBACK reg_wr_data
126125
#pragma FEEDBACK reg_wr_en
127-
if(state[1]|state[2]){
126+
// TODO make this like DMEM, doesnt need if(state) specific
127+
// doesnt need to do next_state transition either
128+
if(state[1]|state[2]|state[3]){
128129
reg_file_out = reg_file(
129130
decoded.src1, // First read port address
130131
decoded.src2, // Second read port address
@@ -137,31 +138,31 @@ riscv_out_t riscv_name(
137138
ARRAY_1ROT_UP(uint1_t, next_state, N_CYCLES)
138139
}
139140

140-
// Cycle1: Execute
141-
if(state[1]){
142-
printf("Execute in Cycle/Stage 1\n");
141+
// Cycle2: Execute
142+
if(state[2]){
143+
printf("Execute in Cycle/Stage 2\n");
143144
exe = execute(
144145
pc, pc_plus4_reg,
145-
decoded,
146+
decoded_reg,
146147
reg_file_out.rd_data1, reg_file_out.rd_data2
147148
);
148149
// Next state/cycle (potentially redundant)
149150
next_state = state;
150151
ARRAY_1ROT_UP(uint1_t, next_state, N_CYCLES)
151152
}
152153

153-
// Boundary shared between cycle1 and cycle2
154+
// Boundary shared between cycle2 and cycle3
154155
// Data Memory inputs in stage1
155156
// Default no writes or reads
156157
ARRAY_SET(mem_wr_byte_ens, 0, 4)
157158
ARRAY_SET(mem_rd_byte_ens, 0, 4)
158159
mem_addr = exe.result; // addr always from execute module, not always used
159160
mem_wr_data = reg_file_out.rd_data2;
160-
if(state[1]){
161+
if(state[2]){
161162
// Only write or read en during first cycle of two cycle read
162-
mem_wr_byte_ens = decoded.mem_wr_byte_ens;
163-
mem_rd_byte_ens = decoded.mem_rd_byte_ens;
164-
if(decoded.mem_wr_byte_ens[0]){
163+
mem_wr_byte_ens = decoded_reg.mem_wr_byte_ens;
164+
mem_rd_byte_ens = decoded_reg.mem_rd_byte_ens;
165+
if(decoded_reg.mem_wr_byte_ens[0]){
165166
printf("Write Mem[0x%X] = %d\n", mem_addr, mem_wr_data);
166167
}
167168
}
@@ -182,21 +183,21 @@ riscv_out_t riscv_name(
182183
#ifdef riscv_mem_map_outputs_t
183184
o.mem_map_outputs = dmem_out.mem_map_outputs;
184185
#endif
185-
// Data memory outputs in stage2
186-
if(state[2]){
186+
// Data memory outputs in stage3
187+
if(state[3]){
187188
// Read output available from dmem_out in second cycle of two cycle read
188189
if(decoded_reg.mem_rd_byte_ens[0]){
189190
printf("Read Mem[0x%X] = %d\n", mem_addr_reg, dmem_out.rd_data);
190191
}
191192
}
192193

193-
// Cycle 2: Write Back + Next PC
194+
// Cycle 3: Write Back + Next PC
194195
// default values needed for feedback signals
195196
reg_wr_en = 0; // default no writes
196197
reg_wr_addr = 0;
197198
reg_wr_data = 0;
198-
if(state[2]){
199-
printf("Write Back + Next PC in Cycle/Stage 2\n");
199+
if(state[3]){
200+
printf("Write Back + Next PC in Cycle/Stage 3\n");
200201
// Reg file write back, drive inputs (FEEDBACK)
201202
reg_wr_en = decoded_reg.reg_wr;
202203
reg_wr_addr = decoded_reg.dest;

examples/risc-v/reg_file.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,23 @@
1010
// Need a RAM with two read ports and one write port
1111
// Declare register file RAM
1212
// Triple port, two read ports, one write
13+
#ifdef RISCV_REGFILE_1_CYCLE
14+
// 1 cycle latency like bram
15+
DECL_RAM_TP_R_R_W_1(
16+
uint32_t,
17+
reg_file_ram,
18+
NUM_REGS,
19+
RAM_INIT_INT_ZEROS
20+
)
21+
#else
1322
// Zero latency
1423
DECL_RAM_TP_R_R_W_0(
1524
uint32_t,
1625
reg_file_ram,
1726
NUM_REGS,
1827
RAM_INIT_INT_ZEROS
1928
)
29+
#endif
2030

2131
// Split the_reg_file into three parts, 2 read ports, 1 write
2232
typedef struct reg_file_out_t

pipelinec/include/ram.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,3 +654,58 @@ begin \n\
654654
return_output.rd_data1 <= the_ram(rd_addr1_s); \n\
655655
"); \
656656
}
657+
658+
659+
// Triple port, two read only, one write only, 1 latency
660+
#define DECL_RAM_TP_R_R_W_1( \
661+
elem_t, \
662+
ram_name, \
663+
SIZE, \
664+
VHDL_INIT \
665+
) \
666+
typedef struct ram_name##_out_t \
667+
{ \
668+
elem_t rd_data0; \
669+
elem_t rd_data1; \
670+
}ram_name##_out_t; \
671+
ram_name##_out_t ram_name( \
672+
uint32_t rd_addr0, \
673+
uint32_t rd_addr1, \
674+
uint32_t wr_addr, elem_t wr_data, uint1_t wr_en \
675+
){ \
676+
__vhdl__("\n\
677+
constant SIZE : integer := " xstr(SIZE) "; \n\
678+
type ram_t is array(0 to SIZE-1) of " xstr(elem_t) "; \n\
679+
signal the_ram : ram_t := " VHDL_INIT "; \n\
680+
-- Limit zero latency comb. read addr range to SIZE \n\
681+
-- since invalid addresses can occur as logic propogates \n\
682+
-- (this includes out of int32 range u32 values) \n\
683+
signal rd_addr0_s : integer range 0 to SIZE-1 := 0; \n\
684+
signal rd_addr1_s : integer range 0 to SIZE-1 := 0; \n\
685+
begin \n\
686+
process(all) begin \n\
687+
rd_addr0_s <= to_integer(rd_addr0(30 downto 0)) \n\
688+
-- synthesis translate_off \n\
689+
mod SIZE \n\
690+
-- synthesis translate_on \n\
691+
; \n\
692+
rd_addr1_s <= to_integer(rd_addr1(30 downto 0)) \n\
693+
-- synthesis translate_off \n\
694+
mod SIZE \n\
695+
-- synthesis translate_on \n\
696+
; \n\
697+
end process; \n\
698+
process(clk) \n\
699+
begin \n\
700+
if rising_edge(clk) then \n\
701+
if CLOCK_ENABLE(0)='1' then \n\
702+
if wr_en(0) = '1' then \n\
703+
the_ram(to_integer(wr_addr)) <= wr_data; \n\
704+
end if; \n\
705+
return_output.rd_data0 <= the_ram(rd_addr0_s); \n\
706+
return_output.rd_data1 <= the_ram(rd_addr1_s); \n\
707+
end if; \n\
708+
end if; \n\
709+
end process; \n\
710+
"); \
711+
}

0 commit comments

Comments
 (0)