mirror of
https://github.com/UzixLS/zx-sizif-xxs.git
synced 2025-07-18 23:01:40 +03:00

When this feature enabled: * Frequency sets to 14MHz on esxdos activity - for fastest loading from sd card; * Frequency sets to 14MHz on 48 BASIC startup; * Frequency sets to 3.5MHz within ~1ms after #FE port access - this allows to load from tape within turbo mode. Also this improves beeper sound effects; * Otherwise user configured frequency is used.
529 lines
11 KiB
Systemverilog
Executable File
529 lines
11 KiB
Systemverilog
Executable File
import common::*;
|
|
|
|
module zx_ula(
|
|
input clk_in,
|
|
|
|
output reg n_rstcpu,
|
|
output reg clkcpu,
|
|
|
|
inout [18:0] va,
|
|
inout [7:0] vd,
|
|
input [15:13] a,
|
|
|
|
output n_vrd,
|
|
output n_vwr,
|
|
|
|
input n_rd,
|
|
input n_wr,
|
|
input n_mreq,
|
|
input n_iorq,
|
|
input n_m1,
|
|
input n_rfsh,
|
|
output reg n_int,
|
|
output n_nmi,
|
|
|
|
output [7:0] composite,
|
|
input [1:0] reserv,
|
|
|
|
output snd_l,
|
|
output snd_r,
|
|
|
|
input ps2_clk,
|
|
input ps2_dat,
|
|
|
|
input sd_cd,
|
|
input sd_miso_tape_in,
|
|
output sd_mosi_tape_out,
|
|
output reg sd_sck,
|
|
output reg sd_cs
|
|
);
|
|
|
|
/* CLOCK */
|
|
wire clk28 = clk_in;
|
|
wire clk168;
|
|
wire rst_n;
|
|
pll pll0(.inclk0(clk_in), .c0(clk168), .locked(rst_n));
|
|
reg [1:0] clk168_en42_cnt = 0;
|
|
reg clk168_en42;
|
|
always @(posedge clk168) begin
|
|
clk168_en42 <= clk168_en42_cnt == 2'b00;
|
|
clk168_en42_cnt <= clk168_en42_cnt + 1'b1;
|
|
end
|
|
|
|
|
|
/* SHARED DEFINITIONS */
|
|
machine_t machine;
|
|
turbo_t turbo;
|
|
wire ps2_key_reset, ps2_key_pause;
|
|
wire [2:0] border;
|
|
wire magic_reboot, magic_beeper;
|
|
wire up_active;
|
|
wire [2:0] ram_page128;
|
|
wire init_done;
|
|
wire mem_bus_valid;
|
|
wire mem_wait;
|
|
wire basic48_paged;
|
|
wire sd_indication;
|
|
|
|
|
|
/* CPU BUS */
|
|
cpu_bus bus();
|
|
always @(negedge clk28) begin
|
|
bus.a_raw <= {a[15:13], va[12:0]};
|
|
bus.iorq <= ~n_iorq;
|
|
bus.mreq <= ~n_mreq;
|
|
bus.m1 <= ~n_m1;
|
|
bus.rfsh <= ~n_rfsh;
|
|
bus.rd <= ~n_rd;
|
|
bus.wr <= ~n_wr;
|
|
end
|
|
always @(posedge clk28) begin
|
|
bus.a <= mem_bus_valid? {a[15:13], va[12:0]} : bus.a;
|
|
bus.d <= mem_bus_valid? vd : bus.d;
|
|
bus.ioreq <= (mem_bus_valid | bus.ioreq) & ~n_iorq & n_m1;
|
|
bus.memreq <= (mem_bus_valid | bus.memreq) & ~n_mreq & n_rfsh;
|
|
bus.memreq_rise <= mem_bus_valid & ~bus.memreq & ~n_mreq & n_rfsh;
|
|
end
|
|
|
|
|
|
/* RESET */
|
|
reg usrrst_n = 0;
|
|
always @(posedge clk28) begin
|
|
usrrst_n <= (!rst_n || ps2_key_reset || magic_reboot)? 1'b0 : 1'b1;
|
|
end
|
|
|
|
|
|
/* VIDEO CONTROLLER */
|
|
wire [5:0] r, g, b;
|
|
wire hsync, vsync, csync0;
|
|
wire video_contention, port_ff_active;
|
|
wire video_read_req, video_read_req_ack, video_read_data_valid;
|
|
wire [14:0] video_read_addr;
|
|
wire [5:0] up_ink_addr, up_paper_addr;
|
|
wire [7:0] up_ink_data, up_paper_data;
|
|
wire [8:0] vc, hc;
|
|
wire [7:0] port_ff_data;
|
|
wire clk14, clk7, clk35, ck14, ck7, ck35;
|
|
video video0(
|
|
.rst_n(usrrst_n),
|
|
.clk28(clk28),
|
|
|
|
.machine(machine),
|
|
.border({border[2] ^ sd_indication, border[1] ^ magic_beeper, border[0]}),
|
|
|
|
.r(r),
|
|
.g(g),
|
|
.b(b),
|
|
.csync(csync0),
|
|
.vsync(vsync),
|
|
.hsync(hsync),
|
|
|
|
.read_req(video_read_req),
|
|
.read_req_addr(video_read_addr),
|
|
.read_req_ack(video_read_req_ack),
|
|
.read_data_valid(video_read_data_valid),
|
|
.read_data(vd),
|
|
|
|
.up_en(up_active),
|
|
.up_ink_addr(up_ink_addr),
|
|
.up_ink_data(up_ink_data),
|
|
.up_paper_addr(up_paper_addr),
|
|
.up_paper_data(up_paper_data),
|
|
|
|
.contention(video_contention),
|
|
.port_ff_active(port_ff_active),
|
|
.port_ff_data(port_ff_data),
|
|
|
|
.vc_out(vc),
|
|
.hc_out(hc),
|
|
.clk14(clk14),
|
|
.clk7(clk7),
|
|
.clk35(clk35),
|
|
.ck14(ck14),
|
|
.ck7(ck7),
|
|
.ck35(ck35)
|
|
);
|
|
|
|
|
|
/* VIDEO OUTPUT */
|
|
vencode vencode(
|
|
.clk(clk168),
|
|
.clk_en(clk168_en42),
|
|
.videoR(r),
|
|
.videoG(g),
|
|
.videoB(b),
|
|
.videoHS_n(hsync),
|
|
.videoVS_n(vsync),
|
|
.videoPS_n(csync0),
|
|
.videoV(composite)
|
|
);
|
|
|
|
|
|
/* PS/2 KEYBOARD */
|
|
wire [4:0] ps2_kd;
|
|
wire ps2_key_magic;
|
|
wire ps2_joy_up, ps2_joy_down, ps2_joy_left, ps2_joy_right, ps2_joy_fire;
|
|
ps2 #(.CLK_FREQ(28_000_000)) ps2_0(
|
|
.rst_n(rst_n),
|
|
.clk(clk28),
|
|
.ps2_clk_in(ps2_clk),
|
|
.ps2_dat_in(ps2_dat),
|
|
.zxkb_addr(bus.a[15:8]),
|
|
.zxkb_data(ps2_kd),
|
|
.key_magic(ps2_key_magic),
|
|
.key_reset(ps2_key_reset),
|
|
.key_pause(ps2_key_pause),
|
|
.joy_up(ps2_joy_up),
|
|
.joy_down(ps2_joy_down),
|
|
.joy_left(ps2_joy_left),
|
|
.joy_right(ps2_joy_right),
|
|
.joy_fire(ps2_joy_fire)
|
|
);
|
|
|
|
|
|
/* CPU CONTROLLER */
|
|
wire n_int_next, clkcpu_ck, snow, cpu_contention;
|
|
cpu cpu0(
|
|
.rst_n(usrrst_n),
|
|
.clk28(clk28),
|
|
.clk14(clk14),
|
|
.clk7(clk7),
|
|
.clk35(clk35),
|
|
.ck14(ck14),
|
|
.ck7(ck7),
|
|
|
|
.bus(bus),
|
|
|
|
.vc(vc),
|
|
.hc(hc),
|
|
.ram_page128(ram_page128),
|
|
.machine(machine),
|
|
.turbo(turbo),
|
|
.hold(mem_wait),
|
|
.video_contention(video_contention),
|
|
.init_done_in(init_done),
|
|
|
|
.n_rstcpu_out(n_rstcpu),
|
|
.clkcpu(clkcpu),
|
|
.clkcpu_ck(clkcpu_ck),
|
|
.n_int(n_int),
|
|
.n_int_next(n_int_next),
|
|
.snow(snow),
|
|
.contention(cpu_contention)
|
|
);
|
|
|
|
|
|
/* MAGIC */
|
|
wire div_map;
|
|
wire div_mapram;
|
|
wire [7:0] magic_dout;
|
|
wire magic_dout_active;
|
|
wire magic_mode, magic_map;
|
|
wire joy_sinclair, up_en, ay_en, covox_en, soundrive_en;
|
|
panning_t panning;
|
|
wire divmmc_en, zc_en, sd_indication_en;
|
|
assign sd_indication = sd_indication_en & ~sd_cs;
|
|
|
|
magic magic0(
|
|
.rst_n(n_rstcpu),
|
|
.clk28(clk28),
|
|
.ck35(ck35),
|
|
|
|
.bus(bus),
|
|
.d_out(magic_dout),
|
|
.d_out_active(magic_dout_active),
|
|
|
|
.n_int(n_int),
|
|
.n_int_next(n_int_next),
|
|
.n_nmi(n_nmi),
|
|
|
|
.magic_button(ps2_key_magic),
|
|
.pause_button(ps2_key_pause),
|
|
.div_paged(div_map && !div_mapram),
|
|
.basic48_paged(basic48_paged),
|
|
|
|
.magic_mode(magic_mode),
|
|
.magic_map(magic_map),
|
|
|
|
.magic_reboot(magic_reboot),
|
|
.magic_beeper(magic_beeper),
|
|
.machine(machine),
|
|
.turbo(turbo),
|
|
.joy_sinclair(joy_sinclair),
|
|
.panning(panning),
|
|
.divmmc_en(divmmc_en),
|
|
.zc_en(zc_en),
|
|
.ulaplus_en(up_en),
|
|
.ay_en(ay_en),
|
|
.covox_en(covox_en),
|
|
.soundrive_en(soundrive_en),
|
|
.sd_indication_en(sd_indication_en)
|
|
);
|
|
|
|
|
|
/* PORTS */
|
|
wire [7:0] ports_dout;
|
|
wire ports_dout_active;
|
|
wire beeper, tape_out;
|
|
wire video_page;
|
|
wire rom_page128;
|
|
wire [2:0] ram_pageext;
|
|
wire [2:0] port_1ffd;
|
|
wire [4:0] port_dffd;
|
|
ports ports0 (
|
|
.rst_n(n_rstcpu),
|
|
.clk28(clk28),
|
|
|
|
.bus(bus),
|
|
.d_out(ports_dout),
|
|
.d_out_active(ports_dout_active),
|
|
|
|
.en_kempston(!joy_sinclair),
|
|
.en_sinclair(joy_sinclair),
|
|
|
|
.machine(machine),
|
|
.port_ff_active(port_ff_active),
|
|
.port_ff_data(port_ff_data),
|
|
.kd(ps2_kd),
|
|
.kempston_data({3'b000, ps2_joy_fire, ps2_joy_up, ps2_joy_down, ps2_joy_left, ps2_joy_right}),
|
|
.magic_map(magic_map),
|
|
.tape_in(sd_miso_tape_in),
|
|
|
|
.tape_out(tape_out),
|
|
.beeper(beeper),
|
|
.border(border),
|
|
.video_page(video_page),
|
|
.rom_page128(rom_page128),
|
|
.ram_page128(ram_page128),
|
|
.ram_pageext(ram_pageext),
|
|
.port_1ffd(port_1ffd),
|
|
.port_dffd(port_dffd)
|
|
);
|
|
|
|
|
|
/* AY TURBOSOUND */
|
|
wire turbosound_dout_active;
|
|
wire [7:0] turbosound_dout;
|
|
wire [7:0] ay_a0, ay_b0, ay_c0, ay_a1, ay_b1, ay_c1;
|
|
turbosound turbosound0(
|
|
.rst_n(n_rstcpu),
|
|
.clk28(clk28),
|
|
.ck35(ck35),
|
|
.en(ay_en),
|
|
.en_ts(1'b1),
|
|
|
|
.bus(bus),
|
|
.d_out(turbosound_dout),
|
|
.d_out_active(turbosound_dout_active),
|
|
|
|
.ay_a0(ay_a0),
|
|
.ay_b0(ay_b0),
|
|
.ay_c0(ay_c0),
|
|
.ay_a1(ay_a1),
|
|
.ay_b1(ay_b1),
|
|
.ay_c1(ay_c1)
|
|
);
|
|
|
|
|
|
/* COVOX & SOUNDRIVE */
|
|
wire [7:0] soundrive_l0, soundrive_l1, soundrive_r0, soundrive_r1;
|
|
soundrive soundrive0(
|
|
.rst_n(n_rstcpu),
|
|
.clk28(clk28),
|
|
.en_covox(covox_en),
|
|
.en_specdrum(covox_en),
|
|
.en_soundrive(soundrive_en),
|
|
|
|
.bus(bus),
|
|
|
|
.ch_l0(soundrive_l0),
|
|
.ch_l1(soundrive_l1),
|
|
.ch_r0(soundrive_r0),
|
|
.ch_r1(soundrive_r1)
|
|
);
|
|
|
|
|
|
/* SOUND MIXER */
|
|
mixer mixer0(
|
|
.rst_n(usrrst_n),
|
|
.clk28(clk28),
|
|
|
|
.beeper(beeper ^ magic_beeper),
|
|
.tape_out(tape_out),
|
|
.tape_in((divmmc_en || zc_en)? sd_indication : sd_miso_tape_in),
|
|
.ay_a0(ay_a0),
|
|
.ay_b0(ay_b0),
|
|
.ay_c0(ay_c0),
|
|
.ay_a1(ay_a1),
|
|
.ay_b1(ay_b1),
|
|
.ay_c1(ay_c1),
|
|
.sd_l0(soundrive_l0),
|
|
.sd_l1(soundrive_l1),
|
|
.sd_r0(soundrive_r0),
|
|
.sd_r1(soundrive_r1),
|
|
|
|
.ay_acb(panning == PANNING_ACB),
|
|
.mono(panning == PANNING_MONO),
|
|
|
|
.dac_l(snd_l),
|
|
.dac_r(snd_r)
|
|
);
|
|
|
|
|
|
/* DIVMMC */
|
|
wire div_ram, div_ramwr_mask, div_dout_active;
|
|
wire [7:0] div_dout;
|
|
wire [3:0] div_page;
|
|
wire sd_mosi0;
|
|
divmmc divmmc0(
|
|
.rst_n(n_rstcpu),
|
|
.clk28(clk28),
|
|
.ck14(ck14),
|
|
.ck7(ck7),
|
|
.en(divmmc_en),
|
|
.en_hooks(divmmc_en),
|
|
.en_zc(zc_en),
|
|
|
|
.bus(bus),
|
|
.d_out(div_dout),
|
|
.d_out_active(div_dout_active),
|
|
|
|
.sd_cd(sd_cd),
|
|
.sd_miso(sd_miso_tape_in),
|
|
.sd_mosi(sd_mosi0),
|
|
.sd_sck(sd_sck),
|
|
.sd_cs(sd_cs),
|
|
|
|
.rammap(port_dffd[4] | port_1ffd[0]),
|
|
.mask_hooks(magic_map),
|
|
.mask_nmi_hook(magic_mode),
|
|
.basic48_paged(basic48_paged),
|
|
|
|
.page(div_page),
|
|
.map(div_map),
|
|
.mapram(div_mapram),
|
|
.ram(div_ram),
|
|
.ramwr_mask(div_ramwr_mask)
|
|
);
|
|
assign sd_mosi_tape_out = (divmmc_en || zc_en)? sd_mosi0 : tape_out;
|
|
|
|
|
|
/* ULAPLUS */
|
|
wire up_dout_active;
|
|
wire [7:0] up_dout;
|
|
ulaplus ulaplus0(
|
|
.rst_n(n_rstcpu),
|
|
.clk28(clk28),
|
|
.en(up_en),
|
|
|
|
.bus(bus),
|
|
.d_out(up_dout),
|
|
.d_out_active(up_dout_active),
|
|
|
|
.active(up_active),
|
|
.read_addr1(up_ink_addr),
|
|
.read_data1(up_ink_data),
|
|
.read_addr2(up_paper_addr),
|
|
.read_data2(up_paper_data)
|
|
);
|
|
|
|
|
|
/* MEMORY INITIALIZER */
|
|
wire rom2ram_clk = clk7;
|
|
wire [16:0] rom2ram_ram_address, rom2ram_rom_address;
|
|
wire [7:0] rom2ram_datain, rom2ram_dataout;
|
|
wire rom2ram_rom_rden;
|
|
wire rom2ram_rom_data_ready;
|
|
wire rom2ram_ram_wren;
|
|
wire rom2ram_active;
|
|
assign init_done = !rom2ram_active;
|
|
reg [1:0] rom2ram_init;
|
|
always @(posedge rom2ram_clk or negedge rst_n) begin
|
|
if (!rst_n)
|
|
rom2ram_init <= 0;
|
|
else if (rom2ram_init != 3)
|
|
rom2ram_init <= rom2ram_init + 1'b1;
|
|
end
|
|
rom2ram rom2ram0(
|
|
.clock(rom2ram_clk),
|
|
.init(rom2ram_init == 2),
|
|
.datain(rom2ram_datain),
|
|
.rom_data_ready(rom2ram_rom_data_ready),
|
|
|
|
.init_busy(rom2ram_active),
|
|
.rom_address(rom2ram_rom_address),
|
|
.rom_rden(rom2ram_rom_rden),
|
|
.ram_wren(rom2ram_ram_wren),
|
|
.ram_address(rom2ram_ram_address),
|
|
.dataout(rom2ram_dataout)
|
|
);
|
|
|
|
localparam ROM_OFFSET = 24'h13256;
|
|
wire [23:0] asmi_addr = ROM_OFFSET + rom2ram_rom_address;
|
|
asmi asmi0(
|
|
.clkin(rom2ram_clk),
|
|
.read(rom2ram_rom_rden),
|
|
.rden(rom2ram_active),
|
|
.addr(asmi_addr),
|
|
.reset(!rst_n),
|
|
|
|
.dataout(rom2ram_datain),
|
|
.busy(),
|
|
.data_valid(rom2ram_rom_data_ready)
|
|
);
|
|
|
|
|
|
/* MEMORY CONTROLLER */
|
|
mem mem0(
|
|
.rst_n(rst_n),
|
|
.clk28(clk28),
|
|
.bus(bus),
|
|
.va(va),
|
|
.vd(vd),
|
|
.n_vrd(n_vrd),
|
|
.n_vwr(n_vwr),
|
|
|
|
.bus_valid(mem_bus_valid),
|
|
.cpuwait(mem_wait),
|
|
.basic48_paged(basic48_paged),
|
|
|
|
.machine(machine),
|
|
.turbo(turbo),
|
|
.cpu_contention(cpu_contention),
|
|
.magic_map(magic_map),
|
|
.ram_page128(ram_page128),
|
|
.rom_page128(rom_page128),
|
|
.port_1ffd(port_1ffd),
|
|
.port_dffd(port_dffd),
|
|
.ram_pageext(ram_pageext),
|
|
.div_ram(div_ram),
|
|
.div_map(div_map),
|
|
.div_ramwr_mask(div_ramwr_mask),
|
|
.div_page(div_page),
|
|
|
|
.snow(snow),
|
|
.video_page(video_page),
|
|
.video_read_req(video_read_req),
|
|
.video_read_addr(video_read_addr),
|
|
.video_read_req_ack(video_read_req_ack),
|
|
.video_data_valid(video_read_data_valid),
|
|
|
|
.rom2ram_ram_address(rom2ram_ram_address),
|
|
.rom2ram_ram_wren(rom2ram_ram_wren),
|
|
.rom2ram_dataout(rom2ram_dataout),
|
|
|
|
.magic_dout_active(magic_dout_active),
|
|
.magic_dout(magic_dout),
|
|
.up_dout_active(up_dout_active),
|
|
.up_dout(up_dout),
|
|
.div_dout_active(div_dout_active),
|
|
.div_dout(div_dout),
|
|
.turbosound_dout_active(turbosound_dout_active),
|
|
.turbosound_dout(turbosound_dout),
|
|
.ports_dout_active(ports_dout_active),
|
|
.ports_dout(ports_dout)
|
|
);
|
|
|
|
|
|
endmodule
|