mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-02-18 05:23:45 +00:00
187 lines
5.5 KiB
Systemverilog
187 lines
5.5 KiB
Systemverilog
/*
|
|
* Copyright (c) 2014, Aleksander Osman
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
module opl3
|
|
#(
|
|
parameter OPLCLK = 64000000 // opl_clk in Hz
|
|
)
|
|
(
|
|
input clk,
|
|
input clk_opl,
|
|
input rst_n,
|
|
output reg irq_n,
|
|
|
|
input [12:0] period_80us, // from clk
|
|
|
|
input [1:0] addr,
|
|
output [7:0] dout,
|
|
input [7:0] din,
|
|
input we,
|
|
|
|
output signed [15:0] sample_l,
|
|
output signed [15:0] sample_r
|
|
);
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
wire [7:0] io_readdata = { timer1_overflow | timer2_overflow, timer1_overflow, timer2_overflow, 5'd0 };
|
|
assign dout = !addr ? io_readdata : 8'hFF;
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
reg old_write;
|
|
always @(posedge clk) old_write <= we;
|
|
|
|
wire write = (~old_write & we);
|
|
|
|
reg [8:0] index;
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if(rst_n == 0) index <= 0;
|
|
else if(~addr[0] && write) index <= {addr[1], din};
|
|
end
|
|
|
|
wire io_write = (addr[0] && write);
|
|
wire [7:0] io_writedata = din;
|
|
|
|
//------------------------------------------------------------------------------ timer 1
|
|
|
|
reg [7:0] timer1_preset;
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if(rst_n == 0) timer1_preset <= 0;
|
|
else if(io_write && index == 2) timer1_preset <= io_writedata;
|
|
end
|
|
|
|
reg timer1_mask;
|
|
reg timer1_active;
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if(rst_n == 0) {timer1_mask, timer1_active} <= 0;
|
|
else if(io_write && index == 4 && ~io_writedata[7]) {timer1_mask, timer1_active} <= {io_writedata[6], io_writedata[0]};
|
|
end
|
|
|
|
wire timer1_pulse;
|
|
timer timer1( clk, period_80us, timer1_preset, timer1_active, timer1_pulse );
|
|
|
|
reg timer1_overflow;
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if(rst_n == 0) timer1_overflow <= 0;
|
|
else begin
|
|
if(io_write && index == 4 && io_writedata[7]) timer1_overflow <= 0;
|
|
if(timer1_pulse) timer1_overflow <= 1;
|
|
end
|
|
end
|
|
|
|
|
|
//------------------------------------------------------------------------------ timer 2
|
|
|
|
reg [7:0] timer2_preset;
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if(rst_n == 0) timer2_preset <= 0;
|
|
else if(io_write && index == 3) timer2_preset <= io_writedata;
|
|
end
|
|
|
|
reg timer2_mask;
|
|
reg timer2_active;
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if(rst_n == 0) {timer2_mask, timer2_active} <= 0;
|
|
else if(io_write && index == 4 && ~io_writedata[7]) {timer2_mask, timer2_active} <= {io_writedata[5], io_writedata[1]};
|
|
end
|
|
|
|
wire timer2_pulse;
|
|
timer timer2( clk, {period_80us, 2'b00}, timer2_preset, timer2_active, timer2_pulse );
|
|
|
|
reg timer2_overflow;
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if(rst_n == 0) timer2_overflow <= 0;
|
|
else begin
|
|
if(io_write && index == 4 && io_writedata[7]) timer2_overflow <= 0;
|
|
if(timer2_pulse) timer2_overflow <= 1;
|
|
end
|
|
end
|
|
|
|
|
|
//------------------------------------------------------------------------------ IRQ
|
|
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if(rst_n == 0) irq_n <= 1;
|
|
else begin
|
|
if(io_write && index == 4 && io_writedata[7]) irq_n <= 1;
|
|
if(~timer1_mask && timer1_pulse) irq_n <= 0;
|
|
if(~timer2_mask && timer2_pulse) irq_n <= 0;
|
|
end
|
|
end
|
|
|
|
opl3sw #(OPLCLK) opl3
|
|
(
|
|
.reset(~rst_n),
|
|
|
|
.cpu_clk(clk),
|
|
.addr(addr),
|
|
.din(din),
|
|
.wr(write),
|
|
|
|
.clk(clk_opl),
|
|
.left(sample_l),
|
|
.right(sample_r)
|
|
);
|
|
|
|
endmodule
|
|
|
|
module timer
|
|
(
|
|
input clk,
|
|
input [14:0] resolution,
|
|
input [7:0] init,
|
|
input active,
|
|
output reg overflow_pulse
|
|
);
|
|
|
|
always @(posedge clk) begin
|
|
reg [7:0] counter = 0;
|
|
reg [14:0] sub_counter = 0;
|
|
reg old_act;
|
|
|
|
old_act <= active;
|
|
overflow_pulse <= 0;
|
|
|
|
if(~old_act && active) begin
|
|
counter <= init;
|
|
sub_counter <= resolution;
|
|
end
|
|
else if(active) begin
|
|
sub_counter <= sub_counter - 1'd1;
|
|
if(!sub_counter) begin
|
|
sub_counter <= resolution;
|
|
counter <= counter + 1'd1;
|
|
if(&counter) begin
|
|
overflow_pulse <= 1;
|
|
counter <= init;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule
|