diff options
| author | Julian Blake Kongslie | 2022-02-17 08:36:10 -0800 |
|---|---|---|
| committer | Julian Blake Kongslie | 2022-02-17 08:36:10 -0800 |
| commit | 5bec0a6c6e4aee1c43a7757ac9818f3b9fdc2b15 (patch) | |
| tree | 654ea4343fb3ba63aeba9133882340101c1d777f | |
| parent | Fix pin names in TCL file (diff) | |
| download | simple-memory-controller-5bec0a6c6e4aee1c43a7757ac9818f3b9fdc2b15.tar.xz | |
Reorganize controller state machine and tweak timing slightly.
| -rw-r--r-- | hdl/ram_controller.sv | 110 |
1 files changed, 62 insertions, 48 deletions
diff --git a/hdl/ram_controller.sv b/hdl/ram_controller.sv index b6e744b..015eef0 100644 --- a/hdl/ram_controller.sv +++ b/hdl/ram_controller.sv | |||
| @@ -34,27 +34,44 @@ module ram_controller | |||
| 34 | bit slow; | 34 | bit slow; |
| 35 | 35 | ||
| 36 | enum | 36 | enum |
| 37 | { SEND_COMMAND_1 | 37 | { CHIP_SELECT |
| 38 | |||
| 39 | , SEND_COMMAND_1 | ||
| 38 | , SEND_COMMAND_2 | 40 | , SEND_COMMAND_2 |
| 39 | , SEND_COMMAND_3 | 41 | , SEND_COMMAND_3 |
| 40 | , SEND_COMMAND_4 | 42 | , SEND_COMMAND_4 |
| 41 | , SEND_COMMAND_5 | 43 | , SEND_COMMAND_5 |
| 42 | , SEND_COMMAND_6 | 44 | , SEND_COMMAND_6 |
| 43 | 45 | ||
| 44 | , LAT2_CYC1 | 46 | , LAT2_12 |
| 45 | , LAT2_CYC2 | 47 | , LAT2_11 |
| 46 | , LAT2_CYC3 | 48 | , LAT2_10 |
| 47 | , LAT2_CYC4 | 49 | , LAT2_9 |
| 48 | , LAT2_CYC5 | 50 | , LAT2_8 |
| 49 | , LAT2_CYC6 | 51 | , LAT2_7 |
| 52 | , LAT2_6 | ||
| 53 | , LAT2_5 | ||
| 54 | , LAT2_4 | ||
| 55 | , LAT2_3 | ||
| 56 | , LAT2_2 | ||
| 57 | , LAT2_1 | ||
| 50 | 58 | ||
| 51 | , LAT1_CYC1 | 59 | /* Latency blocks are 6 cycle, but you start counting after the upper |
| 52 | , LAT1_CYC2 | 60 | * column address is sent (SEND_COMMAND_4) so we reduce the |
| 53 | , LAT1_CYC3 | 61 | * lowest-latency block by one full cycle (two states). |
| 54 | , LAT1_CYC4 | 62 | , LAT1_12 |
| 55 | // Latency blocks are 6 cycle, but they start in the SEND_COMMAND_5 cycle, so block 1 is only 4 real cycles | 63 | , LAT1_11 |
| 56 | //, LAT1_CYC5 | 64 | */ |
| 57 | //, LAT1_CYC6 | 65 | , LAT1_10 |
| 66 | , LAT1_9 | ||
| 67 | , LAT1_8 | ||
| 68 | , LAT1_7 | ||
| 69 | , LAT1_6 | ||
| 70 | , LAT1_5 | ||
| 71 | , LAT1_4 | ||
| 72 | , LAT1_3 | ||
| 73 | , LAT1_2 | ||
| 74 | , LAT1_1 | ||
| 58 | 75 | ||
| 59 | , DATA_1 | 76 | , DATA_1 |
| 60 | , DATA_2 | 77 | , DATA_2 |
| @@ -104,84 +121,81 @@ module ram_controller | |||
| 104 | ram_csn[1] = 1; | 121 | ram_csn[1] = 1; |
| 105 | ram_clkp = 0; | 122 | ram_clkp = 0; |
| 106 | end else begin | 123 | end else begin |
| 124 | automatic bit stall = 0; | ||
| 125 | ram_clkp = !ram_clkp; | ||
| 107 | case (state) | 126 | case (state) |
| 108 | 127 | ||
| 128 | CHIP_SELECT: begin | ||
| 129 | ram_clkp = 0; // Overriding clock to guarantee that we're starting the command with the correct clock polarity | ||
| 130 | ram_csn[address[23]] = 0; | ||
| 131 | end | ||
| 132 | |||
| 109 | SEND_COMMAND_1: begin | 133 | SEND_COMMAND_1: begin |
| 110 | ram_clkp = 0; | ||
| 111 | ram_csn[address[23]] = 0; | 134 | ram_csn[address[23]] = 0; |
| 112 | ram_data_oe = 1; | 135 | ram_data_oe = 1; |
| 113 | ram_data_out = {!write, 1'b0, 1'b0, 5'b0}; // R/W# AS BURST RESERVED | 136 | ram_data_out = {!write, 1'b0, 1'b0, 5'b0}; // R/W#, ADDRSPACE, BURST, RESERVED |
| 114 | state = state.next; | ||
| 115 | end | 137 | end |
| 116 | 138 | ||
| 117 | SEND_COMMAND_2: begin | 139 | SEND_COMMAND_2: begin |
| 118 | ram_clkp = 1; | ||
| 119 | ram_data_oe = 1; | 140 | ram_data_oe = 1; |
| 120 | ram_data_out = {4'b0, address[22:19]}; // RESERVED ROW | 141 | ram_data_out = {4'b0, address[22:19]}; // RESERVED, ROW |
| 121 | state = state.next; | ||
| 122 | end | 142 | end |
| 123 | 143 | ||
| 124 | SEND_COMMAND_3: begin | 144 | SEND_COMMAND_3: begin |
| 125 | ram_clkp = 0; | ||
| 126 | ram_data_oe = 1; | 145 | ram_data_oe = 1; |
| 127 | ram_data_out = {address[18:11]}; // ROW | 146 | ram_data_out = {address[18:11]}; // ROW |
| 128 | state = state.next; | ||
| 129 | end | 147 | end |
| 130 | 148 | ||
| 131 | SEND_COMMAND_4: begin | 149 | SEND_COMMAND_4: begin |
| 132 | ram_clkp = 1; | ||
| 133 | ram_data_oe = 1; | 150 | ram_data_oe = 1; |
| 134 | ram_data_out = {address[10:9], address[8:3]}; // ROW UPPERCOL | 151 | ram_data_out = {address[10:9], address[8:3]}; // ROW, UPPERCOL |
| 135 | slow = ram_rwds_in; // Sort of arbitrarily capturing RWDS in the middle of the command string | 152 | // This is the cycle immediately before the latency countdown *really* begins. |
| 136 | state = state.next; | 153 | // So we capture RWDS now in order to know how many latency blocks are required. |
| 154 | slow = ram_rwds_in; | ||
| 137 | end | 155 | end |
| 138 | 156 | ||
| 139 | SEND_COMMAND_5: begin | 157 | SEND_COMMAND_5: begin |
| 140 | ram_clkp = 0; | ||
| 141 | ram_data_oe = 1; | 158 | ram_data_oe = 1; |
| 142 | ram_data_out = {8'b0}; // RESERVED | 159 | ram_data_out = {8'b0}; // RESERVED |
| 143 | state = state.next; | ||
| 144 | end | 160 | end |
| 145 | 161 | ||
| 146 | SEND_COMMAND_6: begin | 162 | SEND_COMMAND_6: begin |
| 147 | ram_clkp = 1; | ||
| 148 | ram_data_oe = 1; | 163 | ram_data_oe = 1; |
| 149 | ram_data_out = {5'b0, address[2:0]}; // RESERVED LOWERCOL | 164 | ram_data_out = {5'b0, address[2:0]}; // RESERVED, LOWERCOL |
| 150 | if (slow) | 165 | // If we're not in "slow" mode then skip the LAT2 latency |
| 151 | state = LAT2_CYC1; | 166 | // block. Note that the state=state.next will still happen |
| 152 | else | 167 | // below, taking us to the first state in the LAT1 block. |
| 153 | state = LAT1_CYC1; | 168 | if (!slow) state = LAT2_1; |
| 154 | end | 169 | end |
| 155 | 170 | ||
| 156 | LAT2_CYC1, LAT2_CYC2, LAT2_CYC3, LAT2_CYC4, LAT2_CYC5, LAT2_CYC6, | 171 | // Nothing happens on any of the LAT_* states except for |
| 157 | LAT1_CYC1, LAT1_CYC2, LAT1_CYC3, LAT1_CYC4: begin | 172 | // cycling the clock and advancing state. |
| 158 | ram_clkp = !ram_clkp; | ||
| 159 | state = state.next; | ||
| 160 | end | ||
| 161 | 173 | ||
| 162 | DATA_1, DATA_2: begin | 174 | DATA_1, DATA_2: begin |
| 163 | ram_clkp = !ram_clkp; | ||
| 164 | if (write) begin | 175 | if (write) begin |
| 165 | ram_rwds_oe = 1; | 176 | ram_rwds_oe = 1; |
| 166 | ram_rwds_out = 1; | 177 | ram_rwds_out = 1; |
| 167 | ram_data_oe = 1; | 178 | ram_data_oe = 1; |
| 168 | ram_data_out = data[7:0]; | 179 | ram_data_out = data[7:0]; |
| 169 | data = data >> 8; | 180 | data = data >> 8; |
| 170 | state = state.next; | ||
| 171 | end else if (ram_rwds_in) begin | 181 | end else if (ram_rwds_in) begin |
| 172 | data = data << 8; | 182 | data = data << 8; |
| 173 | data[7:0] = ram_data_in; | 183 | data[7:0] = ram_data_in; |
| 174 | state = state.next; | 184 | end else begin |
| 185 | stall = 1; | ||
| 175 | end | 186 | end |
| 176 | end | 187 | end |
| 177 | 188 | ||
| 178 | endcase | 189 | endcase |
| 179 | if (state == state.first) begin | 190 | if (!stall) begin |
| 180 | valid = 0; | 191 | state = state.next; |
| 181 | if (!write) begin | 192 | if (state == state.first) begin |
| 182 | // We know that this is safe because we don't accept commands unless we have result bandwidth | 193 | valid = 0; |
| 183 | result_valid = 1; | 194 | if (!write) begin |
| 184 | result_data = data; | 195 | // We know that this is safe because we don't accept commands unless we have result bandwidth |
| 196 | result_valid = 1; | ||
| 197 | result_data = data; | ||
| 198 | end | ||
| 185 | end | 199 | end |
| 186 | end | 200 | end |
| 187 | end | 201 | end |
