3
3
//
4
4
// This version uses the Tang Nano 20K SDRAM for extended functionality
5
5
//
6
+ // (c) 2023,2024 Ed Anuff <ed@a2fpga.com>
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
+ //
6
20
7
21
// Using the Gowin IDE
8
22
`define GW_IDE
9
23
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
11
26
12
27
`undef ENSONIQ
13
- `undef PICOSOC
28
+ `define PICOSOC
29
+ `undef DISKII
14
30
15
31
module top # (
16
32
parameter int CLOCK_SPEED_HZ = 54_000_000 ,
@@ -29,6 +45,9 @@ module top #(
29
45
parameter bit SUPERSERIAL_ENABLE = 0 ,
30
46
parameter SUPERSERIAL_SLOT = 2 ,
31
47
48
+ parameter bit DISK_II_ENABLE = 1 ,
49
+ parameter DISK_II_SLOT = 5 ,
50
+
32
51
parameter bit ENSONIQ_ENABLE = 1 ,
33
52
34
53
parameter bit CLEAR_APPLE_VIDEO_RAM = 1 , // Clear video ram on startup
@@ -160,13 +179,31 @@ module top #(
160
179
`ifdef ENSONIQ
161
180
localparam GLU_MEM_PORT = 2 ;
162
181
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
166
191
localparam NUM_PORTS = 4 ;
192
+ `endif
167
193
`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
168
203
localparam NUM_PORTS = 2 ;
204
+ `endif
169
205
`endif
206
+
170
207
localparam PORT_ADDR_WIDTH = 21 ;
171
208
localparam DATA_WIDTH = 32 ;
172
209
localparam DQM_WIDTH = 4 ;
@@ -372,6 +409,8 @@ module top #(
372
409
wire [7 : 0 ] diskii_d_w;
373
410
wire diskii_rd;
374
411
412
+ `ifdef DISKII
413
+
375
414
DiskII # (
376
415
.ENABLE (DISK_II_ENABLE ),
377
416
.SLOT (DISK_II_SLOT )
@@ -385,6 +424,25 @@ module top #(
385
424
386
425
.volumes (volumes)
387
426
);
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
+
388
446
389
447
`else
390
448
@@ -420,6 +478,10 @@ module top #(
420
478
assign f18a_gpu_if.raddr = 13'b0 ;
421
479
assign f18a_gpu_if.gstatus = 7'b0 ;
422
480
481
+
482
+ wire [7 : 0 ] diskii_d_w = 8'b0 ;
483
+ wire diskii_rd = 1'b0 ;
484
+
423
485
`endif
424
486
425
487
// Video
@@ -593,8 +655,10 @@ module top #(
593
655
594
656
wire ssc_uart_rx;
595
657
wire ssc_uart_tx;
658
+ `ifndef PICOSOC
596
659
assign ssc_uart_rx = uart_rx;
597
660
assign uart_tx = ssc_uart_tx;
661
+ `endif
598
662
599
663
SuperSerial # (
600
664
.ENABLE (SUPERSERIAL_ENABLE ),
@@ -614,83 +678,72 @@ module top #(
614
678
615
679
// Data output
616
680
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 ;
618
682
619
683
assign data_out_w = ssc_rd ? ssc_d_w :
620
684
ssp_rd ? ssp_d_w :
621
685
mb_rd ? mb_d_w :
686
+ diskii_rd ? diskii_d_w :
622
687
a2bus_if.data;
623
688
624
689
// Interrupts
625
690
626
691
assign irq_n_w = mb_irq_n && vdp_irq_n && ssc_irq_n;
627
692
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
+ );
629
702
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 ;
633
711
634
712
localparam AUDIO_RATE = 44100 ;
635
713
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
+ );
653
741
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
680
743
681
- // //
682
744
logic [2 : 0 ] tmds;
683
745
wire tmdsClk;
684
746
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
-
694
747
wire scanline_en = scanlines_w && hdmi_y[0 ];
695
748
696
749
hdmi # (
@@ -708,7 +761,7 @@ module top #(
708
761
) hdmi (
709
762
.clk_pixel_x5 (clk_hdmi_w),
710
763
.clk_pixel (clk_pixel_w),
711
- .clk_audio (clk_audio_r ),
764
+ .clk_audio (clk_audio_w ),
712
765
.rgb ({
713
766
scanline_en ? { 1'b0 , rgb_r_w[7 : 1 ]} : rgb_r_w,
714
767
scanline_en ? { 1'b0 , rgb_g_w[7 : 1 ]} : rgb_g_w,
@@ -735,7 +788,9 @@ module top #(
735
788
);
736
789
737
790
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};
739
794
else led <= { ! vdp_unlocked_w, ~ vdp_gmode_w} ;
740
795
// else led <= {!vdp_unlocked_w, dip_switches_n_w};
741
796
end
0 commit comments