mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-04-30 21:58:59 +00:00
Sync
This commit is contained in:
@@ -1,310 +0,0 @@
|
||||
//
|
||||
// K580VI53 timer implementation
|
||||
//
|
||||
// Copyright (c) 2016 Sorgelig
|
||||
//
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// altera message_off 10240
|
||||
|
||||
|
||||
`default_nettype none
|
||||
|
||||
module k580vi53
|
||||
(
|
||||
// CPU bus
|
||||
input reset,
|
||||
input clk_sys,
|
||||
input [1:0] addr,
|
||||
input [7:0] din,
|
||||
output [7:0] dout,
|
||||
input wr,
|
||||
input rd,
|
||||
|
||||
// Timer signals
|
||||
input [2:0] clk_timer,
|
||||
input [2:0] gate,
|
||||
output [2:0] out,
|
||||
output [2:0] sound_active
|
||||
);
|
||||
|
||||
wire [7:0] dout0;
|
||||
wire [7:0] dout1;
|
||||
wire [7:0] dout2;
|
||||
|
||||
assign dout = dout0 & dout1 & dout2;
|
||||
|
||||
timer t0(reset, clk_sys, clk_timer[0], din, dout0, wr && (addr == 3) && (din[7:6] == 0), wr && (addr == 0), rd && (addr == 0), gate[0], out[0], sound_active[0]);
|
||||
timer t1(reset, clk_sys, clk_timer[1], din, dout1, wr && (addr == 3) && (din[7:6] == 1), wr && (addr == 1), rd && (addr == 1), gate[1], out[1], sound_active[1]);
|
||||
timer t2(reset, clk_sys, clk_timer[2], din, dout2, wr && (addr == 3) && (din[7:6] == 2), wr && (addr == 2), rd && (addr == 2), gate[2], out[2], sound_active[2]);
|
||||
|
||||
endmodule
|
||||
|
||||
module timer
|
||||
(
|
||||
input reset,
|
||||
input clk_sys,
|
||||
input clk_timer,
|
||||
input [7:0] din,
|
||||
output [7:0] dout,
|
||||
input wr_cw,
|
||||
input wr,
|
||||
input rd,
|
||||
input gate,
|
||||
output reg out,
|
||||
output reg sound_active
|
||||
);
|
||||
|
||||
reg [7:0] q;
|
||||
reg [7:0] cw;
|
||||
reg [15:0] counter;
|
||||
reg [15:0] ld_count;
|
||||
reg [7:0] load;
|
||||
reg pause;
|
||||
reg stop1;
|
||||
|
||||
|
||||
assign dout = q;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg [15:0] l_counter;
|
||||
reg msbw, msbr; // according to Siemens doc, read and write have indepenent msb flag.
|
||||
reg latched;
|
||||
|
||||
reg old_wr_cw, old_wr, old_rd;
|
||||
old_wr_cw <= wr_cw;
|
||||
old_wr <= wr;
|
||||
old_rd <= rd;
|
||||
|
||||
if(!old_wr_cw && wr_cw) begin
|
||||
msbw <=0;
|
||||
msbr <=0;
|
||||
if(!din[5:4]) begin
|
||||
if(!latched) begin
|
||||
latched <=1;
|
||||
l_counter <= counter;
|
||||
end
|
||||
end else begin
|
||||
cw <= din;
|
||||
latched <=0;
|
||||
stop1 <=1;
|
||||
pause<=1;
|
||||
end
|
||||
end
|
||||
|
||||
if(!old_wr && wr) begin
|
||||
case(cw[5:4])
|
||||
1: begin // high speed mode
|
||||
ld_count[7:0] <= check(din);
|
||||
ld_count[15:8] <= 0;
|
||||
stop1 <=0;
|
||||
load <=load + 1'd1;
|
||||
pause <=0;
|
||||
end
|
||||
2: begin // low precision mode
|
||||
ld_count[7:0] <= 0;
|
||||
ld_count[15:8] <= check(din);
|
||||
stop1 <=0;
|
||||
load <=load + 1'd1;
|
||||
pause <=0;
|
||||
end
|
||||
default: begin // full mode
|
||||
if(msbw) ld_count[15:8] <= check(din);
|
||||
else ld_count[7:0] <= check(din);
|
||||
msbw <= ~msbw;
|
||||
pause <= ~msbw;
|
||||
if(msbw) begin
|
||||
stop1 <=0;
|
||||
load <=load + 1'd1;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
if(!old_rd && rd) begin
|
||||
casex({latched, msbr, cw[5:4]})
|
||||
4'b0X01: q <=counter[7:0];
|
||||
4'b0X10: q <=counter[15:8];
|
||||
4'b0011: q <=counter[7:0];
|
||||
4'b0111: q <=counter[15:8];
|
||||
4'b1X01: begin q <=l_counter[7:0]; latched <=0; end
|
||||
4'b1X10: begin q <=l_counter[15:8]; latched <=0; end
|
||||
4'b1011: q <=l_counter[7:0];
|
||||
4'b1111: begin q <=l_counter[15:8]; latched <=0; end
|
||||
endcase
|
||||
msbr <= ~msbr;
|
||||
end
|
||||
|
||||
if(!rd || reset) q <= 255;
|
||||
|
||||
if(reset) begin
|
||||
stop1 <=1;
|
||||
ld_count <=0;
|
||||
cw <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
function [15:0] minus1;
|
||||
input [15:0] value;
|
||||
begin
|
||||
if(!cw[0]) minus1 = value-1'd1;
|
||||
else begin
|
||||
minus1 = value;
|
||||
if(!minus1[3:0]) begin
|
||||
minus1[3:0] = 9;
|
||||
if(!minus1[7:4]) begin
|
||||
minus1[7:4] = 9;
|
||||
if(!minus1[11:8]) begin
|
||||
minus1[11:8] = 9;
|
||||
if(!minus1[15:12]) begin
|
||||
minus1[15:12] = 9;
|
||||
end else minus1[15:12] = minus1[15:12]-1'd1;
|
||||
end else minus1[11:8] = minus1[11:8]-1'd1;
|
||||
end else minus1[7:4] = minus1[7:4]-1'd1;
|
||||
end else minus1[3:0] = minus1[3:0]-1'd1;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
function [7:0] check;
|
||||
input [7:0] value;
|
||||
begin
|
||||
if(!cw[0]) check = value;
|
||||
else begin
|
||||
check[3:0] = (value[3:0]>9) ? 4'd9 : value[3:0];
|
||||
check[7:4] = (value[7:4]>9) ? 4'd9 : value[7:4];
|
||||
end;
|
||||
end
|
||||
endfunction
|
||||
|
||||
reg stop2;
|
||||
wire stop = stop1 | stop2;
|
||||
|
||||
//
|
||||
// With bugs implemented:
|
||||
//
|
||||
// M0,M1,M4,M5 - counter doesn't stop at the end but wrap around instead.
|
||||
//
|
||||
// M1,M5 - setting of Control Word doesn't reset counter.
|
||||
// Counter continue to count old value after ccounter register is set.
|
||||
//
|
||||
always @(posedge clk_sys) begin
|
||||
reg [7:0] old_load;
|
||||
reg old_gate;
|
||||
reg start, count_en, m3state;
|
||||
reg [7:0] stop_delay;
|
||||
reg old_clk;
|
||||
|
||||
// cannot treat it as clock enable because timer clock
|
||||
// can be fed from output of other timer
|
||||
old_clk <= clk_timer;
|
||||
if(old_clk & ~clk_timer) begin
|
||||
stop2 <= stop1;
|
||||
|
||||
old_load <= load;
|
||||
old_gate <= gate;
|
||||
start <= stop;
|
||||
|
||||
// Assume sound is generated by mode 3 and mode 0(DAC emulation).
|
||||
sound_active <= (!cw[3:1] || (cw[2:1] == 2'b11)) && !stop;
|
||||
|
||||
casex(cw[3:1])
|
||||
3'b000: if(stop) begin out <=0; count_en <=0; end
|
||||
else begin
|
||||
if(start || (old_load != load)) begin
|
||||
counter <= ld_count;
|
||||
out <=0;
|
||||
count_en <=1;
|
||||
end else if(!pause && gate) begin
|
||||
counter <= minus1(counter);
|
||||
if(counter == 1) begin
|
||||
out <=1;
|
||||
count_en <=0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
3'b001: if(stop) begin out <=1; count_en <=0; end
|
||||
else begin
|
||||
if(!old_gate & gate) begin
|
||||
counter <= ld_count;
|
||||
out <=0;
|
||||
count_en <=1;
|
||||
end else begin
|
||||
counter <= minus1(counter);
|
||||
if((counter == 1) && count_en) begin
|
||||
out <=1;
|
||||
count_en <=0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
3'bX10: if(stop || !gate) out <=1;
|
||||
else begin
|
||||
if(start || (!old_gate & gate) || (counter <= 1)) begin
|
||||
counter <=ld_count;
|
||||
out <=1;
|
||||
end else begin
|
||||
counter <= minus1(counter);
|
||||
if(counter == 2) out <=0;
|
||||
end
|
||||
end
|
||||
|
||||
3'bX11: if(stop || !gate) begin out <=1; m3state <=1; end
|
||||
else begin
|
||||
if(start || (!old_gate & gate) || (counter <= 2)) begin
|
||||
counter <=ld_count;
|
||||
out <= m3state;
|
||||
m3state <= ~m3state;
|
||||
end else begin
|
||||
counter <= !counter[0] ? minus1(minus1(counter)) : out ? minus1(counter) : minus1(minus1(minus1(counter)));
|
||||
end
|
||||
end
|
||||
|
||||
3'b100: if(stop) begin out <=1; count_en <=0; end
|
||||
else begin
|
||||
out <=1;
|
||||
if(start) begin
|
||||
counter <=ld_count;
|
||||
count_en <=1;
|
||||
end else if(gate) begin
|
||||
counter <= minus1(counter);
|
||||
if((counter == 1) && count_en) begin
|
||||
out <=0;
|
||||
count_en <=0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
3'b101: if(stop) begin out <=1; count_en <=0; end
|
||||
else begin
|
||||
out <=1;
|
||||
if(!old_gate & gate) begin
|
||||
counter <=ld_count;
|
||||
out <=1;
|
||||
count_en <=1;
|
||||
end else begin
|
||||
counter <= minus1(counter);
|
||||
if((counter == 1) && count_en) begin
|
||||
out <=0;
|
||||
count_en <=0;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user