Skip to content

Commit

Permalink
riscv multi cycle design 4 cycles seems working, split decode and exe…
Browse files Browse the repository at this point in the history
… at reg rd
  • Loading branch information
JulianKemmerer committed Jun 30, 2024
1 parent d2a0024 commit d9a6d92
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 34 deletions.
5 changes: 5 additions & 0 deletions examples/risc-v/mem_decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
#include "arrays.h"
#include "mem_map.h"

// Helper macro to rename wrapped user type
#ifndef riscv_mmio_mod_out_t
#define riscv_mmio_mod_out_t riscv_mem_map_mod_out_t(riscv_mem_map_outputs_t)
#endif

// Instruction and data memory initialized from gcc compile

// RAM with one read port for instructions
Expand Down
13 changes: 5 additions & 8 deletions examples/risc-v/multi_cycle_risc-v.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
#pragma PART "xc7a35ticsg324-1l" //LFE5U-85F-6BG381C" //xc7a35ticsg324-1l"
#pragma PART "LFE5U-85F-6BG381C" //LFE5U-85F-6BG381C" //xc7a35ticsg324-1l"
#include "uintN_t.h"
#include "intN_t.h"

// RISC-V components
#include "risc-v.h"

// Include test gcc compiled program
#include "gcc_test/mem_map.h"
#include "gcc_test/text_mem_init.h"
#include "gcc_test/data_mem_init.h"

// Declare memory map information
// Starts with shared with software memory map info
#include "gcc_test/mem_map.h"
// Define inputs and outputs
// Helpers macros for building mmio modules
#include "mem_map.h"
// Define MMIO inputs and outputs
typedef struct my_mmio_in_t{
uint1_t button;
}my_mmio_in_t;
Expand Down
53 changes: 27 additions & 26 deletions examples/risc-v/multi_cycle_risc-v_decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@
#include "uintN_t.h"
#include "intN_t.h"

// Support old single core using mem_map_out_t
#include "mem_map.h"
#ifdef riscv_mem_map_outputs_t
#define riscv_mmio_mod_out_t riscv_mem_map_mod_out_t(riscv_mem_map_outputs_t)
#else
#define riscv_mmio_mod_out_t mem_map_out_t
#endif
// RISC-V components
#define RISCV_REGFILE_1_CYCLE
#include "risc-v.h"

// Declare instruction and data memory
// also includes memory mapped IO
Expand All @@ -17,10 +13,10 @@
// Multi cycle is not a pipeline
#define RISCV_IMEM_NO_AUTOPIPELINE
#define RISCV_DMEM_NO_AUTOPIPELINE
#define N_CYCLES 3
#include "mem_decl.h"

