Matt Venn | dfc149e | 2022-11-24 16:39:10 +0100 | [diff] [blame] | 1 | ///////////////////////////////////////////////////////////////////////////
|
| 2 | // M0 - 16-bit serial SUBLEQ processor
|
| 3 | //
|
| 4 | // Copyright 2022 William Moyes
|
| 5 | //
|
| 6 | // The M0 is a 16-bit, bit serial microprocessor based upon the SUBLEQ
|
| 7 | // architecture. The only external devices needed for operation are a SPI
|
| 8 | // RAM, SPI ROM, and clock source. The entire ROM and RAM are available for
|
| 9 | // user code. All registers and logic are contained within the M0 itself.
|
| 10 | // A transmit UART is included for serial output.
|
| 11 | //
|
| 12 | // See README.md at https://github.com/moyesw/TT02-M0/blob/main/README.md
|
| 13 | // for more information on the M0 architecture.
|
| 14 | //
|
| 15 | // The M0 microarchitecture
|
| 16 | // --------------------------
|
| 17 | // PC - Program counter shift register
|
| 18 | // ADR - Address shift register
|
| 19 | // TMP - Temporary shift register
|
| 20 | //
|
| 21 | // The M0 has a six phase exeuction sequence. Each phase performs
|
| 22 | // one 16-bit access to the SPI bus:
|
| 23 | // Phase 0: ADR <-- mem[PC++]
|
| 24 | // Phase 1: TMP <-- mem[ADR]
|
| 25 | // Phase 2: ADR <-- mem[PC++]
|
| 26 | // Phase 3: TMP <-- mem[ADR] - TMP ;checks if result <= 0
|
| 27 | // Phase 4: mem[ADR] <-- TMP
|
| 28 | // Phase 5: PC <-- mem[PC++] or PC++
|
| 29 | //
|
| 30 |
|
| 31 | `default_nettype none
|
| 32 | `timescale 100us/10ps
|
| 33 |
|
| 34 |
|
| 35 | ///////////////////////////////////////////////////////////////////////////
|
| 36 | // SPI Controller
|
| 37 | //
|
| 38 | // 16-bit Address + 16-bit Data controller and timing generator
|
| 39 | //
|
| 40 | module SPIController (
|
| 41 | // System Interfaces
|
| 42 | input wire clk,
|
| 43 | input wire rst,
|
| 44 |
|
| 45 | // SPI Bus Interfaces
|
| 46 | output reg CS0,
|
| 47 | output reg CS1,
|
| 48 | output reg SPICLK,
|
| 49 | output reg MOSI,
|
| 50 | input wire MISO,
|
| 51 |
|
| 52 | // Input Signals
|
| 53 | input wire Addr15, // Sampled on Phase 01
|
| 54 | input wire Read_notWrite, // Sampled on Phase 16
|
| 55 | input wire Addr, // Sampled on Phase 18[bit0/LSB], 20[bit1], ..., 44[bit13], 46[bit14/MSB], bit 15 not sampled (see Addr15)
|
| 56 | input wire Data, // Sampled on Phase 50[bit0/LSB], 52[bit1], ..., 78[bit14], 80[bit15/MSB]
|
| 57 |
|
| 58 |
|
| 59 | // Timing Output Signals
|
| 60 | output reg ShiftAddr, // Asserted when the Address should be shifted
|
| 61 | output reg ShiftDataRead, // Asserted when the data register collecting data read from memory should be shifted
|
| 62 | output reg ShiftDataWrite, // Asserted when the data regsiter providing data to be written to memory should be shifted
|
| 63 | output reg PresetCarry, // Asserted the clock before data motion starts
|
| 64 | output reg EndOfPhase, //
|
| 65 | output reg PrepOutput
|
| 66 | );
|
| 67 |
|
| 68 | // SPI sequencer
|
| 69 | reg [6:0] SPIphase;
|
| 70 | always @(posedge clk) begin
|
| 71 | if (rst)
|
| 72 | SPIphase <= 0;
|
| 73 | else if (SPIphase == 83)
|
| 74 | SPIphase <= 0;
|
| 75 | else
|
| 76 | SPIphase <= SPIphase + 1;
|
| 77 | end
|
| 78 |
|
| 79 | // SPI bus signal generator
|
| 80 | always @(posedge clk) begin
|
| 81 | if (SPIphase <= 1) begin
|
| 82 | CS0 <= 1;
|
| 83 | CS1 <= 1;
|
| 84 | SPICLK <= 0;
|
| 85 | MOSI <= 0;
|
| 86 | end else begin
|
| 87 | CS0 <= CSreg;
|
| 88 | CS1 <= !CSreg;
|
| 89 | if (SPIphase <= 81)
|
| 90 | SPICLK <= SPIphase[0];
|
| 91 | else
|
| 92 | SPICLK <= 0;
|
| 93 |
|
| 94 | if (SPIphase <= 13)
|
| 95 | MOSI <= 0;
|
| 96 | else if (SPIphase <= 15)
|
| 97 | MOSI <= 1;
|
| 98 | else if (SPIphase <= 17) begin
|
| 99 | if (SPIphase[0] == 0)
|
| 100 | MOSI <= Read_notWrite;
|
| 101 | end else if (SPIphase <= 47) begin
|
| 102 | if (SPIphase[0] == 0)
|
| 103 | MOSI <= Addr;
|
| 104 | end else if (SPIphase <= 49)
|
| 105 | MOSI <= 0;
|
| 106 | else begin
|
| 107 | if (Read_notWrite)
|
| 108 | MOSI <= 0;
|
| 109 | else begin
|
| 110 | if (SPIphase[0] == 0)
|
| 111 | MOSI <= Data;
|
| 112 | end
|
| 113 | end
|
| 114 | end
|
| 115 | end
|
| 116 |
|
| 117 | // Generate Address Shift Enable Signals
|
| 118 | always @(posedge clk) begin
|
| 119 | ShiftAddr <= ((SPIphase >= 18) && (SPIphase <= 48) && (SPIphase[0] == 0));
|
| 120 | ShiftDataRead <= ((SPIphase >= 51) && (SPIphase <= 81) && (SPIphase[0] == 1) && Read_notWrite);
|
| 121 | ShiftDataWrite <= ((SPIphase >= 50) && (SPIphase <= 80) && (SPIphase[0] == 0) && !Read_notWrite);
|
| 122 | PresetCarry <= (SPIphase == 17);
|
| 123 | EndOfPhase <= (SPIphase == 83);
|
| 124 | PrepOutput <= (SPIphase == 49);
|
| 125 | end
|
| 126 |
|
| 127 | reg CSreg;
|
| 128 | always @(posedge clk) begin
|
| 129 | if (SPIphase == 1)
|
| 130 | CSreg <= Addr15;
|
| 131 | end
|
| 132 |
|
| 133 | endmodule
|
| 134 |
|
| 135 |
|
| 136 |
|
| 137 | ///////////////////////////////////////////////////////////////////////////
|
| 138 | // M0 top level
|
| 139 | //
|
| 140 | module moyes0_top_module (
|
| 141 | input [7:0] io_in,
|
| 142 | output [7:0] io_out
|
| 143 | );
|
| 144 |
|
| 145 | // --- ASIC Inputs ---
|
| 146 | wire clk = io_in[0]; // System clock (~6000 Hz)
|
| 147 | wire rst = io_in[1]; // Reset line, active high
|
| 148 | wire spi_miso= io_in[2]; // SPI bus, ASIC input, target output
|
| 149 | wire uart_rx = io_in[3]; // Serial port, ASIC Receive
|
| 150 | wire in4 = io_in[4];
|
| 151 | wire in5 = io_in[5];
|
| 152 | wire in6 = io_in[6];
|
| 153 | wire in7 = io_in[7];
|
| 154 |
|
| 155 | // --- ASIC Outputs ---
|
| 156 | wire spi_cs0;
|
| 157 | wire spi_cs1;
|
| 158 | wire spi_clk;
|
| 159 | wire spi_mosi;
|
| 160 | wire uart_tx;
|
| 161 | wire out5;
|
| 162 | wire out6;
|
| 163 | wire out7;
|
| 164 |
|
| 165 | wire [7:0] io_out;
|
| 166 | assign io_out[0] = spi_cs0; // SPI bus, Chip Select for RAM, Words 0000-7FFF
|
| 167 | assign io_out[1] = spi_cs1; // SPI bus, Chip Select for ROM, Words 8000-FFFF
|
| 168 | assign io_out[2] = spi_clk; // SPI bus, Clock
|
| 169 | assign io_out[3] = spi_mosi; // SPI bus, ASIC output, target input
|
| 170 | assign io_out[4] = uart_tx; // Serial port, ASIC Transmit
|
| 171 | assign io_out[5] = out5;
|
| 172 | assign io_out[6] = out6;
|
| 173 | assign io_out[7] = out7;
|
| 174 |
|
| 175 | // --- Internal Timing Signals ---
|
| 176 | wire ShiftAddr;
|
| 177 | wire ShiftDataRead;
|
| 178 | wire ShiftDataWrite;
|
| 179 | wire PresetCarry;
|
| 180 | wire EndOfPhase;
|
| 181 | wire PrepOutput;
|
| 182 |
|
| 183 | // --- SPI Control Signals
|
| 184 | wire Addr15;
|
| 185 | wire Read_notWrite;
|
| 186 | wire SPIAddr;
|
| 187 | wire SPIDataIn;
|
| 188 |
|
| 189 | // --- CPU Registers ---
|
| 190 | reg [15:0] PC;
|
| 191 | reg [15:0] TMP;
|
| 192 | reg [15:0] ADR;
|
| 193 | reg PCCarry;
|
| 194 | reg TBorrow;
|
| 195 | reg TZero;
|
| 196 | reg LEQ;
|
| 197 |
|
| 198 | assign out7 = !in7; // For bring-up testing, out7 = !in7. No other internal connections
|
| 199 |
|
| 200 | SPIController spi (
|
| 201 | // System Interfaces
|
| 202 | .clk(clk),
|
| 203 | .rst(rst),
|
| 204 |
|
| 205 | // SPI Bus Interfaces
|
| 206 | .CS0(spi_cs0),
|
| 207 | .CS1(spi_cs1),
|
| 208 | .SPICLK(spi_clk),
|
| 209 | .MOSI(spi_mosi),
|
| 210 | .MISO(spi_miso),
|
| 211 |
|
| 212 | // Input Signals
|
| 213 | .Addr15(Addr15),
|
| 214 | .Read_notWrite(Read_notWrite),
|
| 215 | .Addr(SPIAddr),
|
| 216 | .Data(SPIDataIn),
|
| 217 |
|
| 218 | // Timing Output Signals
|
| 219 | .ShiftAddr(ShiftAddr),
|
| 220 | .ShiftDataRead(ShiftDataRead),
|
| 221 | .ShiftDataWrite(ShiftDataWrite),
|
| 222 | .PresetCarry(PresetCarry),
|
| 223 | .EndOfPhase(EndOfPhase),
|
| 224 | .PrepOutput(PrepOutput)
|
| 225 | );
|
| 226 |
|
| 227 | reg [2:0] CPUphase;
|
| 228 | always @(posedge clk) begin
|
| 229 | if (rst)
|
| 230 | CPUphase <= 3'd0;
|
| 231 | else if (!EndOfPhase)
|
| 232 | CPUphase <= CPUphase;
|
| 233 | else begin
|
| 234 | if (CPUphase == 3'd5)
|
| 235 | CPUphase <= 3'd0;
|
| 236 | else
|
| 237 | CPUphase <= CPUphase + 3'd1;
|
| 238 | end
|
| 239 | end
|
| 240 |
|
| 241 | wire PCphase = (CPUphase == 0) || (CPUphase == 2) || (CPUphase == 5);
|
| 242 |
|
| 243 | assign Addr15 = PCphase ? PC[15] : ADR[15];
|
| 244 |
|
| 245 | assign Read_notWrite = (CPUphase != 4);
|
| 246 |
|
| 247 | always @(posedge clk) begin
|
| 248 |
|
| 249 | if (rst)
|
| 250 | PC <= 16'h8000;
|
| 251 | else begin
|
| 252 | if (PresetCarry)
|
| 253 | PCCarry <= 1;
|
| 254 |
|
| 255 | if (PCphase && ShiftAddr) begin
|
| 256 | PCCarry <= PC[0] & PCCarry;
|
| 257 | PC <= {PC[0] ^ PCCarry, PC[15:1]};
|
| 258 | end
|
| 259 |
|
| 260 | if ((CPUphase == 5) && ShiftDataRead) begin
|
| 261 | PC <= {LEQ ? spi_miso : PC[0], PC[15:1]};
|
| 262 | end
|
| 263 | end
|
| 264 | end
|
| 265 |
|
| 266 | assign SPIAddr = PCphase ? PC[0] : ADR[0];
|
| 267 |
|
| 268 | assign SPIDataIn = TMP[0];
|
| 269 |
|
| 270 | wire ReadADR = (CPUphase == 0) || (CPUphase == 2);
|
| 271 | wire ReadTMP = (CPUphase == 1) || (CPUphase == 3);
|
| 272 |
|
| 273 | always @(posedge clk) begin
|
| 274 | if (ReadADR & ShiftDataRead)
|
| 275 | ADR <= {spi_miso, ADR[15:1]};
|
| 276 |
|
| 277 | if (!PCphase & ShiftAddr)
|
| 278 | ADR <= {ADR[0], ADR[15:1]};
|
| 279 | end
|
| 280 |
|
| 281 | // Transmit UART
|
| 282 | reg BwasFFFF;
|
| 283 | reg UARTout;
|
| 284 | assign uart_tx = UARTout;
|
| 285 | reg [4:0] UARTcount;
|
| 286 | always @(posedge clk) begin
|
| 287 | if (EndOfPhase) begin
|
| 288 | BwasFFFF <= 1;
|
| 289 | UARTout <= 1;
|
| 290 | UARTcount <= 0;
|
| 291 | end
|
| 292 |
|
| 293 | if (ShiftAddr & !ADR[0])
|
| 294 | BwasFFFF <= 0;
|
| 295 |
|
| 296 | if (BwasFFFF & (CPUphase == 3)& PrepOutput) begin
|
| 297 | UARTout <= 0;
|
| 298 | UARTcount <= 9;
|
| 299 | end
|
| 300 |
|
| 301 | if ((UARTcount != 0) & ShiftDataRead) begin
|
| 302 | UARTcount <= UARTcount - 1;
|
| 303 | UARTout <= (UARTcount != 1) ? TMP[0] : 1;
|
| 304 | end;
|
| 305 |
|
| 306 | end
|
| 307 |
|
| 308 |
|
| 309 | wire sub_b;
|
| 310 | wire sub_r;
|
| 311 | assign {sub_b, sub_r} = spi_miso - TMP[0] - TBorrow;
|
| 312 |
|
| 313 | always @(posedge clk) begin
|
| 314 | if (PresetCarry) begin
|
| 315 | TBorrow <= 0;
|
| 316 | TZero <= 1;
|
| 317 | end
|
| 318 |
|
| 319 | if ((CPUphase == 1) & ShiftDataRead)
|
| 320 | TMP <= {spi_miso, TMP[15:1]};
|
| 321 |
|
| 322 | if ((CPUphase == 3) & ShiftDataRead) begin
|
| 323 | TBorrow <= sub_b;
|
| 324 | TMP <= {sub_r, TMP[15:1]};
|
| 325 | if (sub_r)
|
| 326 | TZero <= 0;
|
| 327 | end
|
| 328 |
|
| 329 | if (!Read_notWrite & ShiftDataWrite)
|
| 330 | TMP <= {TMP[0], TMP[15:1]};
|
| 331 |
|
| 332 | end
|
| 333 |
|
| 334 | always @(posedge clk) begin
|
| 335 | if (EndOfPhase & (CPUphase == 3)) begin
|
| 336 | LEQ <= TZero | TMP[15];
|
| 337 | end
|
| 338 | end
|
| 339 |
|
| 340 |
|
| 341 |
|
| 342 | endmodule |