OpenCores
URL https://opencores.org/ocsvn/sqmusic/sqmusic/trunk

Subversion Repositories sqmusic

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

/sqmusic/trunk/1942/1942.v
0,0 → 1,233
/*
1942 simple board setup in order to test SQMUSIC.
Requirements:
TV80, Z80 Verilog module
Dump of Z80 ROM from 1942 board
 
(c) Jose Tejada Gomez, 9th May 2013
You can use this file following the GNU GENERAL PUBLIC LICENSE version 3
Read the details of the license in:
http://www.gnu.org/licenses/gpl.txt
Send comments to: jose.tejada@ieee.org
 
*/
 
`timescale 1ns / 1ps
 
module sound1942;
wire [7:0]cpu_in, cpu_out;
wire [15:0]adr;
wire m1_n, mreq_n, iorq_n, rd_n, wr_n, rfsh_n, halt_n, busak_n;
wire bus_error;
// inputs to Z80
reg reset_n, clk, wait_n, int_n, nmi_n, busrq_n, sound_clk;
 
initial begin
//$dumpfile("dump.lxt");
//$dumpvars(1,map.ym2203_0);
// $dumpvars();
// $dumpon;
// $shm_open("1942.shm");
// $shm_probe( sound1942, "ACTFS" );
reset_n=0;
nmi_n=1;
wait_n=1;
#1500 reset_n=1;
// change finish time depending on song
// #400e6 $finish;
#10e9 $finish;
end
always begin // main clock
clk=0;
forever clk = #167 ~clk;
end
 
always begin // sound clock
sound_clk=0;
forever sound_clk = #334 ~sound_clk;
end
 
parameter int_low_time=167*2*80;
 
always begin // interrupt clock
int_n=1;
forever begin
#(4166667-int_low_time) int_n=0; // 240Hz
//$display("IRQ request @ %t us",$time/1e6);
#(int_low_time) int_n=1;
end
end
tv80n cpu( //outputs
.m1_n(m1_n), .mreq_n(mreq_n), .iorq_n(iorq_n), .rd_n(rd_n), .wr_n(wr_n),
.rfsh_n(rfsh_n), .halt_n(halt_n), .busak_n(busak_n), .A(adr), .do(cpu_out),
// Inputs
.reset_n(reset_n), .clk(clk), .wait_n(wait_n),
.int_n(int_n), .nmi_n(nmi_n), .busrq_n(busrq_n), .di(cpu_in) );
MAP map( .adr(adr), .din(cpu_out), .dout(cpu_in), .clk(clk),
.sound_clk( sound_clk ), .wr_n(wr_n), .rd_n(rd_n),
.bus_error(bus_error), .reset_n(reset_n) );
 
 
endmodule
 
/////////////////////////////////////////////////////
module MAP(
input [15:0] adr,
input [7:0] din,
output [7:0] dout,
input clk,
input sound_clk,
input rd_n,
input wr_n,
input reset_n,
output bus_error );
wire [3:0] ay0_a, ay0_b, ay0_c, ay1_a, ay1_b, ay1_c;
wire [15:0] amp0_y, amp1_y;
 
wire [7:0]ram_out, rom_out, latch_out;
wire rom_enable = adr<16'h4000 ? 1:0;
wire ram_enable = adr>=16'h4000 && adr<16'h4800 ? 1:0;
wire latch_enable = adr==16'h6000 ? 1 : 0;
wire ay_0_enable = adr==16'h8000 || adr==16'h8001 ? 1:0;
wire ay_1_enable = adr==16'hC000 || adr==16'hC001 ? 1:0;
assign bus_error = ~ram_enable & ~rom_enable & ~latch_enable &
~ay_0_enable & ~ay_1_enable;
assign dout=ram_out | rom_out | latch_out;
/*
always @(negedge rd_n)
if( !rd_n && adr==8'h38 )
$display("IRQ processing started @ %t us",$time/1e6);
*/
RAM ram(.adr(adr[10:0]), .din(din), .dout(ram_out), .enable( ram_enable ),
.clk(clk), .wr_n(wr_n), .rd_n(rd_n) );
ROM rom(.adr(adr[13:0]), .data(rom_out), .enable(rom_enable),
.rd_n(rd_n), .clk(clk));
SOUND_LATCH sound_latch( .dout(latch_out), .enable(latch_enable),
.clk(clk), .rd_n(rd_n) );
 
// fake_ay ay_0( .adr(adr[0]), .din(din), .clk(clk), .wr_n(~ay_0_enable|wr_n) );
 
AY_3_8910_capcom ay_0( .reset_n(reset_n), .clk(clk), .sound_clk(sound_clk),
.din(din), .adr(adr[0]), .wr_n(wr_n), .cs_n(~ay_0_enable),
.A(ay0_a), .B(ay0_b), .C(ay0_c) );
AY_3_8910_capcom ay_1( .reset_n(reset_n), .clk(clk), .sound_clk(sound_clk),
.din(din), .adr(adr[0]), .wr_n(wr_n), .cs_n(~ay_1_enable),
.A(ay1_a), .B(ay1_b), .C(ay1_c) );
 
SQM_AMP amp0( .A(ay0_a), .B(ay0_b), .C(ay0_c), .Y( amp0_y ));
SQM_AMP amp1( .A(ay1_a), .B(ay1_b), .C(ay1_c), .Y( amp1_y ));
always #22676 $display("%d", amp0_y+amp1_y ); // 44.1kHz sample
// initial $dumpvars(0,ym2203_0);
endmodule
 
//////////////////////////////////////////////////////////
// this module is used to check the communication of the
// Z80 with the AY-3-8910
// only used for debugging
module fake_ay(
input adr,
input [7:0] din,
input clk,
input wr_n );
reg [7:0] contents[1:0];
wire sample = clk & ~wr_n;
always @(posedge sample) begin
// if( contents[adr] != din ) begin
$display("%t -> %d = %d", $realtime/1e6, adr, din );
if( !adr && din>15 ) $display("AY WARNING");
contents[adr] = din;
end
endmodule
//////////////////////////////////////////////////////////
module RAM(
input [10:0] adr,
input [7:0] din,
output reg [7:0] dout,
input enable,
input clk,
input rd_n,
input wr_n );
 
reg [7:0] contents[2047:0];
wire sample = clk & (~rd_n | ~wr_n );
 
initial dout=0;
always @(posedge sample) begin
if( !enable )
dout=0;
else begin
if( !wr_n ) contents[adr]=din;
if( !rd_n ) dout=contents[adr];
end
end
endmodule
 
//////////////////////////////////////////////////////////
module ROM(
input [13:0] adr,
output reg [7:0] data,
input enable,
input rd_n,
input clk );
 
reg [7:0] contents[16383:0];
 
wire sample = clk & ~rd_n;
 
initial begin
$readmemh("../rom/sr-01.c11.hex", contents ); // this is the hex dump of the ROM
data=0;
end
 
always @( posedge sample ) begin
if ( !enable )
data=0;
else
data=contents[ adr ];
end
endmodule
 
//////////////////////////////////////////////////////////
module SOUND_LATCH(
output reg [7:0] dout,
input enable,
input clk,
input rd_n );
 
wire sample = clk & ~rd_n;
reg [7:0]data;
 
initial begin
dout=0;
data=0;
#100e6 data=8'h12; // enter the song/sound code here
end
always @(posedge sample) begin
if( !enable )
dout=0;
else begin
if( !rd_n ) begin
// $display("Audio latch read @ %t us", $realtime/1e6 );
// if( data != 0 )
// $display("Audio latch read (%X) @ %t us", data, $realtime/1e6 );
dout=data;
end
end
end
endmodule
 
sqmusic/trunk/1942/1942.v Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: sqmusic/trunk/1942/log2wav.cc =================================================================== --- sqmusic/trunk/1942/log2wav.cc (nonexistent) +++ sqmusic/trunk/1942/log2wav.cc (revision 3) @@ -0,0 +1,91 @@ +/* + Converts output from 1942.v to .wav file + + (c) Jose Tejada Gomez, 9th May 2013 + You can use this file following the GNU GENERAL PUBLIC LICENSE version 3 + Read the details of the license in: + http://www.gnu.org/licenses/gpl.txt + + Send comments to: jose.tejada@ieee.org + +*/ + +// Compile with g++ log2wav.cc -o log2wav + +#include +#include +#include +#include +#include +#include + +using namespace std; + +int main(int argc, char *argv[]) { + try { + ifstream fin; + if( argc == 2) + fin.open(argv[1]); + else + fin.open("/dev/stdin"); + ofstream fout("out.wav"); + if( fin.bad() ) throw "Cannot open input file"; + if( fout.bad() ) throw "Cannot open output file"; + assert( sizeof(short int)==2 ); + char buffer[1024]; + int data=0; + + // depending on the simulator the following "while" + // section might no be needed or modified + // It just skips simulator output until the real data + // starts to come out + while( !fin.eof() ) { + fin.getline( buffer, sizeof(buffer) ); + if( strcmp(buffer,"ncsim> run" )==0) break; + } + + if( fin.eof() ) throw "Data not found"; + fout.seekp(44); + while( !fin.eof() ) { + short int value; + fin.getline( buffer, sizeof(buffer) ); + if( buffer[0]=='S' ) break; // reached line "Simulation complete" + value = atoi( buffer ); + fout.write( (char*) &value, sizeof(value) ); + data++; + } + cout << data << " samples written\n"; + // Write the header + const char *RIFF = "RIFF"; + fout.seekp(0); + fout.write( RIFF, 4 ); + int aux=36+2*data; + fout.write( (char*)&aux, 4 ); + const char *WAVE = "WAVE"; + fout.write( WAVE, 4 ); + const char *fmt = "fmt "; + fout.write( fmt, 4 ); + aux=16; + fout.write( (char*)&aux, 4 );// suubchunk 1 size + short int aux_short = 1; + fout.write( (char*)&aux_short, 2 ); // audio format (1) + fout.write( (char*)&aux_short, 2 ); // num channels (1) + aux=44100; + fout.write( (char*)&aux, 4 ); + aux=44100*1*2; + fout.write( (char*)&aux, 4 ); // byte rate + aux_short=2; + fout.write( (char*)&aux_short, 2 ); // block align + aux_short=16; + fout.write( (char*)&aux_short, 2 ); // bits per sample + RIFF="data"; + fout.write( RIFF, 4 ); + aux = data*2; + fout.write( (char*)&aux, 4 ); // data size + return 0; + } + catch( const char *msg ) { + cout << msg << "\n"; + return -1; + } +}
sqmusic/trunk/1942/log2wav.cc Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: sqmusic/trunk/1942/dump.cc =================================================================== --- sqmusic/trunk/1942/dump.cc (nonexistent) +++ sqmusic/trunk/1942/dump.cc (revision 3) @@ -0,0 +1,53 @@ +/* + Converts binary ROM dump to hexadecimal format + so Verilog can read it + + Requirements: + TV80, Z80 Verilog module + Dump of Z80 ROM from 1942 board + + (c) Jose Tejada Gomez, 9th May 2013 + You can use this file following the GNU GENERAL PUBLIC LICENSE version 3 + Read the details of the license in: + http://www.gnu.org/licenses/gpl.txt + + Send comments to: jose.tejada@ieee.org + +*/ + +// Compile with: g++ dump.cc -o dump + +#include +#include + +using namespace std; + +int main( int argc, char *argv[]) { + if( argc!=2 ) { + cout << "Usage: dump filename\n"; + return -1; + } + ifstream f( argv[1] ); + unsigned char *buffer = new unsigned char[16*1024]; + f.read( (char*)buffer, 16*1024 ); + cout << hex; + unsigned char *aux=buffer; + // swap all bytes + /* + for(int k=0;k<32*1024; k+=2) { + unsigned char*p = aux; + unsigned char x0 = *aux++; + unsigned char x1 = *aux; + *p=x1; + *aux=x0; + aux=p+2; + } + aux=buffer;*/ + for(int k=0; k<16*1024; k++ ) { + unsigned val = *aux++; + cout << val << "\n"; + } + + delete [] buffer; + return 0; +}
sqmusic/trunk/1942/dump.cc Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: sqmusic/trunk/1942/gather =================================================================== --- sqmusic/trunk/1942/gather (nonexistent) +++ sqmusic/trunk/1942/gather (revision 3) @@ -0,0 +1,8 @@ +1942.v +../tv80/rtl/core/tv80n.v +../tv80/rtl/core/tv80_core.v +../tv80/rtl/core/tv80_alu.v +../tv80/rtl/core/tv80_mcode.v +../tv80/rtl/core/tv80_reg.v +../sqm/sqm_amp.v +../sqm/sqmusic.v
sqmusic/trunk/1942/gather Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: sqmusic/trunk/1942/readme =================================================================== --- sqmusic/trunk/1942/readme (nonexistent) +++ sqmusic/trunk/1942/readme (revision 3) @@ -0,0 +1,14 @@ +Instructions to play Capcom's 1942 music with a Verilog simulator: + + +1. Dump rom sr-01.c11 from Capcom's 1942 arcade board +2. Compile and run "dump.cc" program to convert the binary file to hexadecimal format +3. Place file in ../rom folder (see 1942.v file for details on location) +4. Run verilog simulation from 1942 folder using the "gather" file +5. Pass the output of the simulation through "log2wav.cc", either using a pipe or storing it on a file. Check that the data dump is caught correctly by log2wav as some simulators will add extra information at the beginning of the file + +Other: + +-tv80 project files are expected to be in ../tv80 +-the music code played can be changed in 1942.v +-you may need to adjust the length of the simulation to listen the full song Index: sqmusic/trunk/sqm/sqm_amp.v =================================================================== --- sqmusic/trunk/sqm/sqm_amp.v (nonexistent) +++ sqmusic/trunk/sqm/sqm_amp.v (revision 3) @@ -0,0 +1,53 @@ +/* + SQmusic + logarithmic digital amplifier to use with SQMUSIC + Version 0.1, tested on simulation only with Capcom's 1942 + + (c) Jose Tejada Gomez, 9th May 2013 + You can use this file following the GNU GENERAL PUBLIC LICENSE version 3 + Read the details of the license in: + http://www.gnu.org/licenses/gpl.txt + + Send comments to: jose.tejada@ieee.org + +*/ +`timescale 1ns / 1ps +module SQM_AMP( + input [3:0]A, input [3:0]B, input [3:0]C, // input channels + output [15:0] Y +); + +wire[11:0] Alog, Blog, Clog; + +SQM_LOG adac( .din(A), .dout(Alog) ); +SQM_LOG bdac( .din(B), .dout(Blog) ); +SQM_LOG cdac( .din(C), .dout(Clog) ); +//always @(*) +assign Y=Alog+Blog+Clog; +endmodule + +module SQM_LOG( + input [3:0]din, + output reg [11:0]dout ); + +always @(din) + case (din) + 0: dout=0; + 1: dout=16; + 2: dout=19; + 3: dout=32; + 4: dout=39; + 5: dout=64; + 6: dout=78; + 7: dout=128; + 8: dout=155; + 9: dout=256; + 10: dout=310; + 11: dout=512; + 12: dout=621; + 13: dout=1024; + 14: dout=1448; + 15: dout=2048; + endcase + +endmodule
sqmusic/trunk/sqm/sqm_amp.v Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: sqmusic/trunk/sqm/sqmusic.v =================================================================== --- sqmusic/trunk/sqm/sqmusic.v (nonexistent) +++ sqmusic/trunk/sqm/sqmusic.v (revision 3) @@ -0,0 +1,254 @@ +/* + SQmusic + Music synthetiser compatible with AY-3-8910 software compatible + Version 0.1, tested on simulation only with Capcom's 1942 + + (c) Jose Tejada Gomez, 9th May 2013 + You can use this file following the GNU GENERAL PUBLIC LICENSE version 3 + Read the details of the license in: + http://www.gnu.org/licenses/gpl.txt + + Send comments to: jose.tejada@ieee.org + +*/ + +/* Capcom arcade boards like 1942 use two memory locations to +communicate with the AY-3-8910 (or compatible) chip. This small code +provides a 2-byte memory map as expected by Capcom games +*/ +`timescale 1ns / 1ps +module AY_3_8910_capcom( + input reset_n, + input clk, // CPU clock + input sound_clk, // normally slower than the CPU clock + input [7:0] din, + input adr, + input wr_n, // write + input cs_n, // chip select + output [3:0]A,B,C // channel outputs +); + +reg [7:0] latches[1:0]; +reg core_wr; +wire sample = clk & ~cs_n & ~wr_n; +reg count; + +always @(posedge sound_clk or negedge reset_n) begin + if(!reset_n) begin + count=0; + end + else begin + if( !count && core_wr) count=1; + else if( core_wr ) begin + count=0; + core_wr=0; + end + end +end + +always @(posedge sample or negedge reset_n) begin + if(!reset_n) begin + latches[0]=0; + latches[1]=0; + end + else begin + latches[adr] = din; + if(adr) core_wr=1; + end +end + +SQMUSIC core( .reset_n(reset_n), .clk(sound_clk), .data_in(latches[1]), + .adr( latches[0][3:0] ), .rd(1'b0), .wr(core_wr), .A(A), .B(B), .C(C) ); +endmodule + +/* The AY core does +*/ +module SQMUSIC( // pins are not multiplexed + input reset_n, + input clk, + input [7:0] data_in, + output reg [7:0] data_out, // read functionality not implemented yet + input [3:0] adr, + input rd, // read + input wr, // write + output [3:0]A,B,C // channel outputs +); + +reg [7:0] regarray[15:0]; +reg [3:0] clkdiv16; + +wire [3:0] envelope; +wire [2:0] sqwave; +wire noise, envclk; +wire Amix = (noise|regarray[7][3]) ^ (sqwave[0]|regarray[7][0]); +wire Bmix = (noise|regarray[7][4]) ^ (sqwave[1]|regarray[7][1]); +wire Cmix = (noise|regarray[7][5]) ^ (sqwave[2]|regarray[7][2]); + +// internal modules operate at clk/16 +SQM_CLK_DIVIDER #(12) chA( .clk(clkdiv16[3]), .reset_n(reset_n), + .period({regarray[1][3:0], regarray[0][7:0] }), .div(sqwave[0]) ); +SQM_CLK_DIVIDER #(12) chB( .clk(clkdiv16[3]), .reset_n(reset_n), + .period({regarray[3][3:0], regarray[2][7:0] }), .div(sqwave[1]) ); +SQM_CLK_DIVIDER #(12) chC( .clk(clkdiv16[3]), .reset_n(reset_n), + .period({regarray[5][3:0], regarray[4][7:0] }), .div(sqwave[2]) ); + +// the noise uses a x2 faster clock in order to produce a frequency +// of Fclk/16 when period is 1 +SQM_NOISE ng( .clk(clkdiv16[3]), .reset_n(reset_n), + .period(regarray[6][4:0]), .noise(noise) ); +// envelope generator +SQM_CLK_DIVIDER #(16) envclkdiv( .clk(clkdiv16[2]), .reset_n(reset_n), + .period({regarray[14],regarray[13]}), .div(envclk) ); +SQM_ENVELOPE env( .clk(envclk),.ctrl(regarray[15][3:0]), + .gain(envelope), .reset_n(reset_n) ); + +assign A=regarray[10][4]? envelope&{4{Amix}} : regarray[10][3:0]&{4{Amix}}; +assign B=regarray[11][4]? envelope&{4{Bmix}} : regarray[10][3:0]&{4{Bmix}}; +assign C=regarray[12][4]? envelope&{4{Cmix}} : regarray[10][3:0]&{4{Cmix}}; + +integer aux; + +// 16-count divider +always @(posedge clk or reset_n) begin + if( !reset_n) + clkdiv16=0; + else + clkdiv16<=clkdiv16+1; +end + +always @(posedge clk or reset_n) begin + if( !reset_n ) begin + data_out=0; + for(aux=0;aux<=15;aux=aux+1) regarray[aux]=0; + end + else begin + if( rd ) + data_out=regarray[ adr ]; + else if( wr ) regarray[adr]=data_in; + end +end + +endmodule + +module SQM_CLK_DIVIDER( + clk, // this is the divided down clock from the core + reset_n, + period, + div +); + +parameter bw=12; +input clk; // this is the divided down clock from the core +input reset_n; +input [bw-1:0]period; +output div; + +reg [bw-1:0]count; +reg clkdiv; + +initial clkdiv=0; + +assign div = period==1 ? clk : clkdiv; + +always @(posedge clk or reset_n) begin + if( !reset_n) begin + count=0; + clkdiv=0; + end + else begin + if( period==0 ) begin + clkdiv<=0; + count<=0; + end + else if( count >= period ) begin + count <= 0; + clkdiv = ~clkdiv; + end + else count <= count+1; + end +end +endmodule + +//////////////////////////////////////////////////////////////// +module SQM_NOISE( + input clk, // this is the divided down clock from the core + input reset_n, + input [4:0]period, + output noise +); + +reg [5:0]count; +reg [16:0]poly17; +wire poly17_zero = poly17==0; +assign noise=poly17[16]; +wire noise_clk; + +always @(posedge noise_clk or reset_n) begin + if( !reset_n) begin + poly17=0; + end + else begin + poly17={ poly17[0] ^ poly17[2] ^ poly17_zero, poly17[16:1] }; + end +end + +SQM_CLK_DIVIDER #(5) ndiv( .clk(clk), .reset_n(reset_n), + .period(period), .div(noise_clk) ); +endmodule + +//////////////////////////////////////////////////////////////// +module SQM_ENVELOPE( + input clk, // this is the divided down clock from the core + input reset_n, + input [3:0]ctrl, + output reg [3:0]gain +); + +reg dir; // direction +reg stop; +reg [3:0]prev_ctrl; // last control orders + +always @(posedge clk or reset_n) begin + if( !reset_n) begin + gain=4'hF; + dir=0; + prev_ctrl=0; + stop=1; + end + else begin + if (ctrl!=prev_ctrl) begin + prev_ctrl<=ctrl; + if( ctrl[2] ) begin + gain<=0; + dir<=1; + stop<=0; + end + else begin + gain<=4'hF; + dir<=0; + stop<=0; + end + end + else begin + if (!stop) begin + if( !prev_ctrl[3] && ((gain==0&&!dir) || (gain==4'hF&&dir))) begin + stop<=1; + gain<=0; + end + else begin + if( prev_ctrl[0] && ( (gain==0&&!dir) || (gain==4'hF&&dir))) begin // HOLD + stop<=1; + gain <= prev_ctrl[1]? ~gain : gain; + end + else begin + gain <= dir ? gain+1 : gain-1; + if( prev_ctrl[1:0]==2'b10 && ( (gain==1&&!dir) || (gain==4'hE&&dir))) begin // ALTERNATE + dir <= ~dir; + end + end + end + end + end + end +end +endmodule
sqmusic/trunk/sqm/sqmusic.v Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.