aboutsummaryrefslogtreecommitdiffstats
path: root/sources/hdl/verilog/fetch_stage.v
blob: bd72fe5eb72559550bf9129e904d313f2fa2fb13 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
`include "parameters.vh"

module fetch_stage(
  // common signals
  input                          clk,
  input                          rst,

  // other control signals
  output                         softmc_end,
  output  [11:0]                 read_size,
  output reg                     read_seq_incoming,
  input  [11:0]                  buffer_space,

  // branch unit <-> fetch stage interface
  input                          br_resolve,
  input   [`IMEM_ADDR_WIDTH-1:0] br_target,

  // fetch stage <-> frontend interface
  output  [`IMEM_ADDR_WIDTH-1:0] addr_out,
  output                         valid_out,
  input   [`INSTR_WIDTH-1:0]     data_in,
  input                          valid_in,
  input   [`IMEM_ADDR_WIDTH-1:0] addr_in,
  input                          ready_out, // frontend is ready for a valid request

  // fetch stage <-> decode stage interface
  output  [`INSTR_WIDTH-1:0]     instr,
  output  [`IMEM_ADDR_WIDTH-1:0] instr_pc,
  output                         instr_valid
  );

  wire inst_is_br, is_end, is_ddr_start, need_flush, is_sleep;

  reg [31:0] sleep_ctr_r, sleep_ctr_ns;

  localparam WAIT_RESOLVE_S      = 0;
  localparam FETCH_NEXT_LINE_S   = 1;
  localparam WAIT_BUFFER_SPACE_S = 2;
  localparam WAIT_SLEEP_S        = 3;

  reg [2:0] state_r, state_ns;

  // kind of confusing but these PCs map to
  // an instruction instead of to a byte.
  // i.e. each PC addresses an instruction.
  reg [`IMEM_ADDR_WIDTH-1:0] pc_r, pc_ns;

  // register outputs, decode will receive
  // stuff we've received with one cycle latency
  // i.e. marks the end of fetch_stage cycle
  reg [`IMEM_ADDR_WIDTH-1:0] instr_pc_r, instr_pc_ns;
  reg [`INSTR_WIDTH-1:0]     instr_r, instr_ns;
  reg                        instr_valid_r, instr_valid_ns;
  
  pre_decode pdec(
    .buffer_space(buffer_space),
    .read_size(read_size),
    .instruction(state_r == WAIT_BUFFER_SPACE_S ? instr_r : data_in),
    .is_branch(inst_is_br),
    .is_end(is_end),
    .is_ddr_start(is_ddr_start),
    .need_flush(need_flush),
    .is_sleep(is_sleep)
  );

  assign instr       = instr_r;
  assign instr_valid = instr_valid_r;
  assign instr_pc    = instr_pc_r;

  // request instr @ pc from frontend
  assign valid_out   = ready_out && (state_r == FETCH_NEXT_LINE_S) && ~need_flush && ~(valid_in && is_sleep);
  assign addr_out    = pc_r;

  assign softmc_end  = is_end && valid_in && (state_r == FETCH_NEXT_LINE_S);

  always @* begin
    sleep_ctr_ns   = sleep_ctr_r;
    state_ns       = state_r;
    pc_ns          = pc_r;
    instr_ns       = instr_r;
    instr_pc_ns    = instr_pc_r;
    instr_valid_ns = ~is_end && valid_in && (state_r == FETCH_NEXT_LINE_S) 
        && ~is_ddr_start;
    read_seq_incoming = `LOW;
    case(state_r)
      WAIT_RESOLVE_S: begin
        if(br_resolve) begin
          state_ns = FETCH_NEXT_LINE_S;
          pc_ns    = br_target;
        end
      end
      FETCH_NEXT_LINE_S: begin
        if(ready_out && valid_out)
          pc_ns = pc_r + 1;
        if(valid_in) begin
          instr_ns = data_in;
          instr_pc_ns = addr_in;
          if(is_sleep) begin
            sleep_ctr_ns = data_in[31:0];
            state_ns = WAIT_SLEEP_S;
          end
          if(is_ddr_start && ~need_flush && (|data_in[9:0]))
            read_seq_incoming = `HIGH;
          if(inst_is_br && ~is_sleep) // we don't have the ability to perform well
            state_ns = WAIT_RESOLVE_S;
          else if(is_end)
            pc_ns    = {`IMEM_ADDR_WIDTH{`LOW}};
          else if(need_flush) begin
            state_ns = WAIT_BUFFER_SPACE_S;
            pc_ns    = addr_in;     // register the info packet
                                    // as the next instruction to fetch
          end
        end  
      end
      WAIT_BUFFER_SPACE_S: begin
        if(~need_flush) begin
          state_ns = FETCH_NEXT_LINE_S;
        end
      end
      WAIT_SLEEP_S: begin
        sleep_ctr_ns = sleep_ctr_r - 1;
        if(sleep_ctr_r == 32'b1)
          state_ns = FETCH_NEXT_LINE_S;
      end
    endcase
  end

  always @(posedge clk) begin
    if (rst) begin
      pc_r          <= {`IMEM_ADDR_WIDTH{`LOW}};
      state_r       <= FETCH_NEXT_LINE_S;
      instr_valid_r <= `LOW;
      instr_r       <= {`INSTR_WIDTH{`LOW}};
      instr_pc_r    <= {`IMEM_ADDR_WIDTH{`LOW}};
      sleep_ctr_r   <= {32{`LOW}};
    end
    else begin
      state_r       <= state_ns;
      pc_r          <= pc_ns;
      instr_r       <= instr_ns;
      instr_pc_r    <= instr_pc_ns;
      instr_valid_r <= instr_valid_ns;
      sleep_ctr_r   <= sleep_ctr_ns;
    end
  end

endmodule