mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-02-09 09:41:09 +00:00
506 lines
13 KiB
Systemverilog
506 lines
13 KiB
Systemverilog
`timescale 1ns / 1ps
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// Company: M-x Butterfly
|
|
// Engineer: Peter Pearson
|
|
//
|
|
// Create Date: 10/29/2015 03:59:30 PM
|
|
// Design Name:
|
|
// Module Name: POKEY
|
|
// Project Name:
|
|
// Target Devices:
|
|
// Tool Versions:
|
|
// Description:
|
|
//
|
|
// Dependencies:
|
|
//
|
|
// Revision:
|
|
// Revision 0.01 - File Created
|
|
// Additional Comments:
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
module POKEY
|
|
(
|
|
input logic [7:0] Din,
|
|
output logic [7:0] Dout,
|
|
input logic [3:0] A,
|
|
input logic [7:0] P,
|
|
input logic phi2,
|
|
input logic readHighWriteLow,
|
|
input logic cs0Bar,
|
|
output logic aud,
|
|
output logic [3:0] audio,
|
|
//This clk is the 100 MHz clock, and is not a pin on the POKEY DIP
|
|
input logic clk
|
|
);
|
|
|
|
|
|
logic [7:0] audf1, audf2, audf3, audf4, audc1, audc2, audc3, audc4, audCtl, allPot, skCtl;
|
|
logic [7:0] dataIn, dataOut;
|
|
logic clr;
|
|
logic baseClkWave;
|
|
logic wave15k, pulse15k, wave64k, pulse64k, wave179m, pulse179m;
|
|
logic rand4, rand5, rand17, reduce9;
|
|
logic [7:0] rngRead;
|
|
logic phi2Rising;
|
|
logic [3:0] bypassMask1, bypassMask2, bypassMask3, bypassMask4;
|
|
|
|
//Outputs of the divide-by-N blocks for each channel
|
|
logic [3:0] divOut;
|
|
|
|
//Base clock fed to each channel
|
|
logic [3:0] baseClks;
|
|
|
|
//High pass filter clocks fed to each channel
|
|
logic [3:0] hpfClks;
|
|
|
|
//Output waveform of each channel
|
|
logic [3:0] rawWave;
|
|
|
|
assign clr = (skCtl[1:0] == 2'b00);
|
|
|
|
|
|
// tristateDriver #(8) triDrv(.i(dataOut), .o(D), .en(readHighWriteLow));
|
|
assign dataIn = Din;
|
|
assign Dout = dataOut;
|
|
|
|
|
|
wave15kGen w15k(.clk(clk), .clr(clr), .wave(wave15k), .pulse(pulse15k));
|
|
wave64kGen w64k(.clk(clk), .clr(clr), .wave(wave64k), .pulse(pulse64k));
|
|
wave179mGen w179m(.clk(clk), .clr(clr), .wave(wave179m), .pulse(pulse179m));
|
|
|
|
polyCounter4 pc4(.clk(clk), .pulse179m(pulse179m), .rand4(rand4), .clr(clr));
|
|
polyCounter5 pc5(.clk(clk), .pulse179m(pulse179m), .rand5(rand5), .clr(clr));
|
|
polyCounter17 pc17(.clk(clk), .pulse179m(pulse179m), .reduce9(reduce9), .rand17(rand17), .rngVal(rngRead), .clr(clr));
|
|
|
|
|
|
risingDetector risingPhi(.clk(clk), .clr(clr), .signalIn(phi2), .risingEdge(phi2Rising));
|
|
|
|
|
|
audioChannelDigital channel1(.clk(clk), .clr(clr), .baseClkWave(baseClks[0]), .audf(audf1), .audc(audc1), .rand4(rand4), .rand5(rand5), .rand17(rand17), .hpfClk(hpfClks[0]), .bypassMask(bypassMask1), .rawWave(rawWave[0]), .divOut(divOut[0]));
|
|
audioChannelDigital channel2(.clk(clk), .clr(clr), .baseClkWave(baseClks[1]), .audf(audf2), .audc(audc2), .rand4(rand4), .rand5(rand5), .rand17(rand17), .hpfClk(hpfClks[1]), .bypassMask(bypassMask2), .rawWave(rawWave[1]), .divOut(divOut[1]));
|
|
audioChannelDigital channel3(.clk(clk), .clr(clr), .baseClkWave(baseClks[2]), .audf(audf3), .audc(audc3), .rand4(rand4), .rand5(rand5), .rand17(rand17), .hpfClk(hpfClks[2]), .bypassMask(bypassMask3), .rawWave(rawWave[2]), .divOut(divOut[2]));
|
|
audioChannelDigital channel4(.clk(clk), .clr(clr), .baseClkWave(baseClks[3]), .audf(audf4), .audc(audc4), .rand4(rand4), .rand5(rand5), .rand17(rand17), .hpfClk(hpfClks[3]), .bypassMask(bypassMask4), .rawWave(rawWave[3]), .divOut(divOut[3]));
|
|
|
|
assign audio = {4{aud}};
|
|
volumeMixer finalMix(.clk(clk), .clr(clr), .audc1(audc1), .audc2(audc2), .audc3(audc3), .audc4(audc4), .digitalWave(rawWave), .pwmWave(aud));
|
|
|
|
|
|
assign hpfClks = {{divOut[2]},{divOut[3]},{2'b00}};
|
|
|
|
|
|
//AUDCTL and bypass mask logic
|
|
always_comb
|
|
begin
|
|
reduce9 = audCtl[7];
|
|
|
|
baseClks[0] = (audCtl[6] ? wave179m : baseClkWave);
|
|
baseClks[2] = (audCtl[5] ? wave179m : baseClkWave);
|
|
baseClks[1] = (audCtl[4] ? divOut[0] : baseClkWave);
|
|
baseClks[3] = (audCtl[3] ? divOut[2] : baseClkWave);
|
|
|
|
bypassMask1 = {{audCtl[2]},{3'b000}};
|
|
bypassMask2 = {{audCtl[1]},{3'b000}};
|
|
bypassMask3 = 4'h8;
|
|
bypassMask4 = 4'h8;
|
|
|
|
baseClkWave = (audCtl[0] ? wave15k : wave64k);
|
|
end
|
|
|
|
|
|
always_ff@(posedge clk)
|
|
begin
|
|
if(phi2Rising & !cs0Bar)
|
|
begin
|
|
if(clr)
|
|
begin
|
|
audf1 <= 8'd0;
|
|
audf2 <= 8'd0;
|
|
audf3 <= 8'd0;
|
|
audf4 <= 8'd0;
|
|
audc1 <= 8'd0;
|
|
audc2 <= 8'd0;
|
|
audc3 <= 8'd0;
|
|
audc4 <= 8'd0;
|
|
audCtl <= 8'd0;
|
|
allPot <= 8'd0;
|
|
dataOut <= 8'd0;
|
|
if(!readHighWriteLow & (A == 4'hF))
|
|
begin
|
|
skCtl <= dataIn;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
if(readHighWriteLow)
|
|
begin
|
|
case(A)
|
|
4'h8: dataOut <= allPot;
|
|
4'hA: dataOut <= rngRead;
|
|
endcase
|
|
end
|
|
else
|
|
begin
|
|
case(A)
|
|
4'h0: audf1 <= dataIn;
|
|
4'h1: audc1 <= dataIn;
|
|
4'h2: audf2 <= dataIn;
|
|
4'h3: audc2 <= dataIn;
|
|
4'h4: audf3 <= dataIn;
|
|
4'h5: audc3 <= dataIn;
|
|
4'h6: audf4 <= dataIn;
|
|
4'h7: audc4 <= dataIn;
|
|
4'h8: audCtl <= dataIn;
|
|
4'hB: allPot <= P;
|
|
4'hF: skCtl <= dataIn;
|
|
endcase // case (A)
|
|
end // else: !if(readHighWriteLow)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
endmodule: POKEY
|
|
|
|
module tristateDriver
|
|
#(parameter WIDTH = 8)
|
|
(
|
|
input logic [WIDTH-1:0] i,
|
|
output logic [WIDTH-1:0] o,
|
|
input logic en
|
|
);
|
|
|
|
assign o = (en) ? i : ({WIDTH{1'bz}});
|
|
|
|
endmodule: tristateDriver
|
|
|
|
module volumeMixer
|
|
(
|
|
input logic clk, clr,
|
|
input logic [7:0] audc1, audc2, audc3, audc4,
|
|
input logic [3:0] digitalWave,
|
|
output logic pwmWave
|
|
);
|
|
|
|
logic [5:0] volume;
|
|
logic [5:0] pwmCnt;
|
|
|
|
assign volume =
|
|
((digitalWave[3] | audc4[4]) ? audc4[3:0] : 0) +
|
|
((digitalWave[2] | audc3[4]) ? audc3[3:0] : 0) +
|
|
((digitalWave[1] | audc2[4]) ? audc2[3:0] : 0) +
|
|
((digitalWave[0] | audc1[4]) ? audc1[3:0] : 0);
|
|
|
|
m_counter #(6) pwmClk(.Q(pwmCnt), .D(6'd0), .clk(clk), .clr(clr), .load(1'b0), .en(1'b1), .up(1'b1));
|
|
|
|
assign pwmWave = (pwmCnt < volume);
|
|
|
|
endmodule: volumeMixer
|
|
|
|
module audioChannelDigital
|
|
(
|
|
input logic clk, clr,
|
|
input logic baseClkWave,
|
|
input logic [7:0] audf, audc,
|
|
input logic rand4, rand5, rand17,
|
|
input logic hpfClk,
|
|
input logic [3:0] bypassMask,
|
|
output logic rawWave, divOut, noiseOut, arbDiv2Out
|
|
);
|
|
|
|
|
|
logic noise;
|
|
|
|
logic [3:0] sigIn, sigOut;
|
|
|
|
divideByN stage1(.signalIn(sigIn[0]), .clk(clk), .clr(clr), .N(audf), .signalOut(sigOut[0]));
|
|
noiseGen rng(.rand4(rand4), .rand5(rand5), .rand17(rand17), .noise(noise), .randSel(audc[7:5]));
|
|
randomMixer randMix(.clk(clk), .clr(clr), .randomIn(noise), .signalIn(sigIn[1]), .signalOut(sigOut[1]));
|
|
arbDivBy2 adb2(.clk(clk), .clr(clr), .signalIn(sigIn[2]), .signalOut(sigOut[2]));
|
|
highPassFilter hpf(.hpfClk(hpfClk), .clk(clk), .clr(clr), .inputSignal(sigIn[3]), .outputSignal(sigOut[3]));
|
|
|
|
|
|
assign sigIn[0] = baseClkWave;
|
|
assign sigIn[1] = bypassMask[0] ? sigIn[0] : sigOut[0];
|
|
assign sigIn[2] = bypassMask[1] ? sigIn[1] : sigOut[1];
|
|
assign sigIn[3] = bypassMask[2] ? sigIn[2] : sigOut[2];
|
|
assign rawWave = bypassMask[3] ? sigIn[3] : sigOut[3];
|
|
assign divOut = sigOut[0];
|
|
assign noiseOut = sigOut[1];
|
|
assign arbDiv2Out = sigOut[2];
|
|
|
|
endmodule: audioChannelDigital
|
|
|
|
module highPassFilter
|
|
(
|
|
input logic clk, clr,
|
|
input logic hpfClk,
|
|
input logic inputSignal,
|
|
output logic outputSignal
|
|
);
|
|
|
|
logic ffOut;
|
|
|
|
m_register #(1) filterReg(.Q(ffOut), .D(inputSignal), .clr(clr), .clk(clk), .en(hpfClk));
|
|
assign outputSignal = (inputSignal ^ ffOut);
|
|
|
|
endmodule: highPassFilter
|
|
|
|
|
|
module noiseGen
|
|
(
|
|
input logic rand4, rand5, rand17,
|
|
input logic [2:0] randSel,
|
|
output logic noise
|
|
);
|
|
|
|
always_comb
|
|
begin
|
|
casex(randSel)
|
|
3'b000:
|
|
begin
|
|
noise = rand5 & rand17;
|
|
end
|
|
3'b0?1:
|
|
begin
|
|
noise = rand5;
|
|
end
|
|
3'b010:
|
|
begin
|
|
noise = rand4 & rand5;
|
|
end
|
|
3'b100:
|
|
begin
|
|
noise = rand17;
|
|
end
|
|
3'b1?1:
|
|
begin
|
|
noise = 1'b1;
|
|
end
|
|
3'b110:
|
|
begin
|
|
noise = rand4;
|
|
end
|
|
default:
|
|
begin
|
|
noise = 1'b1;
|
|
end
|
|
endcase // casex (randSel)
|
|
|
|
end
|
|
|
|
|
|
endmodule: noiseGen
|
|
|
|
module edgeDetector
|
|
(
|
|
input logic clk, clr,
|
|
input logic signal,
|
|
output logic edgeFound
|
|
);
|
|
|
|
logic prevSignal;
|
|
|
|
m_register #(1) edgeRegister(.Q(prevSignal), .D(signal), .clk(clk), .clr(clr), .en(1'b1));
|
|
|
|
assign edgeFound = signal ^ prevSignal;
|
|
|
|
endmodule: edgeDetector
|
|
|
|
|
|
module divideByN
|
|
(
|
|
input logic signalIn, clk, clr,
|
|
input logic [7:0] N,
|
|
output logic signalOut
|
|
);
|
|
|
|
logic [7:0] countOut;
|
|
logic rollover, edgeFound;
|
|
|
|
edgeDetector edgeChecker(.clk(clk), .clr(clr), .signal(signalIn), .edgeFound(edgeFound));
|
|
m_counter #(8) divCounter(.D(8'd0), .Q(countOut), .clk(clk), .en(edgeFound), .up(1'b1), .clr(clr), .load(rollover));
|
|
m_register #(1) waveTracker(.Q(signalOut), .D(!signalOut), .clk(clk), .en(rollover), .clr(clr));
|
|
|
|
assign rollover = (countOut >= N) & edgeFound;
|
|
|
|
endmodule: divideByN
|
|
|
|
|
|
module wave15kGen
|
|
(
|
|
input logic clk, clr,
|
|
output logic wave, pulse
|
|
);
|
|
|
|
logic [11:0] parallel15k;
|
|
|
|
m_counter #(12) counter15k(.D(12'd0), .Q(parallel15k), .clk(clk), .en(1'b1), .up(1'b1), .clr(clr), .load(pulse));
|
|
m_register #(1) waveTracker(.D(!wave), .Q(wave), .clk(clk), .en(pulse), .clr(clr));
|
|
|
|
assign pulse = (parallel15k == 12'd3333);
|
|
|
|
endmodule: wave15kGen
|
|
|
|
module wave64kGen
|
|
(
|
|
input logic clk, clr,
|
|
output logic wave, pulse
|
|
);
|
|
|
|
logic [9:0] parallel64k;
|
|
|
|
m_counter #(10) counter64k(.D(10'd0), .Q(parallel64k), .clk(clk), .en(1'b1), .up(1'b1), .clr(clr), .load(pulse));
|
|
m_register #(1) waveTracker(.D(!wave), .Q(wave), .clk(clk), .en(pulse), .clr(clr));
|
|
|
|
assign pulse = (parallel64k == 10'd781);
|
|
|
|
endmodule: wave64kGen
|
|
|
|
module wave179mGen
|
|
(
|
|
input logic clk, clr,
|
|
output logic wave, pulse
|
|
);
|
|
|
|
logic [4:0] parallel179m;
|
|
|
|
m_counter #(5) counter64k(.D(5'd0), .Q(parallel179m), .clk(clk), .en(1'b1), .up(1'b1), .clr(clr), .load(pulse));
|
|
m_register #(1) waveTracker(.D(!wave), .Q(wave), .clk(clk), .en(pulse), .clr(clr));
|
|
|
|
assign pulse = (parallel179m == 5'd28);
|
|
|
|
endmodule: wave179mGen
|
|
|
|
|
|
module polyCounter4
|
|
(
|
|
input logic clk, pulse179m, clr,
|
|
output logic rand4
|
|
);
|
|
|
|
logic [3:0] regValue;
|
|
logic feedbackVal;
|
|
|
|
m_shift_register #(4) polyShifter(.Q(regValue), .clk(clk), .en(pulse179m), .left(1'b0), .s_in(feedbackVal), .clr(clr));
|
|
|
|
assign feedbackVal = !(regValue[3] ^ regValue[2]);
|
|
assign rand4 = regValue[3];
|
|
|
|
endmodule: polyCounter4
|
|
|
|
|
|
module polyCounter5
|
|
(
|
|
input logic clk, pulse179m, clr,
|
|
output logic rand5
|
|
);
|
|
|
|
logic [4:0] regValue;
|
|
logic feedbackVal;
|
|
|
|
m_shift_register #(5) polyShifter(.Q(regValue), .clk(clk), .en(pulse179m), .left(1'b1), .s_in(feedbackVal), .clr(clr));
|
|
|
|
assign feedbackVal = !(regValue[4] ^ regValue[2]);
|
|
assign rand5 = regValue[4];
|
|
|
|
endmodule: polyCounter5
|
|
|
|
|
|
module polyCounter17
|
|
(
|
|
input logic clk, pulse179m, clr,
|
|
input logic reduce9,
|
|
output logic rand17,
|
|
output logic [7:0] rngVal
|
|
);
|
|
|
|
logic [16:0] regValue;
|
|
logic feedbackVal;
|
|
|
|
m_shift_register #(9) polyShifterUpper(.Q(regValue[16:8]), .clk(clk), .en(pulse179m), .left(1'b1), .s_in(reduce9 ? feedbackVal : regValue[7]), .clr(clr));
|
|
m_shift_register #(8) polyShifterLower(.Q(regValue[7:0]), .clk(clk), .en(pulse179m), .left(1'b1), .s_in(feedbackVal), .clr(clr));
|
|
|
|
assign feedbackVal = !(regValue[16] ^ regValue[11]);
|
|
assign rand17 = regValue[16];
|
|
assign rngVal = regValue[16:9];
|
|
|
|
endmodule: polyCounter17
|
|
|
|
module volumeControl
|
|
(
|
|
input logic clk, clr,
|
|
input logic signalIn,
|
|
input logic [3:0] volume,
|
|
input logic dcVolume,
|
|
output logic signalOut
|
|
);
|
|
|
|
logic [3:0] pwmCount;
|
|
logic pwmOn;
|
|
|
|
m_counter #(4) pwmTimer(.Q(pwmCount), .D(4'h0), .clk(clk), .clr(clr), .load(1'b0), .en(1'b1), .up(1'b1));
|
|
|
|
assign pwmOn = (pwmCount <= volume);
|
|
|
|
assign signalOut = dcVolume ? pwmOn : (pwmOn & signalIn);
|
|
|
|
|
|
endmodule: volumeControl
|
|
|
|
module risingDetector
|
|
(
|
|
input logic clk, clr,
|
|
input logic signalIn,
|
|
output logic risingEdge
|
|
);
|
|
|
|
logic prevSignal;
|
|
|
|
m_register #(1) risingRegister(.Q(prevSignal), .D(signalIn), .en(1'b1), .clk(clk), .clr(clr));
|
|
assign risingEdge = signalIn & ~prevSignal;
|
|
|
|
endmodule: risingDetector
|
|
|
|
module randomMixer
|
|
(
|
|
input logic clk, clr,
|
|
input logic signalIn,
|
|
input logic randomIn,
|
|
output logic signalOut
|
|
);
|
|
|
|
logic risingEdge;
|
|
|
|
logic waveWideRandom;
|
|
|
|
//This instance name made sense at 4AM when I typed it
|
|
risingDetector rayfall(.clk(clk), .clr(clr), .signalIn(signalIn), .risingEdge(risingEdge));
|
|
|
|
m_register #(1) randomCapture(.Q(waveWideRandom), .D(randomIn), .en(risingEdge), .clk(clk), .clr(clr));
|
|
|
|
assign signalOut = signalIn & waveWideRandom;
|
|
|
|
endmodule: randomMixer
|
|
|
|
module arbDivBy2
|
|
(
|
|
input logic clk, clr,
|
|
input logic signalIn,
|
|
output logic signalOut
|
|
);
|
|
|
|
logic risingEdge;
|
|
|
|
risingDetector risingCheck(.clk(clk), .clr(clr), .signalIn(signalIn), .risingEdge(risingEdge));
|
|
|
|
m_register #(1) waveTracker(.Q(signalOut), .D(~signalOut), .en(risingEdge), .clk(clk), .clr(clr));
|
|
|
|
endmodule: arbDivBy2
|
|
|
|
|
|
|