33//
44// This version uses the Tang Nano 20K SDRAM for extended functionality
55//
6+ // (c) 2023,2024 Ed Anuff <[email protected] > 7+ //
8+ // Permission to use, copy, modify, and/or distribute this software for any
9+ // purpose with or without fee is hereby granted, provided that the above
10+ // copyright notice and this permission notice appear in all copies.
11+ //
12+ // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13+ // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14+ // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15+ // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16+ // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17+ // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18+ // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19+ //
620
721// Using the Gowin IDE
822`define GW_IDE
923
10- // Ensoniq and PicoSoC are included via defines in the top module
24+ // Ensoniq, PicoSoC, and DiskII are included via defines in the top module
25+ // Disk II requires PicoSoC
1126
1227`undef ENSONIQ
13- `undef PICOSOC
28+ `define PICOSOC
29+ `undef DISKII
1430
1531module top # (
1632 parameter int CLOCK_SPEED_HZ = 54_000_000 ,
@@ -29,6 +45,9 @@ module top #(
2945 parameter bit SUPERSERIAL_ENABLE = 0 ,
3046 parameter SUPERSERIAL_SLOT = 2 ,
3147
48+ parameter bit DISK_II_ENABLE = 1 ,
49+ parameter DISK_II_SLOT = 5 ,
50+
3251 parameter bit ENSONIQ_ENABLE = 1 ,
3352
3453 parameter bit CLEAR_APPLE_VIDEO_RAM = 1 , // Clear video ram on startup
@@ -160,13 +179,31 @@ module top #(
160179`ifdef ENSONIQ
161180 localparam GLU_MEM_PORT = 2 ;
162181 localparam DOC_MEM_PORT = 3 ;
163- `endif
164-
165- `ifdef ENSONIQ
182+ `ifdef PICOSOC
183+ localparam SOC_MEM_PORT = 4 ;
184+ `ifdef DISKII
185+ localparam RAMDISK_MEM_PORT = 5 ;
186+ localparam NUM_PORTS = 6 ;
187+ `else
188+ localparam NUM_PORTS = 5 ;
189+ `endif
190+ `else
166191 localparam NUM_PORTS = 4 ;
192+ `endif
167193`else
194+ `ifdef PICOSOC
195+ localparam SOC_MEM_PORT = 2 ;
196+ `ifdef DISKII
197+ localparam RAMDISK_MEM_PORT = 3 ;
198+ localparam NUM_PORTS = 4 ;
199+ `else
200+ localparam NUM_PORTS = 3 ;
201+ `endif
202+ `else
168203 localparam NUM_PORTS = 2 ;
204+ `endif
169205`endif
206+
170207 localparam PORT_ADDR_WIDTH = 21 ;
171208 localparam DATA_WIDTH = 32 ;
172209 localparam DQM_WIDTH = 4 ;
@@ -372,6 +409,8 @@ module top #(
372409 wire [7 : 0 ] diskii_d_w;
373410 wire diskii_rd;
374411
412+ `ifdef DISKII
413+
375414 DiskII # (
376415 .ENABLE (DISK_II_ENABLE ),
377416 .SLOT (DISK_II_SLOT )
@@ -385,6 +424,25 @@ module top #(
385424
386425 .volumes (volumes)
387426 );
427+ `else
428+ assign diskii_d_w = 8'b0 ;
429+ assign diskii_rd = 1'b0 ;
430+
431+ assign volumes[0 ].active = 1'b0 ;
432+ assign volumes[0 ].lba = 32'd0 ;
433+ assign volumes[0 ].blk_cnt = 6'd0 ;
434+ assign volumes[0 ].rd = 1'b0 ;
435+ assign volumes[0 ].wr = 1'b0 ;
436+
437+
438+ assign volumes[1 ].active = 1'b0 ;
439+ assign volumes[1 ].lba = 32'd0 ;
440+ assign volumes[1 ].blk_cnt = 6'd0 ;
441+ assign volumes[1 ].rd = 1'b0 ;
442+ assign volumes[1 ].wr = 1'b0 ;
443+
444+ `endif
445+
388446
389447`else
390448
@@ -420,6 +478,10 @@ module top #(
420478 assign f18a_gpu_if.raddr = 13'b0 ;
421479 assign f18a_gpu_if.gstatus = 7'b0 ;
422480
481+
482+ wire [7 : 0 ] diskii_d_w = 8'b0 ;
483+ wire diskii_rd = 1'b0 ;
484+
423485`endif
424486
425487 // Video
@@ -593,8 +655,10 @@ module top #(
593655
594656 wire ssc_uart_rx;
595657 wire ssc_uart_tx;
658+ `ifndef PICOSOC
596659 assign ssc_uart_rx = uart_rx;
597660 assign uart_tx = ssc_uart_tx;
661+ `endif
598662
599663 SuperSerial # (
600664 .ENABLE (SUPERSERIAL_ENABLE ),
@@ -614,83 +678,72 @@ module top #(
614678
615679 // Data output
616680
617- assign data_out_en_w = ssp_rd || mb_rd || ssc_rd;
681+ assign data_out_en_w = ssp_rd || mb_rd || ssc_rd || diskii_rd ;
618682
619683 assign data_out_w = ssc_rd ? ssc_d_w :
620684 ssp_rd ? ssp_d_w :
621685 mb_rd ? mb_d_w :
686+ diskii_rd ? diskii_d_w :
622687 a2bus_if.data;
623688
624689 // Interrupts
625690
626691 assign irq_n_w = mb_irq_n && vdp_irq_n && ssc_irq_n;
627692
628- // HDMI
693+ // Audio
694+
695+ wire speaker_audio_w;
696+
697+ apple_speaker apple_speaker (
698+ .a2bus_if (a2bus_if),
699+ .enable (APPLE_SPEAKER_ENABLE | sw_apple_speaker_w),
700+ .speaker_o (speaker_audio_w)
701+ );
629702
630- // TODO - Needs to incorporate the audio filter code from a2n20v2
631- // IMPORTANT - the Ensoniq module outputs signed 16-bit audio, so we need to
632- // properly mix it with the apple audio and the mockingboard audio
703+ localparam [31 : 0 ] aflt_rate = 7_056_000 ;
704+ localparam [39 : 0 ] acx = 4258969 ;
705+ localparam [7 : 0 ] acx0 = 3 ;
706+ localparam [7 : 0 ] acx1 = 3 ;
707+ localparam [7 : 0 ] acx2 = 1 ;
708+ localparam [23 : 0 ] acy0 = - 24'd6216759 ;
709+ localparam [23 : 0 ] acy1 = 24'd6143386 ;
710+ localparam [23 : 0 ] acy2 = - 24'd2023767 ;
633711
634712 localparam AUDIO_RATE = 44100 ;
635713 localparam AUDIO_BIT_WIDTH = 16 ;
636- localparam AUDIO_CLK_COUNT = (CLOCK_SPEED_HZ / 2 ) / AUDIO_RATE ;
637- logic [$clog2 (AUDIO_CLK_COUNT )- 1 : 0 ] audio_counter_r;
638- logic clk_audio_r;
639-
640- always_ff @ (posedge clk_pixel_w)
641- begin
642- audio_counter_r <= (audio_counter_r == AUDIO_CLK_COUNT ) ? 1'd0 : audio_counter_r + 1'd1 ;
643- clk_audio_r <= audio_counter_r == AUDIO_CLK_COUNT ;
644- end
645-
646- reg speaker_bit;
647- always @ (posedge clk_logic_w or negedge system_reset_n_w) begin
648- if (! system_reset_n_w) begin
649- speaker_bit <= 1'b0 ;
650- end else if (phi1_posedge && (a2bus_if.addr[15 : 0 ] == 16'hC030 ) && ! a2bus_if.m2sel_n)
651- speaker_bit <= ! speaker_bit;
652- end
714+ wire clk_audio_w;
715+ wire [15 : 0 ] audio_sample_word[1 : 0 ];
716+ audio_out # (
717+ .CLK_RATE (CLOCK_SPEED_HZ / 2 ),
718+ .AUDIO_RATE (AUDIO_RATE )
719+ ) audio_out
720+ (
721+ .reset (~ device_reset_n_w),
722+ .clk (clk_pixel_w),
723+
724+ .flt_rate (aflt_rate),
725+ .cx (acx),
726+ .cx0 (acx0),
727+ .cx1 (acx1),
728+ .cx2 (acx2),
729+ .cy0 (acy0),
730+ .cy1 (acy1),
731+ .cy2 (acy2),
732+
733+ .is_signed (1'b0 ),
734+ .core_l (ssp_audio_w + { mb_audio_l, 5'b00 } + { speaker_audio_w, 13'b0 } ),
735+ .core_r (ssp_audio_w + { mb_audio_r, 5'b00 } + { speaker_audio_w, 13'b0 } ),
736+
737+ .audio_clk (clk_audio_w),
738+ .audio_l (audio_sample_word[0 ]),
739+ .audio_r (audio_sample_word[1 ])
740+ );
653741
654- // Apple intermal audio toggles a +5V signal to a speaker. We cannot simply leave a square wave
655- // indefinitaley on the HDMI audio line, so we need to generate a pulse of a maximum length.
656- // If we don't do this, the HDMI audio line will essentially have an amplitude offset, which
657- // will cause the HDMI receiver to clip the audio or amplify anything such as the Mockingboard
658- // audio that is added to it.
659-
660- reg speaker_audio;
661- reg [7 : 0 ] speaker_audio_counter;
662- reg prev_speaker_bit;
663-
664- always_ff @ (posedge clk_pixel_w) begin
665- if (clk_audio_r) begin
666- if (speaker_bit != prev_speaker_bit) begin
667- speaker_audio_counter <= 8'b11111111 ;
668- end else if (speaker_audio_counter != 0 ) begin
669- speaker_audio_counter <= speaker_audio_counter - 8'd1 ;
670- end
671- prev_speaker_bit <= speaker_bit;
672-
673- if (prev_speaker_bit && (speaker_audio_counter != 0 )) begin
674- speaker_audio <= APPLE_SPEAKER_ENABLE | sw_apple_speaker_w;
675- end else begin
676- speaker_audio <= 1'b0 ;
677- end
678- end
679- end
742+ // HDMI
680743
681- // //
682744 logic [2 : 0 ] tmds;
683745 wire tmdsClk;
684746
685- // wire [15:0] sample = {ssp_psg_mix_audio_o, 2'b00};
686- reg [15 : 0 ] audio_sample_word[1 : 0 ], audio_sample_word0[1 : 0 ];
687- always @ (posedge clk_pixel_w) begin // crossing clock domain
688- audio_sample_word0[0 ] <= ssp_audio_w + { mb_audio_l, 4'b00 } + { speaker_audio, 13'b0 } + sg_audio_l;
689- audio_sample_word[0 ] <= audio_sample_word0[0 ];
690- audio_sample_word0[1 ] <= ssp_audio_w + { mb_audio_r, 4'b00 } + { speaker_audio, 13'b0 } + sg_audio_r;
691- audio_sample_word[1 ] <= audio_sample_word0[1 ];
692- end
693-
694747 wire scanline_en = scanlines_w && hdmi_y[0 ];
695748
696749 hdmi # (
@@ -708,7 +761,7 @@ module top #(
708761 ) hdmi (
709762 .clk_pixel_x5 (clk_hdmi_w),
710763 .clk_pixel (clk_pixel_w),
711- .clk_audio (clk_audio_r ),
764+ .clk_audio (clk_audio_w ),
712765 .rgb ({
713766 scanline_en ? { 1'b0 , rgb_r_w[7 : 1 ]} : rgb_r_w,
714767 scanline_en ? { 1'b0 , rgb_g_w[7 : 1 ]} : rgb_g_w,
@@ -735,7 +788,9 @@ module top #(
735788 );
736789
737790 always @ (posedge clk_logic_w) begin
738- if (! s2) led <= { ! a2mem_if.TEXT_MODE , ! a2mem_if.MIXED_MODE , ! a2mem_if.HIRES_MODE , ! a2mem_if.AN3 , ! a2mem_if.STORE80 } ;
791+ if (! s2) led <= { ! a2mem_if.TEXT_MODE , ! a2mem_if.SHRG_MODE , ! a2mem_if.HIRES_MODE , ! a2mem_if.RAMWRT , ! a2mem_if.STORE80 } ;
792+ // if (!s2) led <= {!a2mem_if.TEXT_MODE, !a2mem_if.MIXED_MODE, !a2mem_if.HIRES_MODE, !a2mem_if.RAMWRT, !a2mem_if.STORE80};
793+ // if (!s2) led <= {!a2mem_if.TEXT_MODE, !a2mem_if.MIXED_MODE, !a2mem_if.HIRES_MODE, !a2mem_if.AN3, !a2mem_if.STORE80};
739794 else led <= { ! vdp_unlocked_w, ~ vdp_gmode_w} ;
740795 // else led <= {!vdp_unlocked_w, dip_switches_n_w};
741796 end
0 commit comments