// CPU top level
#define N_CYCLES 4 // 3 pipeline reg delays: imem, regfile, dmem = 4 cycles
#define riscv_out_t PPCAT(riscv_name,_out_t)
typedef struct riscv_out_t{
// Debug IO
Expand Down Expand Up @@ -90,6 +86,8 @@ riscv_out_t riscv_name(
}

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

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

// Cycle1: Execute
if(state[1]){
printf("Execute in Cycle/Stage 1\n");
// Cycle2: Execute
if(state[2]){
printf("Execute in Cycle/Stage 2\n");
exe = execute(
pc, pc_plus4_reg,
decoded,
decoded_reg,
reg_file_out.rd_data1, reg_file_out.rd_data2
);
// Next state/cycle (potentially redundant)
next_state = state;
ARRAY_1ROT_UP(uint1_t, next_state, N_CYCLES)
}

// Boundary shared between cycle1 and cycle2
// Boundary shared between cycle2 and cycle3
// Data Memory inputs in stage1
// Default no writes or reads
ARRAY_SET(mem_wr_byte_ens, 0, 4)
ARRAY_SET(mem_rd_byte_ens, 0, 4)
mem_addr = exe.result; // addr always from execute module, not always used
mem_wr_data = reg_file_out.rd_data2;
if(state[1]){
if(state[2]){
// Only write or read en during first cycle of two cycle read
mem_wr_byte_ens = decoded.mem_wr_byte_ens;
mem_rd_byte_ens = decoded.mem_rd_byte_ens;
if(decoded.mem_wr_byte_ens[0]){
mem_wr_byte_ens = decoded_reg.mem_wr_byte_ens;
mem_rd_byte_ens = decoded_reg.mem_rd_byte_ens;
if(decoded_reg.mem_wr_byte_ens[0]){
printf("Write Mem[0x%X] = %d\n", mem_addr, mem_wr_data);
}
}
Expand All @@ -182,21 +183,21 @@ riscv_out_t riscv_name(
#ifdef riscv_mem_map_outputs_t
o.mem_map_outputs = dmem_out.mem_map_outputs;
#endif
// Data memory outputs in stage2
if(state[2]){
// Data memory outputs in stage3
if(state[3]){
// Read output available from dmem_out in second cycle of two cycle read
if(decoded_reg.mem_rd_byte_ens[0]){
printf("Read Mem[0x%X] = %d\n", mem_addr_reg, dmem_out.rd_data);
}
}

// Cycle 2: Write Back + Next PC
// Cycle 3: Write Back + Next PC
// default values needed for feedback signals
reg_wr_en = 0; // default no writes
reg_wr_addr = 0;
reg_wr_data = 0;
if(state[2]){
printf("Write Back + Next PC in Cycle/Stage 2\n");
if(state[3]){
printf("Write Back + Next PC in Cycle/Stage 3\n");
// Reg file write back, drive inputs (FEEDBACK)
reg_wr_en = decoded_reg.reg_wr;
reg_wr_addr = decoded_reg.dest;
Expand Down
10 changes: 10 additions & 0 deletions examples/risc-v/reg_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,23 @@
// Need a RAM with two read ports and one write port
// Declare register file RAM
// Triple port, two read ports, one write
#ifdef RISCV_REGFILE_1_CYCLE
// 1 cycle latency like bram
DECL_RAM_TP_R_R_W_1(
uint32_t,
reg_file_ram,
NUM_REGS,
RAM_INIT_INT_ZEROS
)
#else
// Zero latency
DECL_RAM_TP_R_R_W_0(
uint32_t,
reg_file_ram,
NUM_REGS,
RAM_INIT_INT_ZEROS
)
#endif

// Split the_reg_file into three parts, 2 read ports, 1 write
typedef struct reg_file_out_t
Expand Down
55 changes: 55 additions & 0 deletions pipelinec/include/ram.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,3 +654,58 @@ begin \n\
return_output.rd_data1 <= the_ram(rd_addr1_s); \n\
"); \
}


// Triple port, two read only, one write only, 1 latency
#define DECL_RAM_TP_R_R_W_1( \
elem_t, \
ram_name, \
SIZE, \
VHDL_INIT \
) \
typedef struct ram_name##_out_t \
{ \
elem_t rd_data0; \
elem_t rd_data1; \
}ram_name##_out_t; \
ram_name##_out_t ram_name( \
uint32_t rd_addr0, \
uint32_t rd_addr1, \
uint32_t wr_addr, elem_t wr_data, uint1_t wr_en \
){ \
__vhdl__("\n\
constant SIZE : integer := " xstr(SIZE) "; \n\
type ram_t is array(0 to SIZE-1) of " xstr(elem_t) "; \n\
signal the_ram : ram_t := " VHDL_INIT "; \n\
-- Limit zero latency comb. read addr range to SIZE \n\
-- since invalid addresses can occur as logic propogates \n\
-- (this includes out of int32 range u32 values) \n\
signal rd_addr0_s : integer range 0 to SIZE-1 := 0; \n\
signal rd_addr1_s : integer range 0 to SIZE-1 := 0; \n\
begin \n\
process(all) begin \n\
rd_addr0_s <= to_integer(rd_addr0(30 downto 0)) \n\
-- synthesis translate_off \n\
mod SIZE \n\
-- synthesis translate_on \n\
; \n\
rd_addr1_s <= to_integer(rd_addr1(30 downto 0)) \n\
-- synthesis translate_off \n\
mod SIZE \n\
-- synthesis translate_on \n\
; \n\
end process; \n\
process(clk) \n\
begin \n\
if rising_edge(clk) then \n\
if CLOCK_ENABLE(0)='1' then \n\
if wr_en(0) = '1' then \n\
the_ram(to_integer(wr_addr)) <= wr_data; \n\
end if; \n\
return_output.rd_data0 <= the_ram(rd_addr0_s); \n\
return_output.rd_data1 <= the_ram(rd_addr1_s); \n\
end if; \n\
end if; \n\
end process; \n\
"); \
}

0 comments on commit d9a6d92

Please sign in to comment.