From 45c3d234d346e6f4052424c999bbc85313cf80bc Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 28 May 2021 15:53:05 +0200 Subject: [PATCH] Supervision --- .../UltraTank_MiST/rtl/ultratank_mist.sv | 4 +- .../ChannelF_MiST/rtl/ChannelF_MiST.sv | 36 +- Console_MiST/Supervision_MiST/ReadMe.txt | 19 + .../Snapshot/Supervision_MiST.rbf | Bin 0 -> 229296 bytes .../Supervision_MiST/Supervision_MiST.qpf | 30 + .../Supervision_MiST/Supervision_MiST.qsf | 240 +++ Console_MiST/Supervision_MiST/clean.bat | 41 + Console_MiST/Supervision_MiST/rtl/65c02/ALU.v | 108 ++ .../Supervision_MiST/rtl/65c02/README | 67 + Console_MiST/Supervision_MiST/rtl/65c02/cpu.v | 1225 +++++++++++++++ .../Supervision_MiST/rtl/65c02/cpu_65c02.v | 1395 +++++++++++++++++ .../Supervision_MiST/rtl/Supervision_MiST.sv | 232 +++ .../Supervision_MiST/rtl/Supervision_Top.sv | 332 ++++ Console_MiST/Supervision_MiST/rtl/audio.sv | 102 ++ .../Supervision_MiST/rtl/build_id.tcl | 35 + Console_MiST/Supervision_MiST/rtl/dma.sv | 77 + Console_MiST/Supervision_MiST/rtl/pll1.v | 348 ++++ Console_MiST/Supervision_MiST/rtl/pll2.v | 320 ++++ Console_MiST/Supervision_MiST/rtl/ram88.sv | 23 + Console_MiST/Supervision_MiST/rtl/rom.v | 22 + Console_MiST/Supervision_MiST/rtl/sdram.sv | 242 +++ Console_MiST/Supervision_MiST/rtl/video.sv | 88 ++ common/Nibbler.exe | Bin 0 -> 29696 bytes 23 files changed, 4961 insertions(+), 25 deletions(-) create mode 100644 Console_MiST/Supervision_MiST/ReadMe.txt create mode 100644 Console_MiST/Supervision_MiST/Snapshot/Supervision_MiST.rbf create mode 100644 Console_MiST/Supervision_MiST/Supervision_MiST.qpf create mode 100644 Console_MiST/Supervision_MiST/Supervision_MiST.qsf create mode 100644 Console_MiST/Supervision_MiST/clean.bat create mode 100644 Console_MiST/Supervision_MiST/rtl/65c02/ALU.v create mode 100644 Console_MiST/Supervision_MiST/rtl/65c02/README create mode 100644 Console_MiST/Supervision_MiST/rtl/65c02/cpu.v create mode 100644 Console_MiST/Supervision_MiST/rtl/65c02/cpu_65c02.v create mode 100644 Console_MiST/Supervision_MiST/rtl/Supervision_MiST.sv create mode 100644 Console_MiST/Supervision_MiST/rtl/Supervision_Top.sv create mode 100644 Console_MiST/Supervision_MiST/rtl/audio.sv create mode 100644 Console_MiST/Supervision_MiST/rtl/build_id.tcl create mode 100644 Console_MiST/Supervision_MiST/rtl/dma.sv create mode 100644 Console_MiST/Supervision_MiST/rtl/pll1.v create mode 100644 Console_MiST/Supervision_MiST/rtl/pll2.v create mode 100644 Console_MiST/Supervision_MiST/rtl/ram88.sv create mode 100644 Console_MiST/Supervision_MiST/rtl/rom.v create mode 100644 Console_MiST/Supervision_MiST/rtl/sdram.sv create mode 100644 Console_MiST/Supervision_MiST/rtl/video.sv create mode 100644 common/Nibbler.exe diff --git a/Arcade_MiST/Atari BW Raster Hardware/UltraTank_MiST/rtl/ultratank_mist.sv b/Arcade_MiST/Atari BW Raster Hardware/UltraTank_MiST/rtl/ultratank_mist.sv index b26a3099..b9a65be5 100644 --- a/Arcade_MiST/Atari BW Raster Hardware/UltraTank_MiST/rtl/ultratank_mist.sv +++ b/Arcade_MiST/Atari BW Raster Hardware/UltraTank_MiST/rtl/ultratank_mist.sv @@ -102,8 +102,8 @@ ultra_tank ultra_tank ( .Reset_n(~(status[0] | buttons[1])), .HS(hs), .VS(vs), - .HB(vb), - .VB(hb), + .HB(hb), + .VB(vb), .Vid(Vid), .CC3_n_O(), .CC0_O(video_b), diff --git a/Console_MiST/ChannelF_MiST/rtl/ChannelF_MiST.sv b/Console_MiST/ChannelF_MiST/rtl/ChannelF_MiST.sv index efbaf512..3c7a7e51 100644 --- a/Console_MiST/ChannelF_MiST/rtl/ChannelF_MiST.sv +++ b/Console_MiST/ChannelF_MiST/rtl/ChannelF_MiST.sv @@ -28,8 +28,7 @@ localparam CONF_STR = { }; assign LED = ~ioctl_downl; -//assign AUDIO_R = AUDIO_L; - +assign AUDIO_R = AUDIO_L; wire pll_locked,clock_28p636, clk3p579; pll pll( .locked ( pll_locked ), @@ -56,13 +55,14 @@ channel_f channel_f( .ioctl_wr ( ~ioctl_wr ),//todo .ioctl_addr ( ioctl_addr ), .ioctl_dout ( ioctl_dout ), - .ioctl_wait ( ),//todo + .ioctl_wait ( ioctl_wait ),//todo .audio ( audio ) ); wire ioctl_downl; wire [7:0] ioctl_index; wire ioctl_wr; +wire ioctl_wait; wire [24:0] ioctl_addr; wire [7:0] ioctl_dout; @@ -101,11 +101,10 @@ mist_video #(.COLOR_DEPTH(6),.SD_HCNT_WIDTH(10)) mist_video( .no_csync ( no_csync ) ); -wire [31:0] status; +wire [63:0] status; wire [1:0] buttons; wire [1:0] switches; -wire [31:0] joystick_0; -wire [31:0] joystick_1; +wire [31:0] joystick_0, joystick_1; wire scandoublerD; wire [7:0] r, g, b; wire hs, vs, blankn; @@ -138,23 +137,14 @@ user_io( .status ( status ) ); -//dac #( -// .C_bits(16)) -//dac( -// .clk_i ( clock_28p636 ), -// .res_n_i ( 1'b1 ), -// .dac_i ( audio ), -// .dac_o ( AUDIO_L ) -// ); - -mist_audio #(16,0,0) mist_audio( - .clk ( clock_28p636 ), - .reset_n ( 1'b1 ), - .audio_inL ( audio ), -// .audio_inR ( audio ), - .AUDIO_L ( AUDIO_L ), - .AUDIO_R ( AUDIO_R ) -); +dac #( + .C_bits(16)) +dac( + .clk_i ( clock_28p636 ), + .res_n_i ( 1'b1 ), + .dac_i ( audio ), + .dac_o ( AUDIO_L ) + ); wire m_up, m_down, m_left, m_right, m_fireA, m_fireB, m_fireC, m_fireD, m_fireE, m_fireF; wire m_up2, m_down2, m_left2, m_right2, m_fire2A, m_fire2B, m_fire2C, m_fire2D, m_fire2E, m_fire2F; diff --git a/Console_MiST/Supervision_MiST/ReadMe.txt b/Console_MiST/Supervision_MiST/ReadMe.txt new file mode 100644 index 00000000..116c47a4 --- /dev/null +++ b/Console_MiST/Supervision_MiST/ReadMe.txt @@ -0,0 +1,19 @@ +Watara Supervision for MiSTer by Pierre Cornier + + + +wip + +VGA Only + + +Working for Now + +Brain Power +Galactic Crusader +Galaxy Fighter +Happy Pairs +John Advenzure +Kabi Island +Penguin Hideout +Super Kong diff --git a/Console_MiST/Supervision_MiST/Snapshot/Supervision_MiST.rbf b/Console_MiST/Supervision_MiST/Snapshot/Supervision_MiST.rbf new file mode 100644 index 0000000000000000000000000000000000000000..cc2358e082e0dcef0305c2ddcc95b390bed0e73a GIT binary patch literal 229296 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

AK=BVwmwQ~SQ&?GS&UmJZuJ~07X-g#JIg~s?_ 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 3'd5); + +// CO9 is the carry-out bit when doing BCD add +wire CO9 = BCD & (temp_h[3:1] >= 3'd5); + +// combined half carry bit +wire temp_HC = temp_l[4] | HC9; + +// perform the addition as 2 separate nibble, so we get +// access to the half carry flag +always @* begin + temp_l = temp_logic[3:0] + temp_BI[3:0] + adder_CI; + temp_h = temp_logic[8:4] + temp_BI[7:4] + temp_HC; +end + +// calculate the flags +always @(posedge clk) + if( RDY ) begin + AI7 <= AI[7]; + BI7 <= temp_BI[7]; + OUT <= temp[7:0]; + CO <= temp[8] | CO9; + N <= temp[7]; + HC <= temp_HC; + end + +assign V = AI7 ^ BI7 ^ CO ^ N; +assign Z = ~|OUT; + +endmodule diff --git a/Console_MiST/Supervision_MiST/rtl/65c02/README b/Console_MiST/Supervision_MiST/rtl/65c02/README new file mode 100644 index 00000000..dc2056b2 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/65c02/README @@ -0,0 +1,67 @@ +======================================================== +A Verilog HDL version of the old MOS 6502 and 65C02 CPUs +======================================================== + +Original 6502 core by Arlet Ottens + +65C02 extensions by David Banks and Ed Spittles + +========== +6502 Core +========== + +Arlet's original 6502 core (cpu.v) is unchanged. + +Note: the 6502/65C02 cores assumes a synchronous memory. This means +that valid data (DI) is expected on the cycle *after* valid +address. This allows direct connection to (Xilinx) block RAMs. When +using asynchronous memory, I suggest registering the address/control +lines for glitchless output signals. + +Have fun. + +========== +65C02 Core +========== + +A second core (cpu_65c02.v) has been added, based on Arlet's 6502 +core, with additional 65C02 instructions and addressing modes: +- PHX, PHY, PLX, PLY +- BRA +- INC A, DEC A +- (zp) addressing mode +- STZ +- BIT zpx, absx, imm +- TSB/TRB +- JMP (,X) +- NOPs (optional) +- 65C02 BCD N/Z flags (optional, disabled) + +The Rockwell/WDC specific instructions (RMB/SMB/BBR/BBS/WAI/STP) are +not currently implemented + +The 65C02 core passes the Dormann 6502 test suite, and also passes the +Dormann 65C02 test suite if the optional support for NOPs and 65C02 +BCD flags is enabled. + +It has been tested as a BBC Micro "Matchbox" 65C02 Co Processor, in a +XC6SLX9-2 FPGA, running at 80MHz using 64KB of internel block RAM. It +just meets timing at 80MHz in this environment. It successfully runs +BBC Basic IV and Tube Elite. + +============ +Known Issues +============ + +The Matchbox Co Processor needed one wait state (via RDY) to be added +to each ROM access (only needed early in the boot process, as +eventually everything runs from RAM). The DIHOLD logic did not work +correctly with a single wait state, and so has been commented out. + +I now believe the correct fix is actually just: + +always @(posedge clk ) + if( RDY ) + DIHOLD <= DI; + +assign DIMUX = ~RDY ? DIHOLD : DI; diff --git a/Console_MiST/Supervision_MiST/rtl/65c02/cpu.v b/Console_MiST/Supervision_MiST/rtl/65c02/cpu.v new file mode 100644 index 00000000..a08804f4 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/65c02/cpu.v @@ -0,0 +1,1225 @@ +/* + * verilog model of 6502 CPU. + * + * (C) Arlet Ottens, + * + * Feel free to use this code in any project (commercial or not), as long as you + * keep this message, and the copyright notice. This code is provided "as is", + * without any warranties of any kind. + * + */ + +/* + * Note that not all 6502 interface signals are supported (yet). The goal + * is to create an Acorn Atom model, and the Atom didn't use all signals on + * the main board. + * + * The data bus is implemented as separate read/write buses. Combine them + * on the output pads if external memory is required. + */ + +module cpu( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY ); + +input clk; // CPU clock +input reset; // reset signal +output reg [15:0] AB; // address bus +input [7:0] DI; // data in, read bus +output [7:0] DO; // data out, write bus +output WE; // write enable +input IRQ; // interrupt request +input NMI; // non-maskable interrupt request +input RDY; // Ready signal. Pauses CPU when RDY=0 + +/* + * internal signals + */ + +reg [15:0] PC; // Program Counter +reg [7:0] ABL; // Address Bus Register LSB +reg [7:0] ABH; // Address Bus Register MSB +wire [7:0] ADD; // Adder Hold Register (registered in ALU) + +reg [7:0] DIHOLD; // Hold for Data In +reg DIHOLD_valid; // +wire [7:0] DIMUX; // + +reg [7:0] IRHOLD; // Hold for Instruction register +reg IRHOLD_valid; // Valid instruction in IRHOLD + +reg [7:0] AXYS[3:0]; // A, X, Y and S register file + +reg C = 0; // carry flag (init at zero to avoid X's in ALU sim) +reg Z = 0; // zero flag +reg I = 0; // interrupt flag +reg D = 0; // decimal flag +reg V = 0; // overflow flag +reg N = 0; // negative flag +wire AZ; // ALU Zero flag +wire AV; // ALU overflow flag +wire AN; // ALU negative flag +wire HC; // ALU half carry + +reg [7:0] AI; // ALU Input A +reg [7:0] BI; // ALU Input B +wire [7:0] DI; // Data In +wire [7:0] IR; // Instruction register +reg [7:0] DO; // Data Out +reg WE; // Write Enable +reg CI; // Carry In +wire CO; // Carry Out +wire [7:0] PCH = PC[15:8]; +wire [7:0] PCL = PC[7:0]; + +reg NMI_edge = 0; // captured NMI edge + +reg [1:0] regsel; // Select A, X, Y or S register +wire [7:0] regfile = AXYS[regsel]; // Selected register output + +parameter + SEL_A = 2'd0, + SEL_S = 2'd1, + SEL_X = 2'd2, + SEL_Y = 2'd3; + +/* + * define some signals for watching in simulator output + */ + + +`ifdef SIM +wire [7:0] A = AXYS[SEL_A]; // Accumulator +wire [7:0] X = AXYS[SEL_X]; // X register +wire [7:0] Y = AXYS[SEL_Y]; // Y register +wire [7:0] S = AXYS[SEL_S]; // Stack pointer +`endif + +wire [7:0] P = { N, V, 2'b11, D, I, Z, C }; + +/* + * instruction decoder/sequencer + */ + +reg [5:0] state; + +/* + * control signals + */ + +reg PC_inc; // Increment PC +reg [15:0] PC_temp; // intermediate value of PC + +reg [1:0] src_reg; // source register index +reg [1:0] dst_reg; // destination register index + +reg index_y; // if set, then Y is index reg rather than X +reg load_reg; // loading a register (A, X, Y, S) in this instruction +reg inc; // increment +reg write_back; // set if memory is read/modified/written +reg load_only; // LDA/LDX/LDY instruction +reg store; // doing store (STA/STX/STY) +reg adc_sbc; // doing ADC/SBC +reg compare; // doing CMP/CPY/CPX +reg shift; // doing shift/rotate instruction +reg rotate; // doing rotate (no shift) +reg backwards; // backwards branch +reg cond_true; // branch condition is true +reg [2:0] cond_code; // condition code bits from instruction +reg shift_right; // Instruction ALU shift/rotate right +reg alu_shift_right; // Current cycle shift right enable +reg [3:0] op; // Main ALU operation for instruction +reg [3:0] alu_op; // Current cycle ALU operation +reg adc_bcd; // ALU should do BCD style carry +reg adj_bcd; // results should be BCD adjusted + +/* + * some flip flops to remember we're doing special instructions. These + * get loaded at the DECODE state, and used later + */ +reg bit_ins; // doing BIT instruction +reg plp; // doing PLP instruction +reg php; // doing PHP instruction +reg clc; // clear carry +reg sec; // set carry +reg cld; // clear decimal +reg sed; // set decimal +reg cli; // clear interrupt +reg sei; // set interrupt +reg clv; // clear overflow +reg brk; // doing BRK + +reg res; // in reset + +/* + * ALU operations + */ + +parameter + OP_OR = 4'b1100, + OP_AND = 4'b1101, + OP_EOR = 4'b1110, + OP_ADD = 4'b0011, + OP_SUB = 4'b0111, + OP_ROL = 4'b1011, + OP_A = 4'b1111; + +/* + * Microcode state machine. Basically, every addressing mode has its own + * path through the state machine. Additional information, such as the + * operation, source and destination registers are decoded in parallel, and + * kept in separate flops. + */ + +parameter + ABS0 = 6'd0, // ABS - fetch LSB + ABS1 = 6'd1, // ABS - fetch MSB + ABSX0 = 6'd2, // ABS, X - fetch LSB and send to ALU (+X) + ABSX1 = 6'd3, // ABS, X - fetch MSB and send to ALU (+Carry) + ABSX2 = 6'd4, // ABS, X - Wait for ALU (only if needed) + BRA0 = 6'd5, // Branch - fetch offset and send to ALU (+PC[7:0]) + BRA1 = 6'd6, // Branch - fetch opcode, and send PC[15:8] to ALU + BRA2 = 6'd7, // Branch - fetch opcode (if page boundary crossed) + BRK0 = 6'd8, // BRK/IRQ - push PCH, send S to ALU (-1) + BRK1 = 6'd9, // BRK/IRQ - push PCL, send S to ALU (-1) + BRK2 = 6'd10, // BRK/IRQ - push P, send S to ALU (-1) + BRK3 = 6'd11, // BRK/IRQ - write S, and fetch @ fffe + DECODE = 6'd12, // IR is valid, decode instruction, and write prev reg + FETCH = 6'd13, // fetch next opcode, and perform prev ALU op + INDX0 = 6'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X) + INDX1 = 6'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1 + INDX2 = 6'd16, // (ZP,X) - fetch MSB at ZP+X+1 + INDX3 = 6'd17, // (ZP,X) - fetch data + INDY0 = 6'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1) + INDY1 = 6'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y) + INDY2 = 6'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry) + INDY3 = 6'd21, // (ZP),Y) - fetch data (if page boundary crossed) + JMP0 = 6'd22, // JMP - fetch PCL and hold + JMP1 = 6'd23, // JMP - fetch PCH + JMPI0 = 6'd24, // JMP IND - fetch LSB and send to ALU for delay (+0) + JMPI1 = 6'd25, // JMP IND - fetch MSB, proceed with JMP0 state + JSR0 = 6'd26, // JSR - push PCH, save LSB, send S to ALU (-1) + JSR1 = 6'd27, // JSR - push PCL, send S to ALU (-1) + JSR2 = 6'd28, // JSR - write S + JSR3 = 6'd29, // JSR - fetch MSB + PULL0 = 6'd30, // PLP/PLA - save next op in IRHOLD, send S to ALU (+1) + PULL1 = 6'd31, // PLP/PLA - fetch data from stack, write S + PULL2 = 6'd32, // PLP/PLA - prefetch op, but don't increment PC + PUSH0 = 6'd33, // PHP/PHA - send A to ALU (+0) + PUSH1 = 6'd34, // PHP/PHA - write A/P, send S to ALU (-1) + READ = 6'd35, // Read memory for read/modify/write (INC, DEC, shift) + REG = 6'd36, // Read register for reg-reg transfers + RTI0 = 6'd37, // RTI - send S to ALU (+1) + RTI1 = 6'd38, // RTI - read P from stack + RTI2 = 6'd39, // RTI - read PCL from stack + RTI3 = 6'd40, // RTI - read PCH from stack + RTI4 = 6'd41, // RTI - read PCH from stack + RTS0 = 6'd42, // RTS - send S to ALU (+1) + RTS1 = 6'd43, // RTS - read PCL from stack + RTS2 = 6'd44, // RTS - write PCL to ALU, read PCH + RTS3 = 6'd45, // RTS - load PC and increment + WRITE = 6'd46, // Write memory for read/modify/write + ZP0 = 6'd47, // Z-page - fetch ZP address + ZPX0 = 6'd48, // ZP, X - fetch ZP, and send to ALU (+X) + ZPX1 = 6'd49; // ZP, X - load from memory + +`ifdef SIM + +/* + * easy to read names in simulator output + */ +reg [8*6-1:0] statename; + +always @* + case( state ) + DECODE: statename = "DECODE"; + REG: statename = "REG"; + ZP0: statename = "ZP0"; + ZPX0: statename = "ZPX0"; + ZPX1: statename = "ZPX1"; + ABS0: statename = "ABS0"; + ABS1: statename = "ABS1"; + ABSX0: statename = "ABSX0"; + ABSX1: statename = "ABSX1"; + ABSX2: statename = "ABSX2"; + INDX0: statename = "INDX0"; + INDX1: statename = "INDX1"; + INDX2: statename = "INDX2"; + INDX3: statename = "INDX3"; + INDY0: statename = "INDY0"; + INDY1: statename = "INDY1"; + INDY2: statename = "INDY2"; + INDY3: statename = "INDY3"; + READ: statename = "READ"; + WRITE: statename = "WRITE"; + FETCH: statename = "FETCH"; + PUSH0: statename = "PUSH0"; + PUSH1: statename = "PUSH1"; + PULL0: statename = "PULL0"; + PULL1: statename = "PULL1"; + PULL2: statename = "PULL2"; + JSR0: statename = "JSR0"; + JSR1: statename = "JSR1"; + JSR2: statename = "JSR2"; + JSR3: statename = "JSR3"; + RTI0: statename = "RTI0"; + RTI1: statename = "RTI1"; + RTI2: statename = "RTI2"; + RTI3: statename = "RTI3"; + RTI4: statename = "RTI4"; + RTS0: statename = "RTS0"; + RTS1: statename = "RTS1"; + RTS2: statename = "RTS2"; + RTS3: statename = "RTS3"; + BRK0: statename = "BRK0"; + BRK1: statename = "BRK1"; + BRK2: statename = "BRK2"; + BRK3: statename = "BRK3"; + BRA0: statename = "BRA0"; + BRA1: statename = "BRA1"; + BRA2: statename = "BRA2"; + JMP0: statename = "JMP0"; + JMP1: statename = "JMP1"; + JMPI0: statename = "JMPI0"; + JMPI1: statename = "JMPI1"; + endcase + +//always @( PC ) +// $display( "%t, PC:%04x IR:%02x A:%02x X:%02x Y:%02x S:%02x C:%d Z:%d V:%d N:%d P:%02x", $time, PC, IR, A, X, Y, S, C, Z, V, N, P ); + +`endif + + + +/* + * Program Counter Increment/Load. First calculate the base value in + * PC_temp. + */ +always @* + case( state ) + DECODE: if( (~I & IRQ) | NMI_edge ) + PC_temp = { ABH, ABL }; + else + PC_temp = PC; + + + JMP1, + JMPI1, + JSR3, + RTS3, + RTI4: PC_temp = { DIMUX, ADD }; + + BRA1: PC_temp = { ABH, ADD }; + + BRA2: PC_temp = { ADD, PCL }; + + BRK2: PC_temp = res ? 16'hfffc : + NMI_edge ? 16'hfffa : 16'hfffe; + + default: PC_temp = PC; + endcase + +/* + * Determine wether we need PC_temp, or PC_temp + 1 + */ +always @* + case( state ) + DECODE: if( (~I & IRQ) | NMI_edge ) + PC_inc = 0; + else + PC_inc = 1; + + ABS0, + ABSX0, + FETCH, + BRA0, + BRA2, + BRK3, + JMPI1, + JMP1, + RTI4, + RTS3: PC_inc = 1; + + BRA1: PC_inc = CO ^~ backwards; + + default: PC_inc = 0; + endcase + +/* + * Set new PC + */ +always @(posedge clk) + if( RDY ) + PC <= PC_temp + PC_inc; + +/* + * Address Generator + */ + +parameter + ZEROPAGE = 8'h00, + STACKPAGE = 8'h01; + +always @* + case( state ) + ABSX1, + INDX3, + INDY2, + JMP1, + JMPI1, + RTI4, + ABS1: AB = { DIMUX, ADD }; + + BRA2, + INDY3, + ABSX2: AB = { ADD, ABL }; + + BRA1: AB = { ABH, ADD }; + + JSR0, + PUSH1, + RTS0, + RTI0, + BRK0: AB = { STACKPAGE, regfile }; + + BRK1, + JSR1, + PULL1, + RTS1, + RTS2, + RTI1, + RTI2, + RTI3, + BRK2: AB = { STACKPAGE, ADD }; + + INDY1, + INDX1, + ZPX1, + INDX2: AB = { ZEROPAGE, ADD }; + + ZP0, + INDY0: AB = { ZEROPAGE, DIMUX }; + + REG, + READ, + WRITE: AB = { ABH, ABL }; + + default: AB = PC; + endcase + +/* + * ABH/ABL pair is used for registering previous address bus state. + * This can be used to keep the current address, freeing up the original + * source of the address, such as the ALU or DI. + */ +always @(posedge clk) + if( state != PUSH0 && state != PUSH1 && RDY && + state != PULL0 && state != PULL1 && state != PULL2 ) + begin + ABL <= AB[7:0]; + ABH <= AB[15:8]; + end + +/* + * Data Out MUX + */ +always @* + case( state ) + WRITE: DO = ADD; + + JSR0, + BRK0: DO = PCH; + + JSR1, + BRK1: DO = PCL; + + PUSH1: DO = php ? P : ADD; + + BRK2: DO = (IRQ | NMI_edge) ? (P & 8'b1110_1111) : P; + + default: DO = regfile; + endcase + +/* + * Write Enable Generator + */ + +always @* + case( state ) + BRK0, // writing to stack or memory + BRK1, + BRK2, + JSR0, + JSR1, + PUSH1, + WRITE: WE = 1; + + INDX3, // only if doing a STA, STX or STY + INDY3, + ABSX2, + ABS1, + ZPX1, + ZP0: WE = store; + + default: WE = 0; + endcase + +/* + * register file, contains A, X, Y and S (stack pointer) registers. At each + * cycle only 1 of those registers needs to be accessed, so they combined + * in a small memory, saving resources. + */ + +reg write_register; // set when register file is written + +always @* + case( state ) + DECODE: write_register = load_reg & ~plp; + + PULL1, + RTS2, + RTI3, + BRK3, + JSR0, + JSR2 : write_register = 1; + + default: write_register = 0; + endcase + +/* + * BCD adjust logic + */ + +always @(posedge clk) + adj_bcd <= adc_sbc & D; // '1' when doing a BCD instruction + +reg [3:0] ADJL; +reg [3:0] ADJH; + +// adjustment term to be added to ADD[3:0] based on the following +// adj_bcd: '1' if doing ADC/SBC with D=1 +// adc_bcd: '1' if doing ADC with D=1 +// HC : half carry bit from ALU +always @* begin + casex( {adj_bcd, adc_bcd, HC} ) + 3'b0xx: ADJL = 4'd0; // no BCD instruction + 3'b100: ADJL = 4'd10; // SBC, and digital borrow + 3'b101: ADJL = 4'd0; // SBC, but no borrow + 3'b110: ADJL = 4'd0; // ADC, but no carry + 3'b111: ADJL = 4'd6; // ADC, and decimal/digital carry + endcase +end + +// adjustment term to be added to ADD[7:4] based on the following +// adj_bcd: '1' if doing ADC/SBC with D=1 +// adc_bcd: '1' if doing ADC with D=1 +// CO : carry out bit from ALU +always @* begin + casex( {adj_bcd, adc_bcd, CO} ) + 3'b0xx: ADJH = 4'd0; // no BCD instruction + 3'b100: ADJH = 4'd10; // SBC, and digital borrow + 3'b101: ADJH = 4'd0; // SBC, but no borrow + 3'b110: ADJH = 4'd0; // ADC, but no carry + 3'b111: ADJH = 4'd6; // ADC, and decimal/digital carry + endcase +end + +/* + * write to a register. Usually this is the (BCD corrected) output of the + * ALU, but in case of the JSR0 we use the S register to temporarily store + * the PCL. This is possible, because the S register itself is stored in + * the ALU during those cycles. + */ +always @(posedge clk) + if( write_register & RDY ) + AXYS[regsel] <= (state == JSR0) ? DIMUX : { ADD[7:4] + ADJH, ADD[3:0] + ADJL }; + +/* + * register select logic. This determines which of the A, X, Y or + * S registers will be accessed. + */ + +always @* + case( state ) + INDY1, + INDX0, + ZPX0, + ABSX0 : regsel = index_y ? SEL_Y : SEL_X; + + + DECODE : regsel = dst_reg; + + BRK0, + BRK3, + JSR0, + JSR2, + PULL0, + PULL1, + PUSH1, + RTI0, + RTI3, + RTS0, + RTS2 : regsel = SEL_S; + + default: regsel = src_reg; + endcase + +/* + * ALU + */ + +ALU ALU( .clk(clk), + .op(alu_op), + .right(alu_shift_right), + .AI(AI), + .BI(BI), + .CI(CI), + .BCD(adc_bcd & (state == FETCH)), + .CO(CO), + .OUT(ADD), + .V(AV), + .Z(AZ), + .N(AN), + .HC(HC), + .RDY(RDY) ); + +/* + * Select current ALU operation + */ + +always @* + case( state ) + READ: alu_op = op; + + BRA1: alu_op = backwards ? OP_SUB : OP_ADD; + + FETCH, + REG : alu_op = op; + + DECODE, + ABS1: alu_op = 1'bx; + + PUSH1, + BRK0, + BRK1, + BRK2, + JSR0, + JSR1: alu_op = OP_SUB; + + default: alu_op = OP_ADD; + endcase + +/* + * Determine shift right signal to ALU + */ + +always @* + if( state == FETCH || state == REG || state == READ ) + alu_shift_right = shift_right; + else + alu_shift_right = 0; + +/* + * Sign extend branch offset. + */ + +always @(posedge clk) + if( RDY ) + backwards <= DIMUX[7]; + +/* + * ALU A Input MUX + */ + +always @* + case( state ) + JSR1, + RTS1, + RTI1, + RTI2, + BRK1, + BRK2, + INDX1: AI = ADD; + + REG, + ZPX0, + INDX0, + ABSX0, + RTI0, + RTS0, + JSR0, + JSR2, + BRK0, + PULL0, + INDY1, + PUSH0, + PUSH1: AI = regfile; + + BRA0, + READ: AI = DIMUX; + + BRA1: AI = ABH; // don't use PCH in case we're + + FETCH: AI = load_only ? 0 : regfile; + + DECODE, + ABS1: AI = 8'hxx; // don't care + + default: AI = 0; + endcase + + +/* + * ALU B Input mux + */ + +always @* + case( state ) + BRA1, + RTS1, + RTI0, + RTI1, + RTI2, + INDX1, + READ, + REG, + JSR0, + JSR1, + JSR2, + BRK0, + BRK1, + BRK2, + PUSH0, + PUSH1, + PULL0, + RTS0: BI = 8'h00; + + BRA0: BI = PCL; + + DECODE, + ABS1: BI = 8'hxx; + + default: BI = DIMUX; + endcase + +/* + * ALU CI (carry in) mux + */ + +always @* + case( state ) + INDY2, + BRA1, + ABSX1: CI = CO; + + DECODE, + ABS1: CI = 1'bx; + + READ, + REG: CI = rotate ? C : + shift ? 0 : inc; + + FETCH: CI = rotate ? C : + compare ? 1 : + (shift | load_only) ? 0 : C; + + PULL0, + RTI0, + RTI1, + RTI2, + RTS0, + RTS1, + INDY0, + INDX1: CI = 1; + + default: CI = 0; + endcase + +/* + * Processor Status Register update + * + */ + +/* + * Update C flag when doing ADC/SBC, shift/rotate, compare + */ +always @(posedge clk ) + if( shift && state == WRITE ) + C <= CO; + else if( state == RTI2 ) + C <= DIMUX[0]; + else if( ~write_back && state == DECODE ) begin + if( adc_sbc | shift | compare ) + C <= CO; + else if( plp ) + C <= ADD[0]; + else begin + if( sec ) C <= 1; + if( clc ) C <= 0; + end + end + +/* + * Update Z, N flags when writing A, X, Y, Memory, or when doing compare + */ + +always @(posedge clk) + if( state == WRITE ) + Z <= AZ; + else if( state == RTI2 ) + Z <= DIMUX[1]; + else if( state == DECODE ) begin + if( plp ) + Z <= ADD[1]; + else if( (load_reg & (regsel != SEL_S)) | compare | bit_ins ) + Z <= AZ; + end + +always @(posedge clk) + if( state == WRITE ) + N <= AN; + else if( state == RTI2 ) + N <= DIMUX[7]; + else if( state == DECODE ) begin + if( plp ) + N <= ADD[7]; + else if( (load_reg & (regsel != SEL_S)) | compare ) + N <= AN; + end else if( state == FETCH && bit_ins ) + N <= DIMUX[7]; + +/* + * Update I flag + */ + +always @(posedge clk) + if( state == BRK3 ) + I <= 1; + else if( state == RTI2 ) + I <= DIMUX[2]; + else if( state == REG ) begin + if( sei ) I <= 1; + if( cli ) I <= 0; + end else if( state == DECODE ) + if( plp ) I <= ADD[2]; + +/* + * Update D flag + */ +always @(posedge clk ) + if( state == RTI2 ) + D <= DIMUX[3]; + else if( state == DECODE ) begin + if( sed ) D <= 1; + if( cld ) D <= 0; + if( plp ) D <= ADD[3]; + end + +/* + * Update V flag + */ +always @(posedge clk ) + if( state == RTI2 ) + V <= DIMUX[6]; + else if( state == DECODE ) begin + if( adc_sbc ) V <= AV; + if( clv ) V <= 0; + if( plp ) V <= ADD[6]; + end else if( state == FETCH && bit_ins ) + V <= DIMUX[6]; + +/* + * Instruction decoder + */ + +/* + * IR register/mux. Hold previous DI value in IRHOLD in PULL0 and PUSH0 + * states. In these states, the IR has been prefetched, and there is no + * time to read the IR again before the next decode. + */ + +reg RDY1 = 1; + +always @(posedge clk ) + RDY1 <= RDY; + +always @(posedge clk ) + if( ~RDY && RDY1 ) + DIHOLD <= DI; + +always @(posedge clk ) + if( reset ) + IRHOLD_valid <= 0; + else if( RDY ) begin + if( state == PULL0 || state == PUSH0 ) begin + IRHOLD <= DIMUX; + IRHOLD_valid <= 1; + end else if( state == DECODE ) + IRHOLD_valid <= 0; + end + +assign IR = (IRQ & ~I) | NMI_edge ? 8'h00 : + IRHOLD_valid ? IRHOLD : DIMUX; + +assign DIMUX = ~RDY1 ? DIHOLD : DI; + +/* + * Microcode state machine + */ +always @(posedge clk or posedge reset) + if( reset ) + state <= BRK0; + else if( RDY ) case( state ) + DECODE : + casex ( IR ) + 8'b0000_0000: state <= BRK0; + 8'b0010_0000: state <= JSR0; + 8'b0010_1100: state <= ABS0; // BIT abs + 8'b0100_0000: state <= RTI0; // + 8'b0100_1100: state <= JMP0; + 8'b0110_0000: state <= RTS0; + 8'b0110_1100: state <= JMPI0; + 8'b0x00_1000: state <= PUSH0; + 8'b0x10_1000: state <= PULL0; + 8'b0xx1_1000: state <= REG; // CLC, SEC, CLI, SEI + 8'b1xx0_00x0: state <= FETCH; // IMM + 8'b1xx0_1100: state <= ABS0; // X/Y abs + 8'b1xxx_1000: state <= REG; // DEY, TYA, ... + 8'bxxx0_0001: state <= INDX0; + 8'bxxx0_01xx: state <= ZP0; + 8'bxxx0_1001: state <= FETCH; // IMM + 8'bxxx0_1101: state <= ABS0; // even E column + 8'bxxx0_1110: state <= ABS0; // even E column + 8'bxxx1_0000: state <= BRA0; // odd 0 column + 8'bxxx1_0001: state <= INDY0; // odd 1 column + 8'bxxx1_01xx: state <= ZPX0; // odd 4,5,6,7 columns + 8'bxxx1_1001: state <= ABSX0; // odd 9 column + 8'bxxx1_11xx: state <= ABSX0; // odd C, D, E, F columns + 8'bxxxx_1010: state <= REG; // A, TXA, ... NOP + endcase + + ZP0 : state <= write_back ? READ : FETCH; + + ZPX0 : state <= ZPX1; + ZPX1 : state <= write_back ? READ : FETCH; + + ABS0 : state <= ABS1; + ABS1 : state <= write_back ? READ : FETCH; + + ABSX0 : state <= ABSX1; + ABSX1 : state <= (CO | store | write_back) ? ABSX2 : FETCH; + ABSX2 : state <= write_back ? READ : FETCH; + + INDX0 : state <= INDX1; + INDX1 : state <= INDX2; + INDX2 : state <= INDX3; + INDX3 : state <= FETCH; + + INDY0 : state <= INDY1; + INDY1 : state <= INDY2; + INDY2 : state <= (CO | store) ? INDY3 : FETCH; + INDY3 : state <= FETCH; + + READ : state <= WRITE; + WRITE : state <= FETCH; + FETCH : state <= DECODE; + + REG : state <= DECODE; + + PUSH0 : state <= PUSH1; + PUSH1 : state <= DECODE; + + PULL0 : state <= PULL1; + PULL1 : state <= PULL2; + PULL2 : state <= DECODE; + + JSR0 : state <= JSR1; + JSR1 : state <= JSR2; + JSR2 : state <= JSR3; + JSR3 : state <= FETCH; + + RTI0 : state <= RTI1; + RTI1 : state <= RTI2; + RTI2 : state <= RTI3; + RTI3 : state <= RTI4; + RTI4 : state <= DECODE; + + RTS0 : state <= RTS1; + RTS1 : state <= RTS2; + RTS2 : state <= RTS3; + RTS3 : state <= FETCH; + + BRA0 : state <= cond_true ? BRA1 : DECODE; + BRA1 : state <= (CO ^ backwards) ? BRA2 : DECODE; + BRA2 : state <= DECODE; + + JMP0 : state <= JMP1; + JMP1 : state <= DECODE; + + JMPI0 : state <= JMPI1; + JMPI1 : state <= JMP0; + + BRK0 : state <= BRK1; + BRK1 : state <= BRK2; + BRK2 : state <= BRK3; + BRK3 : state <= JMP0; + + endcase + +/* + * Additional control signals + */ + +always @(posedge clk) + if( reset ) + res <= 1; + else if( state == DECODE ) + res <= 0; + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0xx01010, // ASLA, ROLA, LSRA, RORA + 8'b0xxxxx01, // ORA, AND, EOR, ADC + 8'b100x10x0, // DEY, TYA, TXA, TXS + 8'b1010xxx0, // LDA/LDX/LDY + 8'b10111010, // TSX + 8'b1011x1x0, // LDX/LDY + 8'b11001010, // DEX + 8'b1x1xxx01, // LDA, SBC + 8'bxxx01000: // DEY, TAY, INY, INX + load_reg <= 1; + + default: load_reg <= 0; + endcase + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b1110_1000, // INX + 8'b1100_1010, // DEX + 8'b101x_xx10: // LDX, TAX, TSX + dst_reg <= SEL_X; + + 8'b0x00_1000, // PHP, PHA + 8'b1001_1010: // TXS + dst_reg <= SEL_S; + + 8'b1x00_1000, // DEY, DEX + 8'b101x_x100, // LDY + 8'b1010_x000: // LDY #imm, TAY + dst_reg <= SEL_Y; + + default: dst_reg <= SEL_A; + endcase + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b1011_1010: // TSX + src_reg <= SEL_S; + + 8'b100x_x110, // STX + 8'b100x_1x10, // TXA, TXS + 8'b1110_xx00, // INX, CPX + 8'b1100_1010: // DEX + src_reg <= SEL_X; + + 8'b100x_x100, // STY + 8'b1001_1000, // TYA + 8'b1100_xx00, // CPY + 8'b1x00_1000: // DEY, INY + src_reg <= SEL_Y; + + default: src_reg <= SEL_A; + endcase + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'bxxx1_0001, // INDY + 8'b10x1_x110, // LDX/STX zpg/abs, Y + 8'bxxxx_1001: // abs, Y + index_y <= 1; + + default: index_y <= 0; + endcase + + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b100x_x1x0, // STX, STY + 8'b100x_xx01: // STA + store <= 1; + + default: store <= 0; + + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0xxx_x110, // ASL, ROL, LSR, ROR + 8'b11xx_x110: // DEC/INC + write_back <= 1; + + default: write_back <= 0; + endcase + + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b101x_xxxx: // LDA, LDX, LDY + load_only <= 1; + default: load_only <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b111x_x110, // INC + 8'b11x0_1000: // INX, INY + inc <= 1; + + default: inc <= 0; + endcase + +always @(posedge clk ) + if( (state == DECODE || state == BRK0) && RDY ) + casex( IR ) + 8'bx11x_xx01: // SBC, ADC + adc_sbc <= 1; + + default: adc_sbc <= 0; + endcase + +always @(posedge clk ) + if( (state == DECODE || state == BRK0) && RDY ) + casex( IR ) + 8'b011x_xx01: // ADC + adc_bcd <= D; + + default: adc_bcd <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0xxx_x110, // ASL, ROL, LSR, ROR (abs, absx, zpg, zpgx) + 8'b0xxx_1010: // ASL, ROL, LSR, ROR (acc) + shift <= 1; + + default: shift <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b11x0_0x00, // CPX, CPY (imm/zp) + 8'b11x0_1100, // CPX, CPY (abs) + 8'b110x_xx01: // CMP + compare <= 1; + + default: compare <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b01xx_xx10: // ROR, LSR + shift_right <= 1; + + default: shift_right <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0x1x_1010, // ROL A, ROR A + 8'b0x1x_x110: // ROR, ROL + rotate <= 1; + + default: rotate <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b00xx_xx10: // ROL, ASL + op <= OP_ROL; + + 8'b0010_x100: // BIT zp/abs + op <= OP_AND; + + 8'b01xx_xx10: // ROR, LSR + op <= OP_A; + + 8'b1000_1000, // DEY + 8'b1100_1010, // DEX + 8'b110x_x110, // DEC + 8'b11xx_xx01, // CMP, SBC + 8'b11x0_0x00, // CPX, CPY (imm, zpg) + 8'b11x0_1100: op <= OP_SUB; + + 8'b010x_xx01, // EOR + 8'b00xx_xx01: // ORA, AND + op <= { 2'b11, IR[6:5] }; + + default: op <= OP_ADD; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0010_x100: // BIT zp/abs + bit_ins <= 1; + + default: bit_ins <= 0; + endcase + +/* + * special instructions + */ +always @(posedge clk ) + if( state == DECODE && RDY ) begin + php <= (IR == 8'h08); + clc <= (IR == 8'h18); + plp <= (IR == 8'h28); + sec <= (IR == 8'h38); + cli <= (IR == 8'h58); + sei <= (IR == 8'h78); + clv <= (IR == 8'hb8); + cld <= (IR == 8'hd8); + sed <= (IR == 8'hf8); + brk <= (IR == 8'h00); + end + +always @(posedge clk) + if( RDY ) + cond_code <= IR[7:5]; + +always @* + case( cond_code ) + 3'b000: cond_true = ~N; + 3'b001: cond_true = N; + 3'b010: cond_true = ~V; + 3'b011: cond_true = V; + 3'b100: cond_true = ~C; + 3'b101: cond_true = C; + 3'b110: cond_true = ~Z; + 3'b111: cond_true = Z; + endcase + + +reg NMI_1 = 0; // delayed NMI signal + +always @(posedge clk) + NMI_1 <= NMI; + +always @(posedge clk ) + if( NMI_edge && state == BRK3 ) + NMI_edge <= 0; + else if( NMI & ~NMI_1 ) + NMI_edge <= 1; + +endmodule diff --git a/Console_MiST/Supervision_MiST/rtl/65c02/cpu_65c02.v b/Console_MiST/Supervision_MiST/rtl/65c02/cpu_65c02.v new file mode 100644 index 00000000..a0f0c731 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/65c02/cpu_65c02.v @@ -0,0 +1,1395 @@ +/* + * verilog model of 65C02 CPU. + * + * Based on original 6502 "Arlet 6502 Core" by Arlet Ottens + * + * (C) Arlet Ottens, + * + * Feel free to use this code in any project (commercial or not), as long as you + * keep this message, and the copyright notice. This code is provided "as is", + * without any warranties of any kind. + * + * Support for 65C02 instructions and addressing modes by David Banks and Ed Spittles + * + * (C) 2016 David Banks and Ed Spittles + * + * Feel free to use this code in any project (commercial or not), as long as you + * keep this message, and the copyright notice. This code is provided "as is", + * without any warranties of any kind. + * + */ + +/* + * Note that not all 6502 interface signals are supported (yet). The goal + * is to create an Acorn Atom model, and the Atom didn't use all signals on + * the main board. + * + * The data bus is implemented as separate read/write buses. Combine them + * on the output pads if external memory is required. + */ + +/* + * Two things were needed to correctly implement 65C02 NOPs + * 1. Ensure the microcode state machine uses an appropriate addressing mode for the opcode length + * 2. Ensure there are no side-effects (e.g. register updates, memory stores, etc) + * + * If IMPLEMENT_NOPS is defined, the state machine is modified accordingly. + */ + +`define IMPLEMENT_NOPS + +/* + * Two things were needed to correctly implement 65C02 BCD arithmentic + * 1. The Z flag needs calculating over the BCD adjusted ALU output + * 2. The N flag needs calculating over the BCD adjusted ALU output + * + * If IMPLEMENT_CORRECT_BCD_FLAGS is defined, this additional logic is added + */ + +// `define IMPLEMENT_CORRECT_BCD_FLAGS + +module cpu_65c02( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY ); + +input clk; // CPU clock +input reset; // reset signal +output reg [15:0] AB; // address bus +input [7:0] DI; // data in, read bus +output [7:0] DO; // data out, write bus +output WE; // write enable +input IRQ; // interrupt request +input NMI; // non-maskable interrupt request +input RDY; // Ready signal. Pauses CPU when RDY=0 + +/* + * internal signals + */ + +reg [15:0] PC; // Program Counter +reg [7:0] ABL; // Address Bus Register LSB +reg [7:0] ABH; // Address Bus Register MSB +wire [7:0] ADD; // Adder Hold Register (registered in ALU) + +reg [7:0] DIHOLD; // Hold for Data In +reg DIHOLD_valid; // +wire [7:0] DIMUX; // + +reg [7:0] IRHOLD; // Hold for Instruction register +reg IRHOLD_valid; // Valid instruction in IRHOLD + +reg [7:0] AXYS[3:0]; // A, X, Y and S register file + +reg C = 0; // carry flag (init at zero to avoid X's in ALU sim) +reg Z = 0; // zero flag +reg I = 0; // interrupt flag +reg D = 0; // decimal flag +reg V = 0; // overflow flag +reg N = 0; // negative flag +wire AZ; // ALU Zero flag +wire AZ1; // ALU Zero flag (BCD adjusted) +reg AZ2; // ALU Second Zero flag, set using TSB/TRB semantics +wire AV; // ALU overflow flag +wire AN; // ALU negative flag +wire AN1; // ALU negative flag (BCD adjusted) +wire HC; // ALU half carry + +reg [7:0] AI; // ALU Input A +reg [7:0] BI; // ALU Input B +wire [7:0] DI; // Data In +wire [7:0] IR; // Instruction register +reg [7:0] DO; // Data Out +wire [7:0] AO; // ALU output after BCD adjustment +reg WE; // Write Enable +reg CI; // Carry In +wire CO; // Carry Out +wire [7:0] PCH = PC[15:8]; +wire [7:0] PCL = PC[7:0]; + +reg NMI_edge = 0; // captured NMI edge + +reg [1:0] regsel; // Select A, X, Y or S register +wire [7:0] regfile = AXYS[regsel]; // Selected register output + +parameter + SEL_A = 2'd0, + SEL_S = 2'd1, + SEL_X = 2'd2, + SEL_Y = 2'd3; + +/* + * define some signals for watching in simulator output + */ + + +`ifdef SIM +wire [7:0] A = AXYS[SEL_A]; // Accumulator +wire [7:0] X = AXYS[SEL_X]; // X register +wire [7:0] Y = AXYS[SEL_Y]; // Y register +wire [7:0] S = AXYS[SEL_S]; // Stack pointer +`endif + +wire [7:0] P = { N, V, 2'b11, D, I, Z, C }; + +/* + * instruction decoder/sequencer + */ + +reg [5:0] state; + +/* + * control signals + */ + +reg PC_inc; // Increment PC +reg [15:0] PC_temp; // intermediate value of PC + +reg [1:0] src_reg; // source register index +reg [1:0] dst_reg; // destination register index + +reg index_y; // if set, then Y is index reg rather than X +reg load_reg; // loading a register (A, X, Y, S) in this instruction +reg inc; // increment +reg write_back; // set if memory is read/modified/written +reg load_only; // LDA/LDX/LDY instruction +reg store; // doing store (STA/STX/STY) +reg adc_sbc; // doing ADC/SBC +reg compare; // doing CMP/CPY/CPX +reg shift; // doing shift/rotate instruction +reg rotate; // doing rotate (no shift) +reg backwards; // backwards branch +reg cond_true; // branch condition is true +reg [3:0] cond_code; // condition code bits from instruction +reg shift_right; // Instruction ALU shift/rotate right +reg alu_shift_right; // Current cycle shift right enable +reg [3:0] op; // Main ALU operation for instruction +reg [3:0] alu_op; // Current cycle ALU operation +reg adc_bcd; // ALU should do BCD style carry +reg adj_bcd; // results should be BCD adjusted + +/* + * some flip flops to remember we're doing special instructions. These + * get loaded at the DECODE state, and used later + */ +reg store_zero; // doing STZ instruction +reg trb_ins; // doing TRB instruction +reg txb_ins; // doing TSB/TRB instruction +reg bit_ins; // doing BIT instruction +reg bit_ins_nv; // doing BIT instruction that will update the n and v flags (i.e. not BIT imm) +reg plp; // doing PLP instruction +reg php; // doing PHP instruction +reg clc; // clear carry +reg sec; // set carry +reg cld; // clear decimal +reg sed; // set decimal +reg cli; // clear interrupt +reg sei; // set interrupt +reg clv; // clear overflow +reg brk; // doing BRK + +reg res; // in reset + +/* + * ALU operations + */ + +parameter + OP_OR = 4'b1100, + OP_AND = 4'b1101, + OP_EOR = 4'b1110, + OP_ADD = 4'b0011, + OP_SUB = 4'b0111, + OP_ROL = 4'b1011, + OP_A = 4'b1111; + +/* + * Microcode state machine. Basically, every addressing mode has its own + * path through the state machine. Additional information, such as the + * operation, source and destination registers are decoded in parallel, and + * kept in separate flops. + */ + +parameter + ABS0 = 6'd0, // ABS - fetch LSB + ABS1 = 6'd1, // ABS - fetch MSB + ABSX0 = 6'd2, // ABS, X - fetch LSB and send to ALU (+X) + ABSX1 = 6'd3, // ABS, X - fetch MSB and send to ALU (+Carry) + ABSX2 = 6'd4, // ABS, X - Wait for ALU (only if needed) + BRA0 = 6'd5, // Branch - fetch offset and send to ALU (+PC[7:0]) + BRA1 = 6'd6, // Branch - fetch opcode, and send PC[15:8] to ALU + BRA2 = 6'd7, // Branch - fetch opcode (if page boundary crossed) + BRK0 = 6'd8, // BRK/IRQ - push PCH, send S to ALU (-1) + BRK1 = 6'd9, // BRK/IRQ - push PCL, send S to ALU (-1) + BRK2 = 6'd10, // BRK/IRQ - push P, send S to ALU (-1) + BRK3 = 6'd11, // BRK/IRQ - write S, and fetch @ fffe + DECODE = 6'd12, // IR is valid, decode instruction, and write prev reg + FETCH = 6'd13, // fetch next opcode, and perform prev ALU op + INDX0 = 6'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X) + INDX1 = 6'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1 + INDX2 = 6'd16, // (ZP,X) - fetch MSB at ZP+X+1 + INDX3 = 6'd17, // (ZP,X) - fetch data + INDY0 = 6'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1) + INDY1 = 6'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y) + INDY2 = 6'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry) + INDY3 = 6'd21, // (ZP),Y) - fetch data (if page boundary crossed) + JMP0 = 6'd22, // JMP - fetch PCL and hold + JMP1 = 6'd23, // JMP - fetch PCH + JMPI0 = 6'd24, // JMP IND - fetch LSB and send to ALU for delay (+0) + JMPI1 = 6'd25, // JMP IND - fetch MSB, proceed with JMP0 state + JSR0 = 6'd26, // JSR - push PCH, save LSB, send S to ALU (-1) + JSR1 = 6'd27, // JSR - push PCL, send S to ALU (-1) + JSR2 = 6'd28, // JSR - write S + JSR3 = 6'd29, // JSR - fetch MSB + PULL0 = 6'd30, // PLP/PLA/PLX/PLY - save next op in IRHOLD, send S to ALU (+1) + PULL1 = 6'd31, // PLP/PLA/PLX/PLY - fetch data from stack, write S + PULL2 = 6'd32, // PLP/PLA/PLX/PLY - prefetch op, but don't increment PC + PUSH0 = 6'd33, // PHP/PHA/PHX/PHY - send A to ALU (+0) + PUSH1 = 6'd34, // PHP/PHA/PHX/PHY - write A/P, send S to ALU (-1) + READ = 6'd35, // Read memory for read/modify/write (INC, DEC, shift) + REG = 6'd36, // Read register for reg-reg transfers + RTI0 = 6'd37, // RTI - send S to ALU (+1) + RTI1 = 6'd38, // RTI - read P from stack + RTI2 = 6'd39, // RTI - read PCL from stack + RTI3 = 6'd40, // RTI - read PCH from stack + RTI4 = 6'd41, // RTI - read PCH from stack + RTS0 = 6'd42, // RTS - send S to ALU (+1) + RTS1 = 6'd43, // RTS - read PCL from stack + RTS2 = 6'd44, // RTS - write PCL to ALU, read PCH + RTS3 = 6'd45, // RTS - load PC and increment + WRITE = 6'd46, // Write memory for read/modify/write + ZP0 = 6'd47, // Z-page - fetch ZP address + ZPX0 = 6'd48, // ZP, X - fetch ZP, and send to ALU (+X) + ZPX1 = 6'd49, // ZP, X - load from memory + IND0 = 6'd50, // (ZP) - fetch ZP address, and send to ALU (+0) + JMPIX0 = 6'd51, // JMP (,X)- fetch LSB and send to ALU (+X) + JMPIX1 = 6'd52, // JMP (,X)- fetch MSB and send to ALU (+Carry) + JMPIX2 = 6'd53; // JMP (,X)- Wait for ALU (only if needed) + +`ifdef SIM + +/* + * easy to read names in simulator output + */ +reg [8*6-1:0] statename; + +always @* + case( state ) + DECODE: statename = "DECODE"; + REG: statename = "REG"; + ZP0: statename = "ZP0"; + ZPX0: statename = "ZPX0"; + ZPX1: statename = "ZPX1"; + ABS0: statename = "ABS0"; + ABS1: statename = "ABS1"; + ABSX0: statename = "ABSX0"; + ABSX1: statename = "ABSX1"; + ABSX2: statename = "ABSX2"; + IND0: statename = "IND0"; + INDX0: statename = "INDX0"; + INDX1: statename = "INDX1"; + INDX2: statename = "INDX2"; + INDX3: statename = "INDX3"; + INDY0: statename = "INDY0"; + INDY1: statename = "INDY1"; + INDY2: statename = "INDY2"; + INDY3: statename = "INDY3"; + READ: statename = "READ"; + WRITE: statename = "WRITE"; + FETCH: statename = "FETCH"; + PUSH0: statename = "PUSH0"; + PUSH1: statename = "PUSH1"; + PULL0: statename = "PULL0"; + PULL1: statename = "PULL1"; + PULL2: statename = "PULL2"; + JSR0: statename = "JSR0"; + JSR1: statename = "JSR1"; + JSR2: statename = "JSR2"; + JSR3: statename = "JSR3"; + RTI0: statename = "RTI0"; + RTI1: statename = "RTI1"; + RTI2: statename = "RTI2"; + RTI3: statename = "RTI3"; + RTI4: statename = "RTI4"; + RTS0: statename = "RTS0"; + RTS1: statename = "RTS1"; + RTS2: statename = "RTS2"; + RTS3: statename = "RTS3"; + BRK0: statename = "BRK0"; + BRK1: statename = "BRK1"; + BRK2: statename = "BRK2"; + BRK3: statename = "BRK3"; + BRA0: statename = "BRA0"; + BRA1: statename = "BRA1"; + BRA2: statename = "BRA2"; + JMP0: statename = "JMP0"; + JMP1: statename = "JMP1"; + JMPI0: statename = "JMPI0"; + JMPI1: statename = "JMPI1"; + JMPIX0: statename = "JMPIX0"; + JMPIX1: statename = "JMPIX1"; + JMPIX2: statename = "JMPIX2"; + + endcase + +//always @( PC ) +// $display( "%t, PC:%04x IR:%02x A:%02x X:%02x Y:%02x S:%02x C:%d Z:%d V:%d N:%d P:%02x", $time, PC, IR, A, X, Y, S, C, Z, V, N, P ); + +`endif + + + +/* + * Program Counter Increment/Load. First calculate the base value in + * PC_temp. + */ +always @* + case( state ) + DECODE: if( (~I & IRQ) | NMI_edge ) + PC_temp = { ABH, ABL }; + else + PC_temp = PC; + + + JMP1, + JMPI1, + JMPIX1, + JSR3, + RTS3, + RTI4: PC_temp = { DIMUX, ADD }; + + BRA1: PC_temp = { ABH, ADD }; + + JMPIX2, + BRA2: PC_temp = { ADD, PCL }; + + BRK2: PC_temp = res ? 16'hfffc : + NMI_edge ? 16'hfffa : 16'hfffe; + + default: PC_temp = PC; + endcase + +/* + * Determine wether we need PC_temp, or PC_temp + 1 + */ +always @* + case( state ) + DECODE: if( (~I & IRQ) | NMI_edge ) + PC_inc = 0; + else + PC_inc = 1; + + ABS0, + JMPIX0, + JMPIX2, + ABSX0, + FETCH, + BRA0, + BRA2, + BRK3, + JMPI1, + JMP1, + RTI4, + RTS3: PC_inc = 1; + + JMPIX1: PC_inc = ~CO; // Don't increment PC if we are going to go through JMPIX2 + + BRA1: PC_inc = CO ^~ backwards; + + default: PC_inc = 0; + endcase + +/* + * Set new PC + */ +always @(posedge clk) + if( RDY ) + PC <= PC_temp + PC_inc; + +/* + * Address Generator + */ + +parameter + ZEROPAGE = 8'h00, + STACKPAGE = 8'h01; + +always @* + case( state ) + JMPIX1, + ABSX1, + INDX3, + INDY2, + JMP1, + JMPI1, + RTI4, + ABS1: AB = { DIMUX, ADD }; + + BRA2, + INDY3, + JMPIX2, + ABSX2: AB = { ADD, ABL }; + + BRA1: AB = { ABH, ADD }; + + JSR0, + PUSH1, + RTS0, + RTI0, + BRK0: AB = { STACKPAGE, regfile }; + + BRK1, + JSR1, + PULL1, + RTS1, + RTS2, + RTI1, + RTI2, + RTI3, + BRK2: AB = { STACKPAGE, ADD }; + + INDY1, + INDX1, + ZPX1, + INDX2: AB = { ZEROPAGE, ADD }; + + ZP0, + INDY0: AB = { ZEROPAGE, DIMUX }; + + REG, + READ, + WRITE: AB = { ABH, ABL }; + + default: AB = PC; + endcase + +/* + * ABH/ABL pair is used for registering previous address bus state. + * This can be used to keep the current address, freeing up the original + * source of the address, such as the ALU or DI. + */ +always @(posedge clk) + if( state != PUSH0 && state != PUSH1 && RDY && + state != PULL0 && state != PULL1 && state != PULL2 ) + begin + ABL <= AB[7:0]; + ABH <= AB[15:8]; + end + +/* + * Data Out MUX + */ +always @* + case( state ) + WRITE: DO = ADD; + + JSR0, + BRK0: DO = PCH; + + JSR1, + BRK1: DO = PCL; + + PUSH1: DO = php ? P : ADD; + + BRK2: DO = (IRQ | NMI_edge) ? (P & 8'b1110_1111) : P; + + default: DO = store_zero ? 0 : regfile; + endcase + +/* + * Write Enable Generator + */ + +always @* + case( state ) + BRK0, // writing to stack or memory + BRK1, + BRK2, + JSR0, + JSR1, + PUSH1, + WRITE: WE = 1; + + INDX3, // only if doing a STA, STX or STY + INDY3, + ABSX2, + ABS1, + ZPX1, + ZP0: WE = store; + + default: WE = 0; + endcase + +/* + * register file, contains A, X, Y and S (stack pointer) registers. At each + * cycle only 1 of those registers needs to be accessed, so they combined + * in a small memory, saving resources. + */ + +reg write_register; // set when register file is written + +always @* + case( state ) + DECODE: write_register = load_reg & ~plp; + + PULL1, + RTS2, + RTI3, + BRK3, + JSR0, + JSR2 : write_register = 1; + + default: write_register = 0; + endcase + +/* + * BCD adjust logic + */ + +always @(posedge clk) + adj_bcd <= adc_sbc & D; // '1' when doing a BCD instruction + +reg [3:0] ADJL; +reg [3:0] ADJH; + +// adjustment term to be added to ADD[3:0] based on the following +// adj_bcd: '1' if doing ADC/SBC with D=1 +// adc_bcd: '1' if doing ADC with D=1 +// HC : half carry bit from ALU +always @* begin + casex( {adj_bcd, adc_bcd, HC} ) + 3'b0xx: ADJL = 4'd0; // no BCD instruction + 3'b100: ADJL = 4'd10; // SBC, and digital borrow + 3'b101: ADJL = 4'd0; // SBC, but no borrow + 3'b110: ADJL = 4'd0; // ADC, but no carry + 3'b111: ADJL = 4'd6; // ADC, and decimal/digital carry + endcase +end + +// adjustment term to be added to ADD[7:4] based on the following +// adj_bcd: '1' if doing ADC/SBC with D=1 +// adc_bcd: '1' if doing ADC with D=1 +// CO : carry out bit from ALU +always @* begin + casex( {adj_bcd, adc_bcd, CO} ) + 3'b0xx: ADJH = 4'd0; // no BCD instruction + 3'b100: ADJH = 4'd10; // SBC, and digital borrow + 3'b101: ADJH = 4'd0; // SBC, but no borrow + 3'b110: ADJH = 4'd0; // ADC, but no carry + 3'b111: ADJH = 4'd6; // ADC, and decimal/digital carry + endcase +end + +assign AO = { ADD[7:4] + ADJH, ADD[3:0] + ADJL }; + +`ifdef IMPLEMENT_CORRECT_BCD_FLAGS + +assign AN1 = AO[7]; +assign AZ1 = ~|AO; + +`else + +assign AN1 = AN; +assign AZ1 = AZ; + +`endif + +/* + * write to a register. Usually this is the (BCD corrected) output of the + * ALU, but in case of the JSR0 we use the S register to temporarily store + * the PCL. This is possible, because the S register itself is stored in + * the ALU during those cycles. + */ +always @(posedge clk) + if( write_register & RDY ) + AXYS[regsel] <= (state == JSR0) ? DIMUX : AO; + +/* + * register select logic. This determines which of the A, X, Y or + * S registers will be accessed. + */ + +always @* + case( state ) + INDY1, + INDX0, + ZPX0, + JMPIX0, + ABSX0 : regsel = index_y ? SEL_Y : SEL_X; + + + DECODE : regsel = dst_reg; + + BRK0, + BRK3, + JSR0, + JSR2, + PULL0, + PULL1, + PUSH1, + RTI0, + RTI3, + RTS0, + RTS2 : regsel = SEL_S; + + default: regsel = src_reg; + endcase + +/* + * ALU + */ + +ALU ALU( .clk(clk), + .op(alu_op), + .right(alu_shift_right), + .AI(AI), + .BI(BI), + .CI(CI), + .BCD(adc_bcd & (state == FETCH)), + .CO(CO), + .OUT(ADD), + .V(AV), + .Z(AZ), + .N(AN), + .HC(HC), + .RDY(RDY) ); + +/* + * Select current ALU operation + */ + +always @* + case( state ) + READ: alu_op = op; + + BRA1: alu_op = backwards ? OP_SUB : OP_ADD; + + FETCH, + REG : alu_op = op; + + DECODE, + ABS1: alu_op = 1'bx; + + PUSH1, + BRK0, + BRK1, + BRK2, + JSR0, + JSR1: alu_op = OP_SUB; + + default: alu_op = OP_ADD; + endcase + +/* + * Determine shift right signal to ALU + */ + +always @* + if( state == FETCH || state == REG || state == READ ) + alu_shift_right = shift_right; + else + alu_shift_right = 0; + +/* + * Sign extend branch offset. + */ + +always @(posedge clk) + if( RDY ) + backwards <= DIMUX[7]; + +/* + * ALU A Input MUX + */ + +always @* + case( state ) + JSR1, + RTS1, + RTI1, + RTI2, + BRK1, + BRK2, + INDX1: AI = ADD; + + REG, + ZPX0, + INDX0, + JMPIX0, + ABSX0, + RTI0, + RTS0, + JSR0, + JSR2, + BRK0, + PULL0, + INDY1, + PUSH0, + PUSH1: AI = regfile; + + BRA0, + READ: AI = DIMUX; + + BRA1: AI = ABH; // don't use PCH in case we're + + FETCH: AI = load_only ? 0 : regfile; + + DECODE, + ABS1: AI = 8'hxx; // don't care + + default: AI = 0; + endcase + + +/* + * ALU B Input mux + */ + +always @* + case( state ) + BRA1, + RTS1, + RTI0, + RTI1, + RTI2, + INDX1, + REG, + JSR0, + JSR1, + JSR2, + BRK0, + BRK1, + BRK2, + PUSH0, + PUSH1, + PULL0, + RTS0: BI = 8'h00; + + READ: BI = txb_ins ? (trb_ins ? ~regfile : regfile) : 8'h00; + + BRA0: BI = PCL; + + DECODE, + ABS1: BI = 8'hxx; + + default: BI = DIMUX; + endcase + +/* + * ALU CI (carry in) mux + */ + +always @* + case( state ) + INDY2, + BRA1, + JMPIX1, + ABSX1: CI = CO; + + DECODE, + ABS1: CI = 1'bx; + + READ, + REG: CI = rotate ? C : + shift ? 0 : inc; + + FETCH: CI = rotate ? C : + compare ? 1 : + (shift | load_only) ? 0 : C; + + PULL0, + RTI0, + RTI1, + RTI2, + RTS0, + RTS1, + INDY0, + INDX1: CI = 1; + + default: CI = 0; + endcase + +/* + * Processor Status Register update + * + */ + +/* + * Update C flag when doing ADC/SBC, shift/rotate, compare + */ +always @(posedge clk ) + if( shift && state == WRITE ) + C <= CO; + else if( state == RTI2 ) + C <= DIMUX[0]; + else if( ~write_back && state == DECODE ) begin + if( adc_sbc | shift | compare ) + C <= CO; + else if( plp ) + C <= ADD[0]; + else begin + if( sec ) C <= 1; + if( clc ) C <= 0; + end + end + +/* + * Special Z flag got TRB/TSB + */ +always @(posedge clk) + AZ2 <= ~|(AI & regfile); + +/* + * Update Z, N flags when writing A, X, Y, Memory, or when doing compare + */ + +always @(posedge clk) + if( state == WRITE) + Z <= txb_ins ? AZ2 : AZ1; + else if( state == RTI2 ) + Z <= DIMUX[1]; + else if( state == DECODE ) begin + if( plp ) + Z <= ADD[1]; + else if( (load_reg & (regsel != SEL_S)) | compare | bit_ins ) + Z <= AZ1; + end + +always @(posedge clk) + if( state == WRITE && ~txb_ins) + N <= AN1; + else if( state == RTI2 ) + N <= DIMUX[7]; + else if( state == DECODE ) begin + if( plp ) + N <= ADD[7]; + else if( (load_reg & (regsel != SEL_S)) | compare ) + N <= AN1; + end else if( state == FETCH && bit_ins_nv ) + N <= DIMUX[7]; + +/* + * Update I flag + */ + +always @(posedge clk) + if( state == BRK3 ) + I <= 1; + else if( state == RTI2 ) + I <= DIMUX[2]; + else if( state == REG ) begin + if( sei ) I <= 1; + if( cli ) I <= 0; + end else if( state == DECODE ) + if( plp ) I <= ADD[2]; + +/* + * Update D flag + */ +always @(posedge clk ) + if( state == RTI2 ) + D <= DIMUX[3]; + else if( state == DECODE ) begin + if( sed ) D <= 1; + if( cld ) D <= 0; + if( plp ) D <= ADD[3]; + end + +/* + * Update V flag + */ +always @(posedge clk ) + if( state == RTI2 ) + V <= DIMUX[6]; + else if( state == DECODE ) begin + if( adc_sbc ) V <= AV; + if( clv ) V <= 0; + if( plp ) V <= ADD[6]; + end else if( state == FETCH && bit_ins_nv ) + V <= DIMUX[6]; + +/* + * Instruction decoder + */ + +/* + * IR register/mux. Hold previous DI value in IRHOLD in PULL0 and PUSH0 + * states. In these states, the IR has been prefetched, and there is no + * time to read the IR again before the next decode. + */ + +//reg RDY1 = 1; + +//always @(posedge clk ) +// RDY1 <= RDY; + +//always @(posedge clk ) +// if( ~RDY && RDY1 ) +// DIHOLD <= DI; + +always @(posedge clk ) + if( reset ) + IRHOLD_valid <= 0; + else if( RDY ) begin + if( state == PULL0 || state == PUSH0 ) begin + IRHOLD <= DIMUX; + IRHOLD_valid <= 1; + end else if( state == DECODE ) + IRHOLD_valid <= 0; + end + +assign IR = (IRQ & ~I) | NMI_edge ? 8'h00 : + IRHOLD_valid ? IRHOLD : DIMUX; + +//assign DIMUX = ~RDY1 ? DIHOLD : DI; + +assign DIMUX = DI; + +/* + * Microcode state machine + */ +always @(posedge clk or posedge reset) + if( reset ) + state <= BRK0; + else if( RDY ) case( state ) + DECODE : + casex ( IR ) + // TODO Review for simplifications as in verilog the first matching case has priority + 8'b0000_0000: state <= BRK0; + 8'b0010_0000: state <= JSR0; + 8'b0010_1100: state <= ABS0; // BIT abs + 8'b1001_1100: state <= ABS0; // STZ abs + 8'b000x_1100: state <= ABS0; // TSB/TRB + 8'b0100_0000: state <= RTI0; // + 8'b0100_1100: state <= JMP0; + 8'b0110_0000: state <= RTS0; + 8'b0110_1100: state <= JMPI0; + 8'b0111_1100: state <= JMPIX0; +`ifdef IMPLEMENT_NOPS + 8'bxxxx_xx11: state <= REG; // (NOP1: 3/7/B/F column) + 8'bxxx0_0010: state <= FETCH; // (NOP2: 2 column, 4 column handled correctly below) + 8'bx1x1_1100: state <= ABS0; // (NOP3: C column) +`endif + 8'b0x00_1000: state <= PUSH0; + 8'b0x10_1000: state <= PULL0; + 8'b0xx1_1000: state <= REG; // CLC, SEC, CLI, SEI + 8'b11x0_00x0: state <= FETCH; // IMM + 8'b1x10_00x0: state <= FETCH; // IMM + 8'b1xx0_1100: state <= ABS0; // X/Y abs + 8'b1xxx_1000: state <= REG; // DEY, TYA, ... + 8'bxxx0_0001: state <= INDX0; + 8'bxxx1_0010: state <= IND0; // (ZP) odd 2 column + 8'b000x_0100: state <= ZP0; // TSB/TRB + 8'bxxx0_01xx: state <= ZP0; + 8'bxxx0_1001: state <= FETCH; // IMM + 8'bxxx0_1101: state <= ABS0; // even D column + 8'bxxx0_1110: state <= ABS0; // even E column + 8'bxxx1_0000: state <= BRA0; // odd 0 column (Branches) + 8'b1000_0000: state <= BRA0; // BRA + 8'bxxx1_0001: state <= INDY0; // odd 1 column + 8'bxxx1_01xx: state <= ZPX0; // odd 4,5,6,7 columns + 8'bxxx1_1001: state <= ABSX0; // odd 9 column + 8'bx011_1100: state <= ABSX0; // C column BIT (3C), LDY (BC) + 8'bxxx1_11x1: state <= ABSX0; // odd D, F columns + 8'bxxx1_111x: state <= ABSX0; // odd E, F columns + 8'bx101_1010: state <= PUSH0; // PHX/PHY + 8'bx111_1010: state <= PULL0; // PLX/PLY + 8'bx0xx_1010: state <= REG; // A, TXA, ... NOP + 8'bxxx0_1010: state <= REG; // A, TXA, ... NOP + endcase + + ZP0 : state <= write_back ? READ : FETCH; + + ZPX0 : state <= ZPX1; + ZPX1 : state <= write_back ? READ : FETCH; + + ABS0 : state <= ABS1; + ABS1 : state <= write_back ? READ : FETCH; + + ABSX0 : state <= ABSX1; + ABSX1 : state <= (CO | store | write_back) ? ABSX2 : FETCH; + ABSX2 : state <= write_back ? READ : FETCH; + + JMPIX0 : state <= JMPIX1; + JMPIX1 : state <= CO ? JMPIX2 : JMP0; + JMPIX2 : state <= JMP0; + + IND0 : state <= INDX1; + + INDX0 : state <= INDX1; + INDX1 : state <= INDX2; + INDX2 : state <= INDX3; + INDX3 : state <= FETCH; + + INDY0 : state <= INDY1; + INDY1 : state <= INDY2; + INDY2 : state <= (CO | store) ? INDY3 : FETCH; + INDY3 : state <= FETCH; + + READ : state <= WRITE; + WRITE : state <= FETCH; + FETCH : state <= DECODE; + + REG : state <= DECODE; + + PUSH0 : state <= PUSH1; + PUSH1 : state <= DECODE; + + PULL0 : state <= PULL1; + PULL1 : state <= PULL2; + PULL2 : state <= DECODE; + + JSR0 : state <= JSR1; + JSR1 : state <= JSR2; + JSR2 : state <= JSR3; + JSR3 : state <= FETCH; + + RTI0 : state <= RTI1; + RTI1 : state <= RTI2; + RTI2 : state <= RTI3; + RTI3 : state <= RTI4; + RTI4 : state <= DECODE; + + RTS0 : state <= RTS1; + RTS1 : state <= RTS2; + RTS2 : state <= RTS3; + RTS3 : state <= FETCH; + + BRA0 : state <= cond_true ? BRA1 : DECODE; + BRA1 : state <= (CO ^ backwards) ? BRA2 : DECODE; + BRA2 : state <= DECODE; + + JMP0 : state <= JMP1; + JMP1 : state <= DECODE; + + JMPI0 : state <= JMPI1; + JMPI1 : state <= JMP0; + + BRK0 : state <= BRK1; + BRK1 : state <= BRK2; + BRK2 : state <= BRK3; + BRK3 : state <= JMP0; + + endcase + +/* + * Additional control signals + */ + +always @(posedge clk) + if( reset ) + res <= 1; + else if( state == DECODE ) + res <= 0; + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) // DMB: Checked for 65C02 NOP collisions + 8'b0xx1_0010, // ORA, AND, EOR, ADC (zp) + 8'b1x11_0010, // LDA, SBC (zp) + 8'b0xxx_1010, // ASLA, INCA, ROLA, DECA, LSRA, PHY, RORA, PLY + 8'b0xxx_xx01, // ORA, AND, EOR, ADC + 8'b100x_10x0, // DEY, TYA, TXA, TXS + 8'b1010_xxx0, // LDA/LDX/LDY + 8'b1011_1010, // TSX + 8'b1011_x1x0, // LDX/LDY + 8'b1100_1010, // DEX + 8'b11x1_1010, // PHX, PLX + 8'b1x1x_xx01, // LDA, SBC + 8'bxxx0_1000: // PHP, PLP, PHA, PLA, DEY, TAY, INY, INX + load_reg <= 1; + + default: load_reg <= 0; + endcase + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b1110_1000, // INX + 8'b1100_1010, // DEX + 8'b1111_1010, // PLX + 8'b1010_0010, // LDX imm + 8'b101x_x110, // LDX + 8'b101x_1x10: // LDX, TAX, TSX + dst_reg <= SEL_X; + + 8'b0x00_1000, // PHP, PHA + 8'bx101_1010, // PHX, PHY + 8'b1001_1010: // TXS + dst_reg <= SEL_S; + + 8'b1x00_1000, // DEY, DEX + 8'b0111_1010, // PLY + 8'b101x_x100, // LDY + 8'b1010_x000: // LDY #imm, TAY + dst_reg <= SEL_Y; + + default: dst_reg <= SEL_A; + endcase + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b1011_1010: // TSX + src_reg <= SEL_S; + + 8'b100x_x110, // STX + 8'b100x_1x10, // TXA, TXS + 8'b1110_xx00, // INX, CPX + 8'b1101_1010, // PHX + 8'b1100_1010: // DEX + src_reg <= SEL_X; + + 8'b100x_x100, // STY + 8'b1001_1000, // TYA + 8'b1100_xx00, // CPY + 8'b0101_1010, // PHY + 8'b1x00_1000: // DEY, INY + src_reg <= SEL_Y; + + default: src_reg <= SEL_A; + endcase + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'bxxx1_0001, // INDY + 8'b10x1_0110, // LDX zp,Y / STX zp,Y + 8'b1011_1110, // LDX abs,Y + 8'bxxxx_1001: // abs, Y + index_y <= 1; + + default: index_y <= 0; + endcase + + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) // DMB: Checked for 65C02 NOP collisions + 8'b1001_0010, // STA (zp) + 8'b100x_x1x0, // STX, STY, STZ abs, STZ abs,x + 8'b011x_0100, // STZ zp, STZ zp,x + 8'b100x_xx01: // STA + store <= 1; + + default: store <= 0; + + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) // DMB: Checked for 65C02 NOP collisions + 8'b0xxx_x110, // ASL, ROL, LSR, ROR + 8'b000x_x100, // TSB/TRB + 8'b11xx_x110: // DEC/INC + write_back <= 1; + + default: write_back <= 0; + endcase + + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b101x_xxxx: // LDA, LDX, LDY + load_only <= 1; + default: load_only <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0001_1010, // INCA + 8'b111x_x110, // INC + 8'b11x0_1000: // INX, INY + inc <= 1; + + default: inc <= 0; + endcase + +always @(posedge clk ) + if( (state == DECODE || state == BRK0) && RDY ) + casex( IR ) + 8'bx111_0010, // SBC (zp), ADC (zp) + 8'bx11x_xx01: // SBC, ADC + adc_sbc <= 1; + + default: adc_sbc <= 0; + endcase + +always @(posedge clk ) + if( (state == DECODE || state == BRK0) && RDY ) + casex( IR ) + 8'b0111_0010, // ADC (zp) + 8'b011x_xx01: // ADC + adc_bcd <= D; + + default: adc_bcd <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0xxx_x110, // ASL, ROL, LSR, ROR (abs, absx, zpg, zpgx) + 8'b0xx0_1010: // ASL, ROL, LSR, ROR (acc) + shift <= 1; + + default: shift <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b1101_0010, // CMP (zp) + 8'b11x0_0x00, // CPX, CPY (imm/zp) + 8'b11x0_1100, // CPX, CPY (abs) + 8'b110x_xx01: // CMP + compare <= 1; + + default: compare <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b01xx_x110, // ROR, LSR + 8'b01xx_1x10: // ROR, LSR + shift_right <= 1; + + default: shift_right <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0x10_1010, // ROL A, ROR A + 8'b0x1x_x110: // ROR, ROL + rotate <= 1; + + default: rotate <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0000_x100: // TSB + op <= OP_OR; + + 8'b0001_x100: // TRB + op <= OP_AND; + + 8'b00xx_x110, // ROL, ASL + 8'b00x0_1010: // ROL, ASL + op <= OP_ROL; + + 8'b1000_1001, // BIT imm + 8'b001x_x100: // BIT zp/abs/zpx/absx + op <= OP_AND; + + 8'b01xx_x110, // ROR, LSR + 8'b01xx_1x10: // ROR, LSR + op <= OP_A; + + 8'b11x1_0010, // CMP, SBC (zp) + 8'b0011_1010, // DEC A + 8'b1000_1000, // DEY + 8'b1100_1010, // DEX + 8'b110x_x110, // DEC + 8'b11xx_xx01, // CMP, SBC + 8'b11x0_0x00, // CPX, CPY (imm, zpg) + 8'b11x0_1100: op <= OP_SUB; + + 8'b00x1_0010, // ORA, AND (zp) + 8'b0x01_0010, // ORA, EOR (zp) + 8'b010x_xx01, // EOR + 8'b00xx_xx01: // ORA, AND + op <= { 2'b11, IR[6:5] }; + + default: op <= OP_ADD; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b001x_x100: // BIT zp/abs/zpx/absx (update N,V,Z) + {bit_ins, bit_ins_nv} <= 2'b11; + + 8'b1000_1001: // BIT imm (update Z) + {bit_ins, bit_ins_nv} <= 2'b10; + + default: // not a BIT instruction + {bit_ins, bit_ins_nv} <= 2'b00; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b000x_x100: // TRB/TSB + txb_ins <= 1; + + default: txb_ins <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0001_x100: // TRB + trb_ins <= 1; + + default: trb_ins <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b1001_11x0, // STZ abs, STZ abs,x + 8'b011x_0100: // STZ zp, STZ zp,x + store_zero <= 1; + + default: store_zero <= 0; + endcase + +/* + * special instructions + */ +always @(posedge clk ) + if( state == DECODE && RDY ) begin + php <= (IR == 8'h08); + clc <= (IR == 8'h18); + plp <= (IR == 8'h28); + sec <= (IR == 8'h38); + cli <= (IR == 8'h58); + sei <= (IR == 8'h78); + clv <= (IR == 8'hb8); + cld <= (IR == 8'hd8); + sed <= (IR == 8'hf8); + brk <= (IR == 8'h00); + end + +always @(posedge clk) + if( RDY ) + cond_code <= IR[7:4]; + +always @* + case( cond_code ) + 4'b0001: cond_true = ~N; + 4'b0011: cond_true = N; + 4'b0101: cond_true = ~V; + 4'b0111: cond_true = V; + 4'b1001: cond_true = ~C; + 4'b1011: cond_true = C; + 4'b1101: cond_true = ~Z; + 4'b1111: cond_true = Z; + default: cond_true = 1; // BRA is 80 + endcase + + +reg NMI_1 = 0; // delayed NMI signal + +always @(posedge clk) + NMI_1 <= NMI; + +always @(posedge clk ) + if( NMI_edge && state == BRK3 ) + NMI_edge <= 0; + else if( NMI & ~NMI_1 ) + NMI_edge <= 1; + +endmodule diff --git a/Console_MiST/Supervision_MiST/rtl/Supervision_MiST.sv b/Console_MiST/Supervision_MiST/rtl/Supervision_MiST.sv new file mode 100644 index 00000000..23a02ec6 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/Supervision_MiST.sv @@ -0,0 +1,232 @@ +module Supervision_MiST( + output LED, + output [5:0] VGA_R, + output [5:0] VGA_G, + output [5:0] VGA_B, + output VGA_HS, + output VGA_VS, + output AUDIO_L, + output AUDIO_R, + input SPI_SCK, + output SPI_DO, + input SPI_DI, + input SPI_SS2, + input SPI_SS3, + input CONF_DATA0, + input CLOCK_27, + + output [12:0] SDRAM_A, + inout [15:0] SDRAM_DQ, + output SDRAM_DQML, + output SDRAM_DQMH, + output SDRAM_nWE, + output SDRAM_nCAS, + output SDRAM_nRAS, + output SDRAM_nCS, + output [1:0] SDRAM_BA, + output SDRAM_CLK, + output SDRAM_CKE +); + +`include "rtl\build_id.v" + +localparam CONF_STR = { + "SVISION;bin;", +// "O34,Scanlines,Off,25%,50%,75%;", +// "O5,Blending,Off,On;", + "O6,Joyswap,Off,On;", + "O8,Screen Color,Green,White;", + "T0,Reset;", + "V,v1.00.",`BUILD_DATE +}; + +assign LED = ~ioctl_downl; +assign SDRAM_CLK = ~clk_sys; +assign SDRAM_CKE = 1; + +wire clk_sys, clk_vid, clk_cpu, pll_locked; +pll1 pll1( + .inclk0(CLOCK_27), + .c0(clk_sys),//50 + .c1(clk_cpu),// 4 + .locked(pll_locked) + ); + +pll2 pll2( + .inclk0(CLOCK_27), + .c0(clk_vid)// 25.175 + ); + +wire [63:0] status; +wire [1:0] buttons; +wire [1:0] switches; +wire ypbpr; +wire scandoublerD; +wire [3:0] audio_ch1, audio_ch2; +wire hs, vs, hb, vb; +wire blankn = ~(hb | vb); +wire [7:0] r, g, b; +wire key_strobe; +wire key_pressed; +wire [7:0] key_code; +wire [31:0] joystick_0, joystick_1; +wire [15:0] rom_addr; +wire [15:0] rom_do; +wire ioctl_downl; +wire [7:0] ioctl_index; +wire ioctl_wr; +wire [24:0] ioctl_addr; +wire [7:0] ioctl_dout; + +data_io data_io( + .clk_sys ( clk_sys ), + .SPI_SCK ( SPI_SCK ), + .SPI_SS2 ( SPI_SS2 ), + .SPI_DI ( SPI_DI ), + .ioctl_download( ioctl_downl ), + .ioctl_index ( ioctl_index ), + .ioctl_wr ( ioctl_wr ), + .ioctl_addr ( ioctl_addr ), + .ioctl_dout ( ioctl_dout ) +); + +reg port1_req; +sdram sdram( + .*, + .init_n ( pll_locked ), + .clk ( clk_sys ), + + // port1 used for main CPU + .port1_req ( port1_req ), + .port1_ack ( ), + .port1_a ( ioctl_addr[23:1] ), + .port1_ds ( {ioctl_addr[0], ~ioctl_addr[0]} ), + .port1_we ( ioctl_downl ), + .port1_d ( {ioctl_dout, ioctl_dout} ), + .port1_q ( ), + + .cpu1_addr ( ioctl_downl ? 16'hffff : {1'b0, rom_addr[15:1]}), + .cpu1_q ( rom_do ) +); + +always @(posedge clk_sys) begin + reg ioctl_wr_last = 0; + + ioctl_wr_last <= ioctl_wr; + if (ioctl_downl) begin + if (~ioctl_wr_last && ioctl_wr) begin + port1_req <= ~port1_req; + end + end +end + +reg reset = 1; +reg rom_loaded = 0; +always @(posedge clk_sys) begin + reg ioctl_downlD; + ioctl_downlD <= ioctl_downl; + if (ioctl_downlD & ~ioctl_downl) rom_loaded <= 1; + reset <= status[0] | buttons[1] | ~rom_loaded; +end + +Supervision_Top Supervision_Top( + .clk_sys(clk_sys), + .clk_vid(clk_vid), + .clk_cpu(clk_cpu), + .reset(reset), + .hsync(hs), + .vsync(vs), + .hblank(hb), + .vblank(vb), + .white(status[8]), + .red(r), + .green(g), + .blue(b), + .joystick({m_fireA, m_fireB, m_fireC, m_fireD, m_up, m_down, m_left, m_right}), + .audio_ch1(audio_ch1), + .audio_ch2(audio_ch2), + .cpu_rom_addr(rom_addr), + .cpu_rom_data(rom_addr[0] ? rom_do[15:8] : rom_do[7:0]) +); + +mist_video #(.COLOR_DEPTH(6),.SD_HCNT_WIDTH(9)) mist_video( + .clk_sys(clk_vid), + .SPI_SCK(SPI_SCK), + .SPI_SS3(SPI_SS3), + .SPI_DI(SPI_DI), + .R(blankn ? r[7:2] : 0), + .G(blankn ? g[7:2] : 0), + .B(blankn ? b[7:2] : 0), + .HSync(~hs), + .VSync(~vs), + .VGA_R(VGA_R), + .VGA_G(VGA_G), + .VGA_B(VGA_B), + .VGA_VS(VGA_VS), + .VGA_HS(VGA_HS), + .ce_divider(1'b0), + .blend(status[5]), + .scandoubler_disable(1'b1),//scandoublerD), + .scanlines(status[4:3]), + .ypbpr(ypbpr) + ); + +user_io #( + .STRLEN(($size(CONF_STR)>>3))) +user_io( + .clk_sys (clk_sys ), + .conf_str (CONF_STR ), + .SPI_CLK (SPI_SCK ), + .SPI_SS_IO (CONF_DATA0 ), + .SPI_MISO (SPI_DO ), + .SPI_MOSI (SPI_DI ), + .buttons (buttons ), + .switches (switches ), + .scandoubler_disable (scandoublerD ), + .ypbpr (ypbpr ), + .key_strobe (key_strobe ), + .key_pressed (key_pressed ), + .key_code (key_code ), + .joystick_0 (joystick_0 ), + .joystick_1 (joystick_1 ), + .status (status ) + ); + +dac #( + .C_bits(4)) +dac_l( + .clk_i(clk_sys), + .res_n_i(1), + .dac_i(audio_ch2), + .dac_o(AUDIO_L) + ); + +dac #( + .C_bits(4)) +dac_r( + .clk_i(clk_sys), + .res_n_i(1), + .dac_i(audio_ch1), + .dac_o(AUDIO_R) + ); + +wire m_up, m_down, m_left, m_right, m_fireA, m_fireB, m_fireC, m_fireD, m_fireE, m_fireF; +wire m_up2, m_down2, m_left2, m_right2, m_fire2A, m_fire2B, m_fire2C, m_fire2D, m_fire2E, m_fire2F; +wire m_tilt, m_coin1, m_coin2, m_coin3, m_coin4, m_one_player, m_two_players, m_three_players, m_four_players; + +arcade_inputs inputs ( + .clk ( clk_sys ), + .key_strobe ( key_strobe ), + .key_pressed ( key_pressed ), + .key_code ( key_code ), + .joystick_0 ( joystick_0 ), + //.rotate ( rotate ), + //.orientation ( orientation ), + .joyswap ( status[6] ), + .oneplayer ( 1'b1 ), + .controls ( {m_tilt, m_coin4, m_coin3, m_coin2, m_coin1, m_four_players, m_three_players, m_two_players, m_one_player} ), + .player1 ( {m_fireF, m_fireE, m_fireD, m_fireC, m_fireB, m_fireA, m_up, m_down, m_left, m_right} ), + .player2 ( {m_fire2F, m_fire2E, m_fire2D, m_fire2C, m_fire2B, m_fire2A, m_up2, m_down2, m_left2, m_right2} ) +); + +endmodule \ No newline at end of file diff --git a/Console_MiST/Supervision_MiST/rtl/Supervision_Top.sv b/Console_MiST/Supervision_MiST/rtl/Supervision_Top.sv new file mode 100644 index 00000000..b7aafc25 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/Supervision_Top.sv @@ -0,0 +1,332 @@ +module Supervision_Top( + input clk_sys,//50 + input clk_vid,// 25.175 + input clk_cpu,//4 + input reset, + output hsync, + output vsync, + output hblank, + output vblank, + input white, + output [7:0] red, + output [7:0] green, + output [7:0] blue, + output [3:0] audio_ch1, + output [3:0] audio_ch2, + input [7:0] joystick, + output [15:0]cpu_rom_addr, + input [7:0] cpu_rom_data +); + +reg [15:0] nmi_clk; +//wire clk_cpu; +wire nmi = nmi_clk == 0; +always @(posedge clk_cpu) + nmi_clk <= nmi_clk + 16'b1; + +reg [7:0] sys_ctl; +reg [7:0] irq_timer; // 2023 +reg [7:0] irq_status; // 2027 ??????DT 1=expired/finished +reg irq_tim; +reg irq_dma; + +wire [15:0] cpu_addr; +wire [7:0] cpu_dout; +wire [7:0] wram_dout; +wire [7:0] vram_dout; +wire [7:0] rom_dout; +wire [7:0] sys_dout; + +reg [7:0] dma_src_lo; +reg [7:0] dma_src_hi; +reg [7:0] dma_dst_lo; +reg [7:0] dma_dst_hi; +reg [7:0] dma_length; +reg [7:0] dma_ctrl; +wire [7:0] dma_dout; +wire [13:0] dma_addr; +wire dma_busy; +wire dma_sel; +wire dma_write; + +reg [7:0] lcd_xscroll; +reg [7:0] lcd_yscroll; +reg [7:0] lcd_xsize; +reg [7:0] lcd_ysize; +wire [7:0] lcd_din; +wire lcd_pulse; +wire cpu_rdy = ~dma_busy; +wire dma_rdy = ~lcd_pulse; +wire cpu_we; +wire [15:0] lcd_addr; + +reg [7:0] ch1_freq_hi, ch1_freq_low, ch1_length, ch1_vduty; +reg [7:0] ch2_freq_hi, ch2_freq_low, ch2_length, ch2_vduty; +reg [7:0] audio_dma_addr_low, audio_dma_addr_high; +reg [7:0] audio_dma_ctrl, audio_dma_length, audio_dma_trigger; +reg [7:0] noise_ctrl, noise_freq_vol, noise_length; +//wire [3:0] audio_ch1, audio_ch2; + +////////////////////// IRQ ////////////////////////// +reg [13:0] timer_div; + +// irq_tim +always @(posedge clk_sys) + if (sys_ctl[1]) begin // irq enable flag + if (irq_timer == 0 && ~irq_status[0]) irq_tim <= 1; + else if (sys_cs && cpu_we && AB[2:0] == 3'h3 && cpu_dout == 0) irq_tim <= 1; + else irq_tim <= 0; + end + +// irq status +always @(posedge clk_sys) + if (sys_cs && ~cpu_we && AB[2:0] == 3'h4) // write to irq timer ack + irq_status[0] <= 1'b0; + else if (irq_tim) // change status on irq + irq_status[0] <= 1'b1; + +// timer prescaler +always @(posedge clk_cpu) + if (timer_div > 0) + timer_div <= timer_div - 14'b1; + else if (sys_ctl[4]) + timer_div <= 14'h3fff; + else + timer_div <= 14'hff; + +// irq_timer +always @(posedge clk_cpu) + if (sys_cs && cpu_we && AB[2:0] == 3'h3) + irq_timer <= cpu_dout; + else if (timer_div == 0 && irq_timer > 0) + irq_timer <= irq_timer - 8'b1; + + +/////////////////////////// MEMORY MAP ///////////////////// + +// 0000 - 1FFF - WRAM +// 2000 - 202F - CTRL +// 2030 - 3FFF - CTRL - mirrors ?? +// 4000 - 5FFF - VRAM ?? +// 6000 - 7FFF - VRAM - mirrors ?? +// 8000 - BFFF - banks +// C000 - FFFF - last 16k of cartridge + + +wire wram_cs = AB ==? 16'b000x_xxxx_xxxx_xxxx; +wire lcd_cs = AB ==? 16'b0010_0000_0000_0xxx; // match 2000-2007 LCD control registers +wire dma_cs = AB ==? 16'b0010_0000_0000_1xxx; // match 2008-200F DMA control registers +wire snd_cs = AB ==? 16'b0010_0000_0001_xxxx; // match 2010-201F sound registers +wire sys_cs = AB ==? 16'b0010_0000_0010_0xxx; // match 2020-2027 sys registers +wire noi_cs = AB ==? 16'b0010_0000_0010_1xxx; // match 2028-202F sound registers (noise) +wire vram_cs = AB ==? 16'b01xx_xxxx_xxxx_xxxx; +wire rom_cs = AB ==? 16'b1xxx_xxxx_xxxx_xxxx; +wire rom_hi = AB ==? 16'b11xx_xxxx_xxxx_xxxx; + +wire [15:0] AB = dma_busy ? { 2'b0, dma_addr } : cpu_addr; + +reg [7:0] DI; + +wire [7:0] DO = dma_busy ? dma_dout : cpu_dout; +wire wram_we = wram_cs ? dma_busy ? ~dma_write : ~cpu_we : 1'b1; +wire vram_we = vram_cs ? dma_busy ? ~dma_write : ~cpu_we : 1'b1; + +wire [15:0] rom_addr = rom_hi ? AB : { sys_ctl[6:5], AB[13:0] }; + +always @(posedge clk_cpu) + DI <= sys_cs ? sys_dout : + wram_cs ? wram_dout : + vram_cs ? vram_dout : + rom_cs ? rom_dout : 8'hff; + +// write to lcd registers +always @(posedge clk_sys) + if (lcd_cs && cpu_we) begin + case (AB[1:0]) + 2'h0: lcd_xsize <= cpu_dout; + 2'h1: lcd_ysize <= cpu_dout; + 2'h2: lcd_xscroll <= cpu_dout; + 2'h3: lcd_yscroll <= cpu_dout; + endcase + end + +// write to audio registers +always @(posedge clk_sys) + if (snd_cs && cpu_we) begin + case (AB[3:0]) + 4'h0: ch1_freq_low <= cpu_dout; + 4'h1: ch1_freq_hi <= cpu_dout; + 4'h2: ch1_vduty <= cpu_dout; + 4'h3: ch1_length <= cpu_dout; + 4'h4: ch2_freq_low <= cpu_dout; + 4'h5: ch2_freq_hi <= cpu_dout; + 4'h6: ch2_vduty <= cpu_dout; + 4'h7: ch2_length <= cpu_dout; + 4'h8: audio_dma_addr_low <= cpu_dout; + 4'h9: audio_dma_addr_high <= cpu_dout; + 4'ha: audio_dma_length <= cpu_dout; + 4'hb: audio_dma_ctrl <= cpu_dout; + 4'hc: audio_dma_trigger <= cpu_dout; + endcase + end + +// write to noise registers +always @(posedge clk_sys) + if (noi_cs && cpu_we) begin + case (AB[2:0]) + 3'h0: noise_freq_vol <= cpu_dout; + 3'h1: noise_length <= cpu_dout; + 3'h2: noise_ctrl <= cpu_dout; + endcase + end + + +// write to dma registers +always @(posedge clk_sys) + if (dma_cs && cpu_we) + case (AB[2:0]) + 3'h0: dma_src_lo <= cpu_dout; + 3'h1: dma_src_hi <= cpu_dout; + 3'h2: dma_dst_lo <= cpu_dout; + 3'h3: dma_dst_hi <= cpu_dout; + 3'h4: dma_length <= cpu_dout; + 3'h5: dma_ctrl <= cpu_dout; + default: + dma_ctrl <= 8'd0; + endcase + +// write to sys registers +always @(posedge clk_sys) + if (sys_cs && cpu_we) + case (AB[2:0]) + // 3'h3: irq_timer = cpu_dout; + 3'h6: sys_ctl <= cpu_dout; + endcase + +// read sys registers +always @(posedge clk_sys) + if (sys_cs && ~cpu_we) + case (AB[2:0]) + 3'h0: sys_dout <= { + ~joystick[7], + ~joystick[6], + ~joystick[5], + ~joystick[4], + ~joystick[3], + ~joystick[2], + ~joystick[1], + ~joystick[0] + }; + 3'h3: sys_dout <= irq_timer; + 3'h6: sys_dout <= sys_ctl; + endcase + + +//////////////////////////////////////////////// + + +//rom cart( +// .clk(clk_sys), +// .addr(rom_addr), +// .dout(rom_dout), +// .cs(~rom_cs), +// .rom_init(ioctl_download), +// .rom_init_clk(clk_sys), +// .rom_init_address(ioctl_addr), +// .rom_init_data(ioctl_dout) +//); + +assign cpu_rom_addr = rom_addr; +assign rom_dout = cpu_rom_data; + + +ram88 wram( + .clk(clk_sys), + .addr(AB[12:0]), + .din(DO), // <= cpu or dma + .dout(wram_dout), + .we(wram_we), + .cs(~wram_cs) +); + +// dual port ram +ram88 vram( + .clk(clk_sys), + .addr(AB[12:0]), + .din(DO), // <= cpu or dma + .dout(vram_dout), + .addrb(lcd_addr), + .doutb(lcd_din), + .we(vram_we), + .cs(~vram_cs) +); + +dma dma( + .clk(clk_sys), + .rdy(dma_rdy), + .irq_dma(irq_dma), + .ctrl(dma_ctrl), + .src_addr({ dma_src_hi, dma_src_lo }), + .dst_addr({ dma_dst_hi, dma_dst_lo }), + .addr(dma_addr), // => to AB + .din(DI), + .dout(dma_dout), + .length(dma_length), + .busy(dma_busy), + .sel(dma_sel), + .write(dma_write) +); + +audio audio( + .clk(clk_sys), + .CH1_freq({ ch1_freq_hi[2:0], ch1_freq_low }), + .CH1_vduty(ch1_vduty), + .CH1_length(ch1_length), + .CH2_freq({ ch2_freq_hi[2:0], ch2_freq_low }), + .CH2_vduty(ch2_vduty), + .CH2_length(ch2_length), + .DMA_addr({ audio_dma_addr_high, audio_dma_addr_low }), + .DMA_length(audio_dma_length), + .DMA_ctrl(audio_dma_ctrl), + .DMA_trigger(audio_dma_trigger), + .noise_freq_vol(noise_freq_vol), + .noise_length(noise_length), + .noise_ctrl(noise_ctrl), + .CH1(audio_ch1), + .CH2(audio_ch2) +); + +video video( + .clk(clk_vid), + .ce(sys_ctl[3]), + .white(white), + .lcd_xsize(lcd_xsize), + .lcd_ysize(lcd_ysize), + .lcd_xscroll(lcd_xscroll), + .lcd_yscroll(lcd_yscroll), + .lcd_pulse(lcd_pulse), + .addr(lcd_addr), + .data(lcd_din), + .hsync(hsync), + .vsync(vsync), + .hblank(hblank), + .vblank(vblank), + .red(red), + .green(green), + .blue(blue) +); + +cpu_65c02 cpu( + .clk(clk_cpu), + .reset(reset), + .AB(cpu_addr), + .DI(DI), + .DO(cpu_dout), + .WE(cpu_we), + .IRQ(irq_tim | irq_dma), + .NMI(nmi), + .RDY(cpu_rdy) +); + + +endmodule \ No newline at end of file diff --git a/Console_MiST/Supervision_MiST/rtl/audio.sv b/Console_MiST/Supervision_MiST/rtl/audio.sv new file mode 100644 index 00000000..87272f63 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/audio.sv @@ -0,0 +1,102 @@ + +module audio ( + input clk, // clk_sys + + input [9:0] CH1_freq, + input [7:0] CH1_vduty, + input [7:0] CH1_length, + + input [9:0] CH2_freq, + input [7:0] CH2_vduty, + input [7:0] CH2_length, + + input [7:0] DMA_addr, + input [7:0] DMA_length, + input [7:0] DMA_ctrl, + input [7:0] DMA_trigger, + + input [7:0] noise_freq_vol, + input [7:0] noise_length, + input [7:0] noise_ctrl, + + output [3:0] CH1, + output [3:0] CH2 +); + + + +reg [23:0] clk_cnt; +reg pulse; +reg clk_audio; +reg [15:0] prescaler; +reg prescaler_overflow; + +// 50000/125=400/2=200 2^24/200=83886 +always @(posedge clk) + { pulse, clk_cnt } <= clk_cnt + 24'd83886; + +always @(posedge pulse) + clk_audio <= ~clk_audio; + +always @(posedge clk) + { prescaler_overflow, prescaler } <= prescaler + 16'd1; + +reg [16:0] CH1_sum, CH2_sum; +reg [16:0] CH1_dc, CH2_dc; // duty cycle +reg CH1_sw, CH2_sw; // square wave +reg [7:0] CH1_dlength, CH2_dlength, CH1_timer, CH2_timer; + +wire [3:0] CH1_out = CH1_sw ? CH1_vduty[3:0] : 4'd0; +wire [3:0] CH2_out = CH2_sw ? CH2_vduty[3:0] : 4'd0; +wire CH1_en = CH1_timer || CH1_vduty[6] ? 1'b1 : 1'b0; +wire CH2_en = CH2_timer || CH2_vduty[6] ? 1'b1 : 1'b0; +assign CH1 = CH1_en ? CH1_out : 4'd0; +assign CH2 = CH2_en ? CH2_out : 4'd0; + +always @(posedge clk) begin + if (prescaler_overflow && CH1_timer > 8'd0) CH1_timer <= CH1_timer - 8'd1; + if (prescaler_overflow && CH2_timer > 8'd0) CH2_timer <= CH2_length - 8'd1; + if (CH1_dlength != CH1_length) begin + CH1_dlength <= CH1_length; + CH1_timer <= CH1_length; + end + if (CH2_dlength != CH2_length) begin + CH2_dlength <= CH2_length; + CH2_timer <= CH2_length; + end +end + +always @* + case (CH1_vduty[5:4]) + 2'b00: CH1_dc = 17'd15240; // 12.5% + 2'b01: CH1_dc = 17'd31750; // 25% + 2'b10: CH1_dc = 17'd63500; // 50% + 2'b11: CH1_dc = 17'd95250; // 75% + endcase + +always @* + case (CH2_vduty[5:4]) + 2'b00: CH2_dc = 17'd15240; // 12.5% + 2'b01: CH2_dc = 17'd31750; // 25% + 2'b10: CH2_dc = 17'd63500; // 50% + 2'b11: CH2_dc = 17'd95250; // 75% + endcase + +always @(posedge clk_audio) begin + CH1_sum <= CH1_sum + { 7'd0, CH1_freq }; + if (CH1_sum >= CH1_dc) begin + CH1_sum <= 17'd0; + CH1_sw = ~CH1_sw; + end +end + +always @(posedge clk_audio) begin + CH2_sum <= CH2_sum + { 7'd0, CH2_freq }; + if (CH2_sum >= CH2_dc) begin + CH2_sum <= 17'd0; + CH2_sw = ~CH2_sw; + end +end + + +endmodule \ No newline at end of file diff --git a/Console_MiST/Supervision_MiST/rtl/build_id.tcl b/Console_MiST/Supervision_MiST/rtl/build_id.tcl new file mode 100644 index 00000000..938515d8 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/build_id.tcl @@ -0,0 +1,35 @@ +# ================================================================================ +# +# Build ID Verilog Module Script +# Jeff Wiencrot - 8/1/2011 +# +# Generates a Verilog module that contains a timestamp, +# from the current build. These values are available from the build_date, build_time, +# physical_address, and host_name output ports of the build_id module in the build_id.v +# Verilog source file. +# +# ================================================================================ + +proc generateBuildID_Verilog {} { + + # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html) + set buildDate [ clock format [ clock seconds ] -format %y%m%d ] + set buildTime [ clock format [ clock seconds ] -format %H%M%S ] + + # Create a Verilog file for output + set outputFileName "rtl/build_id.v" + set outputFile [open $outputFileName "w"] + + # Output the Verilog source + puts $outputFile "`define BUILD_DATE \"$buildDate\"" + puts $outputFile "`define BUILD_TIME \"$buildTime\"" + close $outputFile + + # Send confirmation message to the Messages window + post_message "Generated build identification Verilog module: [pwd]/$outputFileName" + post_message "Date: $buildDate" + post_message "Time: $buildTime" +} + +# Comment out this line to prevent the process from automatically executing when the file is sourced: +generateBuildID_Verilog \ No newline at end of file diff --git a/Console_MiST/Supervision_MiST/rtl/dma.sv b/Console_MiST/Supervision_MiST/rtl/dma.sv new file mode 100644 index 00000000..b7d861b1 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/dma.sv @@ -0,0 +1,77 @@ + +module dma( + input clk, // 4 x CPU speed ? + input rdy, + output irq_dma, + input [7:0] ctrl, + input [15:0] src_addr, + input [15:0] dst_addr, + output reg [15:0] addr, + input [7:0] din, + output reg [7:0] dout, + input [7:0] length, + output busy, + output sel, // 1: src -> dst, 2: src <- dst + output write +); + +reg [11:0] queue; +reg [12:0] addr_a, addr_b; +reg started; +assign irq_dma = 1'b1; + +assign sel = dst_addr[14]; +assign busy = state != DONE; +assign write = state == WRITE; +reg [1:0] state; + +parameter + DONE = 2'b00, + START = 2'b01, + READ = 2'b10, + WRITE = 2'b11; + +always @(posedge clk) + started <= ctrl[7] ? 1'b1 : 1'b0; + +always @(posedge clk) + if (rdy) + case (state) + DONE: if (~started & ctrl[7]) state <= START; + START: state <= READ; + READ: state <= WRITE; + WRITE: state <= queue == 0 ? DONE : READ; + endcase + +always @(posedge clk) + if (rdy) + case (state) + START: queue <= { length, 4'd0 }; + WRITE: queue <= queue - 12'b1; + endcase + +always @(posedge clk) + if (rdy) + case (state) + READ: addr <= addr_a; + WRITE: addr <= addr_b; + endcase + +always @(posedge clk) + if (rdy && state == WRITE) dout <= din; + +always @(posedge clk) + if (rdy) + case (state) + START: begin + addr_a <= sel ? src_addr[12:0] : dst_addr[12:0]; + addr_b <= sel ? dst_addr[12:0] : src_addr[12:0]; + end + WRITE: begin + addr_a <= addr_a + 13'b1; + addr_b <= addr_b + 13'b1; + end + endcase + + +endmodule \ No newline at end of file diff --git a/Console_MiST/Supervision_MiST/rtl/pll1.v b/Console_MiST/Supervision_MiST/rtl/pll1.v new file mode 100644 index 00000000..bfd5fd25 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/pll1.v @@ -0,0 +1,348 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: pll1.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 SJ Full Version +// ************************************************************ + + +//Copyright (C) 1991-2014 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module pll1 ( + areset, + inclk0, + c0, + c1, + locked); + + input areset; + input inclk0; + output c0; + output c1; + output locked; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri0 areset; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [4:0] sub_wire0; + wire sub_wire2; + wire [0:0] sub_wire6 = 1'h0; + wire [0:0] sub_wire3 = sub_wire0[0:0]; + wire [1:1] sub_wire1 = sub_wire0[1:1]; + wire c1 = sub_wire1; + wire locked = sub_wire2; + wire c0 = sub_wire3; + wire sub_wire4 = inclk0; + wire [1:0] sub_wire5 = {sub_wire6, sub_wire4}; + + altpll altpll_component ( + .areset (areset), + .inclk (sub_wire5), + .clk (sub_wire0), + .locked (sub_wire2), + .activeclock (), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.bandwidth_type = "AUTO", + altpll_component.clk0_divide_by = 9, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 20, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 27, + altpll_component.clk1_duty_cycle = 50, + altpll_component.clk1_multiply_by = 4, + altpll_component.clk1_phase_shift = "0", + altpll_component.compensate_clock = "CLK0", + altpll_component.inclk0_input_frequency = 37037, + altpll_component.intended_device_family = "Cyclone III", + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll1", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.pll_type = "AUTO", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_USED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_USED", + altpll_component.port_clk2 = "PORT_UNUSED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.self_reset_on_loss_lock = "OFF", + altpll_component.width_clock = 5; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "9" +// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "27" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "60.000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "4.000000" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "27.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "ps" +// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +// Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "20" +// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "4" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "60.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "4.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif" +// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +// Retrieval info: PRIVATE: SPREAD_USE STRING "0" +// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_CLK0 STRING "1" +// Retrieval info: PRIVATE: USE_CLK1 STRING "1" +// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "9" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "20" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "27" +// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "4" +// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +// Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +// Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +// Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +// Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +// Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +// Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +// Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL pll1.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll1.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll1.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll1.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll1.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll1_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll1_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/Console_MiST/Supervision_MiST/rtl/pll2.v b/Console_MiST/Supervision_MiST/rtl/pll2.v new file mode 100644 index 00000000..5e1278ec --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/pll2.v @@ -0,0 +1,320 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: pll2.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 SJ Full Version +// ************************************************************ + + +//Copyright (C) 1991-2014 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module pll2 ( + areset, + inclk0, + c0, + locked); + + input areset; + input inclk0; + output c0; + output locked; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri0 areset; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire sub_wire0; + wire [4:0] sub_wire1; + wire [0:0] sub_wire5 = 1'h0; + wire locked = sub_wire0; + wire [0:0] sub_wire2 = sub_wire1[0:0]; + wire c0 = sub_wire2; + wire sub_wire3 = inclk0; + wire [1:0] sub_wire4 = {sub_wire5, sub_wire3}; + + altpll altpll_component ( + .areset (areset), + .inclk (sub_wire4), + .locked (sub_wire0), + .clk (sub_wire1), + .activeclock (), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.bandwidth_type = "AUTO", + altpll_component.clk0_divide_by = 44, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 41, + altpll_component.clk0_phase_shift = "0", + altpll_component.compensate_clock = "CLK0", + altpll_component.inclk0_input_frequency = 37037, + altpll_component.intended_device_family = "Cyclone III", + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll2", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.pll_type = "AUTO", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_USED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_UNUSED", + altpll_component.port_clk2 = "PORT_UNUSED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.self_reset_on_loss_lock = "OFF", + altpll_component.width_clock = 5; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "44" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "25.159090" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "27.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "41" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "25.17500000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif" +// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +// Retrieval info: PRIVATE: SPREAD_USE STRING "0" +// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_CLK0 STRING "1" +// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "44" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "41" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +// Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +// Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +// Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +// Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +// Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL pll2.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll2.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll2.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll2.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll2.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll2_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll2_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/Console_MiST/Supervision_MiST/rtl/ram88.sv b/Console_MiST/Supervision_MiST/rtl/ram88.sv new file mode 100644 index 00000000..9fd41d6e --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/ram88.sv @@ -0,0 +1,23 @@ + +module ram88 ( + input clk, + input [12:0] addr, + input [12:0] addrb, + input [7:0] din, + input we, + input cs, + output reg [7:0] dout, + output reg [7:0] doutb +); + +reg [7:0] memory[8191:0] /*verilator public_flat_rd*/; + +always @(posedge clk) begin + if (~cs) begin + if (~we) memory[addr] <= din; + dout <= memory[addr]; + end + doutb <= memory[addrb]; +end + +endmodule \ No newline at end of file diff --git a/Console_MiST/Supervision_MiST/rtl/rom.v b/Console_MiST/Supervision_MiST/rtl/rom.v new file mode 100644 index 00000000..05de1290 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/rom.v @@ -0,0 +1,22 @@ + +module rom ( + input clk, + input [15:0] addr, + output reg [7:0] dout, + input cs, + input rom_init, + input rom_init_clk, + input [15:0] rom_init_address, + input [7:0] rom_init_data +); + +reg [7:0] memory[65535:0]; + +always @(posedge clk) + if (~cs) dout <= memory[addr]; + +always @(posedge rom_init_clk) + if (rom_init) + memory[rom_init_address] <= rom_init_data; + +endmodule diff --git a/Console_MiST/Supervision_MiST/rtl/sdram.sv b/Console_MiST/Supervision_MiST/rtl/sdram.sv new file mode 100644 index 00000000..d616184c --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/sdram.sv @@ -0,0 +1,242 @@ +// +// sdram.v +// +// sdram controller implementation for the MiST board +// https://github.com/mist-devel/mist-board +// +// Copyright (c) 2013 Till Harbaum +// Copyright (c) 2019 Gyorgy Szombathelyi +// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +module sdram ( + + // interface to the MT48LC16M16 chip + inout reg [15:0] SDRAM_DQ, // 16 bit bidirectional data bus + output reg [12:0] SDRAM_A, // 13 bit multiplexed address bus + output reg SDRAM_DQML, // two byte masks + output reg SDRAM_DQMH, // two byte masks + output reg [1:0] SDRAM_BA, // two banks + output SDRAM_nCS, // a single chip select + output SDRAM_nWE, // write enable + output SDRAM_nRAS, // row address select + output SDRAM_nCAS, // columns address select + + // cpu/chipset interface + input init_n, // init signal after FPGA config to initialize RAM + input clk, // sdram clock + + input port1_req, + output reg port1_ack, + input port1_we, + input [23:1] port1_a, + input [1:0] port1_ds, + input [15:0] port1_d, + output [15:0] port1_q, + + input [17:1] cpu1_addr, + output reg [15:0] cpu1_q +); + +parameter MHZ = 80; // 80 MHz default clock, adjust to calculate the refresh rate correctly + +localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 2 cycles@<100MHz +localparam BURST_LENGTH = 3'b000; // 000=1, 001=2, 010=4, 011=8 +localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved +localparam CAS_LATENCY = 3'd2; // 2/3 allowed +localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed +localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write + +localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH}; + +// 64ms/8192 rows = 7.8us -> 842 cycles@108MHz +localparam RFRSH_CYCLES = 16'd78*MHZ/10; + +// --------------------------------------------------------------------- +// ------------------------ cycle state machine ------------------------ +// --------------------------------------------------------------------- + +/* + SDRAM state machine + 1 word burst, CL2 +cmd issued registered + 0 RAS0 data ready + 1 + 2 CAS0 + 3 + 4 + 5 DATA0 +*/ + +localparam STATE_RAS0 = 3'd0; // first state in cycle +localparam STATE_CAS0 = STATE_RAS0 + RASCAS_DELAY; // CAS phase - 2 +localparam STATE_READ0 = 3'd0; //STATE_CAS0 + CAS_LATENCY + 2'd2; // 6 +localparam STATE_LAST = 3'd5; + +reg [2:0] t; + +always @(posedge clk) begin + t <= t + 1'd1; + if (t == STATE_LAST) t <= STATE_RAS0; +end + +// --------------------------------------------------------------------- +// --------------------------- startup/reset --------------------------- +// --------------------------------------------------------------------- + +// wait 1ms (32 8Mhz cycles) after FPGA config is done before going +// into normal operation. Initialize the ram in the last 16 reset cycles (cycles 15-0) +reg [4:0] reset; +reg init = 1'b1; +always @(posedge clk, negedge init_n) begin + if(!init_n) begin + reset <= 5'h1f; + init <= 1'b1; + end else begin + if((t == STATE_LAST) && (reset != 0)) reset <= reset - 5'd1; + init <= !(reset == 0); + end +end + +// --------------------------------------------------------------------- +// ------------------ generate ram control signals --------------------- +// --------------------------------------------------------------------- + +// all possible commands +localparam CMD_INHIBIT = 4'b1111; +localparam CMD_NOP = 4'b0111; +localparam CMD_ACTIVE = 4'b0011; +localparam CMD_READ = 4'b0101; +localparam CMD_WRITE = 4'b0100; +localparam CMD_BURST_TERMINATE = 4'b0110; +localparam CMD_PRECHARGE = 4'b0010; +localparam CMD_AUTO_REFRESH = 4'b0001; +localparam CMD_LOAD_MODE = 4'b0000; + +reg [3:0] sd_cmd; // current command sent to sd ram +reg [15:0] sd_din; +// drive control signals according to current command +assign SDRAM_nCS = sd_cmd[3]; +assign SDRAM_nRAS = sd_cmd[2]; +assign SDRAM_nCAS = sd_cmd[1]; +assign SDRAM_nWE = sd_cmd[0]; + +reg [24:1] addr_latch; +reg [24:1] addr_latch_next; +reg [17:1] addr_last; +reg [15:0] din_latch; +reg oe_latch; +reg we_latch; +reg [1:0] ds; + +localparam PORT_NONE = 2'd0; +localparam PORT_CPU1 = 2'd1; +localparam PORT_REQ = 2'd2; + +reg [2:0] next_port; +reg [2:0] port; +reg port1_state; + +// PORT1 +always @(*) begin + if (port1_req ^ port1_state) begin + next_port = PORT_REQ; + addr_latch_next = { 1'b0, port1_a }; + end else if (cpu1_addr != addr_last) begin + next_port = PORT_CPU1; + addr_latch_next = { 7'd0, cpu1_addr }; + end else begin + next_port = PORT_NONE; + addr_latch_next = addr_latch; + end +end + +always @(posedge clk) begin + + // permanently latch ram data to reduce delays + sd_din <= SDRAM_DQ; + SDRAM_DQ <= 16'bZZZZZZZZZZZZZZZZ; + { SDRAM_DQMH, SDRAM_DQML } <= 2'b11; + sd_cmd <= CMD_NOP; // default: idle + + if(init) begin + // initialization takes place at the end of the reset phase + if(t == STATE_RAS0) begin + + if(reset == 15) begin + sd_cmd <= CMD_PRECHARGE; + SDRAM_A[10] <= 1'b1; // precharge all banks + end + + if(reset == 10 || reset == 8) begin + sd_cmd <= CMD_AUTO_REFRESH; + end + + if(reset == 2) begin + sd_cmd <= CMD_LOAD_MODE; + SDRAM_A <= MODE; + SDRAM_BA <= 2'b00; + end + end + end else begin + // RAS phase + if(t == STATE_RAS0) begin + addr_latch <= addr_latch_next; + port <= next_port; + { oe_latch, we_latch } <= 2'b00; + + if (next_port != PORT_NONE) begin + sd_cmd <= CMD_ACTIVE; + SDRAM_A <= addr_latch_next[22:10]; + SDRAM_BA <= addr_latch_next[24:23]; + if (next_port == PORT_REQ) begin + { oe_latch, we_latch } <= { ~port1_we, port1_we }; + ds <= port1_ds; + din_latch <= port1_d; + port1_state <= port1_req; + end else begin + { oe_latch, we_latch } <= 2'b10; + ds <= 2'b11; + addr_last <= cpu1_addr; + end + end else begin + sd_cmd <= CMD_AUTO_REFRESH; + end + end + + // CAS phase + if(t == STATE_CAS0 && (we_latch || oe_latch)) begin + sd_cmd <= we_latch?CMD_WRITE:CMD_READ; + { SDRAM_DQMH, SDRAM_DQML } <= ~ds; + if (we_latch) begin + SDRAM_DQ <= din_latch; + port1_ack <= port1_req; + end + SDRAM_A <= { 4'b0010, addr_latch[9:1] }; // auto precharge + SDRAM_BA <= addr_latch[24:23]; + end + + // Data returned + if(t == STATE_READ0 && oe_latch) begin + case(port) + PORT_REQ: begin port1_q <= sd_din; port1_ack <= port1_req; end + PORT_CPU1: begin cpu1_q <= sd_din; end + default: ; + endcase; + end + end +end + +endmodule diff --git a/Console_MiST/Supervision_MiST/rtl/video.sv b/Console_MiST/Supervision_MiST/rtl/video.sv new file mode 100644 index 00000000..d6455949 --- /dev/null +++ b/Console_MiST/Supervision_MiST/rtl/video.sv @@ -0,0 +1,88 @@ + +module video( + + input clk,//vga + input clk7p16,//rgb + output ce_pxl, + input white, + // from lcd ctrl registers + input ce, + input [7:0] lcd_xsize, + input [7:0] lcd_ysize, + input [7:0] lcd_xscroll, + input [7:0] lcd_yscroll, + output lcd_pulse, + + // to/from vram + output [12:0] addr, + input [7:0] data, + + // to vga interface + output hsync, + output vsync, + output hblank, + output vblank, + output reg [7:0] red, + output reg [7:0] green, + output reg [7:0] blue +); + +reg [9:0] hcount; +reg [9:0] vcount; +assign lcd_pulse = ce_pxl; +// VGA industry standard 640x480@60 800 525 31.5 - - 25.2 16 96 48 10 2 33 MHi modelines table +// visible area | front porch back porch +// 640 | 32 < 48 > 112 +assign hsync = ~((hcount >= 672) && (hcount < 720)); +assign vsync = ~((vcount >= 481) && (vcount < 484)); +assign hblank = hcount > 639; +assign vblank = vcount > 479; + + +// convert vga coordinates to lcd coordinates (with borders) +wire [8:0] vgax = hcount < 640 ? hcount[9:1] : 9'd0; // 0 - 319 +wire [8:0] vgay = vcount < 480 ? vcount[9:1] : 9'd0; // 0 - 239 +wire [7:0] lcdx = vgax >= 80 && vgax < 240 ? vgax - 8'd80 : 8'd0; // 0-79(80)|80-239(160)|240-319(80) +wire [7:0] lcdy = vgay >= 40 && vgay < 200 ? vgay - 8'd40 : 8'd0; // 0-39(40)|40-199(160)|200-239(40) + + +// calcul vram address (TODO include xsize, ysize, xscroll[1:0] in calculation) +//assign addr = lcd_yscroll * 8'h30 + lcd_xscroll[7:2] + lcdy * 8'h30 + lcdx[7:2]; +assign addr = lcdy * 8'h30 + lcdx[7:2]; + +assign ce_pxl = hcount[0] == 1; + +// assign colors +wire [2:0] index = { lcdx[1:0], 1'b0 }; + +always @(posedge clk) + if (ce && lcdx != 0 && lcdy != 0) begin + if (ce_pxl) begin + case ({white,data[index+:2]}) + 3'b000: { red, green, blue } <= 24'h87BA6B; + 3'b001: { red, green, blue } <= 24'h6BA378; + 3'b010: { red, green, blue } <= 24'h386B82; + 3'b011: { red, green, blue } <= 24'h384052; + + 3'b100: { red, green, blue } <= 24'hFFFFFF;//white + 3'b101: { red, green, blue } <= 24'hC0C0C0;//silver + 3'b110: { red, green, blue } <= 24'h808080;//gray + 3'b111: { red, green, blue } <= 24'h000000;//black + endcase + end + end + else + { red, green, blue } <= 24'h0; + +always @(posedge clk) begin + hcount <= hcount + 10'd1; + if (hcount == 10'd799) hcount <= 0; +end + +always @(posedge clk) + if (hcount == 10'd799) + vcount <= vcount + 10'd1; + else if (vcount == 10'd509) + vcount <= 0; + +endmodule \ No newline at end of file diff --git a/common/Nibbler.exe b/common/Nibbler.exe new file mode 100644 index 0000000000000000000000000000000000000000..54ee39987e9cc2761f64b56b0421f6f3d546f0e9 GIT binary patch literal 29696 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