1
0
mirror of https://github.com/UzixLS/zx-sizif-xxs.git synced 2025-07-19 07:11:28 +03:00

12 Commits

Author SHA1 Message Date
64a4bb69c0 add auto cpu frequency
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.
2024-01-10 15:39:07 +03:00
df7f0e55e6 fix basic 128 crashes when divmmc is enabled 2024-01-10 15:35:41 +03:00
c8d83ac5c1 refactor memory controller
Also this commit fixes ula+ io contention for classic timings. This
affects ham256.tap.
2024-01-08 20:15:34 +03:00
c69b7c8ba4 improve 128 int timings 2024-01-07 17:51:02 +03:00
76b4d4d838 add option to disable sd indication on border 2024-01-07 17:47:20 +03:00
e7552c5743 rom: minor refactors 2024-01-07 17:22:00 +03:00
a942f43c5a refactor mixer - optimize fpga resources usage 2024-01-06 18:30:42 +03:00
2b263995cc implement ula+ registers reading 2024-01-05 20:32:36 +03:00
34a98edc64 allow nmi call when divmmc's mapram in use 2024-01-04 11:54:04 +03:00
948f4190f3 refactor: rename screen->video, memcontrol->mem, cpucontrol->cpu
no functional changes
2024-01-03 19:05:12 +03:00
48ad108e9c fix support of some ps/2 keyboards with slow clock 2023-10-26 21:01:47 +03:00
671a748207 add fpga firmware file in bin format 2023-03-24 21:58:05 +03:00
31 changed files with 943 additions and 756 deletions

View File

@ -12,11 +12,12 @@ all:
build_rev:
${MAKE} REV=${REV} -C rom_src/ clean all
${MAKE} REV=${REV} -C rom/ clean all
${MAKE} REV=${REV} -C fpga/syn/ clean build sof2jic
${MAKE} REV=${REV} -C fpga/syn/ clean build sof2jic rbf2bin
cp fpga/syn/output/rev_${REV}.jic ${OUTDIR}/rev_${REV}.jic
cat fpga/syn/output/rev_${REV}.bin rom/sizif.rom > ${OUTDIR}/rev_${REV}.bin
clean:
rm -f "${OUTDIR}"
rm -rf "${OUTDIR}"
${MAKE} -C fpga/syn/ clean
${MAKE} -C fpga/tb/ clean
${MAKE} -C rom_src/ clean

View File

@ -50,6 +50,11 @@ Sizif contains 512K RAM. 128K available via 7FFDh port, 128K via DFFDh (Profi st
### SD card
Sizif have preinstalled esxDOS firmware, which provides ability to load TAP, TRD, SCL, Z80 files and save snapshots. To use this you should format SD cart to FAT32 or FAT16 and unpack latest esxDOS release ([link](http://www.esxdos.org/index.html)) to card. Also it's recommended to install Long Filename Browser ([link](https://spectrumcomputing.co.uk/forums/viewtopic.php?t=2553)) to card.
### How to program
There is two options:
1. Program via JTAG connector using USB blaster and Quartus Programmer - use jic file from out folder.
2. Program flash chip directly using TL866 or similar device - use bin file.
### Changelog & current status
* Rev.A - first release. Please note the [errata](pcb/rev.A/ERRATA.txt).
* Rev.B:

View File

@ -6,6 +6,7 @@ endpackage
interface cpu_bus();
reg [15:0] a_raw;
reg [15:0] a;
reg [7:0] d;
reg iorq;
@ -15,8 +16,7 @@ interface cpu_bus();
reg rd;
reg wr;
reg [15:0] a_reg;
reg [7:0] d_reg;
wire ioreq;
wire memreq;
reg ioreq;
reg memreq;
reg memreq_rise;
endinterface

153
fpga/rtl/cpu.sv Normal file
View File

@ -0,0 +1,153 @@
import common::*;
module cpu(
input rst_n,
input clk28,
input clk14,
input clk7,
input clk35,
input ck14,
input ck7,
cpu_bus bus,
input [8:0] vc,
input [8:0] hc,
input video_contention,
input [2:0] ram_page128,
input machine_t machine,
input turbo_t turbo,
input init_done_in,
input hold,
output reg n_rstcpu_out,
output reg clkcpu,
output clkcpu_ck,
output reg n_int,
output reg n_int_next,
output snow,
output contention
);
/* CONTENTION */
wire iorq_contended = bus.ioreq && (~bus.a[0] || (bus.a == 16'hBF3B) || (bus.a == 16'hFF3B)) && (machine != MACHINE_S3);
reg mreq_delayed, iorq_delayed;
always @(posedge clkcpu)
mreq_delayed <= bus.mreq;
always @(posedge clkcpu)
iorq_delayed <= iorq_contended;
wire contention_page = (machine == MACHINE_S3)? ram_page128[2] : ram_page128[0];
wire contention_addr = bus.a_raw[14] & (~bus.a_raw[15] | (bus.a_raw[15] & contention_page));
wire contention_mem = !iorq_contended && !mreq_delayed && contention_addr;
wire contention0 = video_contention && !iorq_delayed && (contention_mem || iorq_contended);
assign contention = clkcpu && contention0 && turbo == TURBO_NONE && (machine == MACHINE_S48 || machine == MACHINE_S128 || machine == MACHINE_S3);
assign snow = video_contention && contention_addr && bus.rfsh && bus.mreq && (machine == MACHINE_S48 || machine == MACHINE_S128);
/* CLOCK */
wire turbo_wait_cond = turbo == TURBO_14 && (bus.rd || bus.wr || (bus.iorq && bus.m1));
reg [2:0] turbo_wait_reg;
reg turbo_wait;
always @* begin
if (bus.iorq)
turbo_wait <= turbo_wait_cond && !turbo_wait_reg[2];
else
turbo_wait <= turbo_wait_cond && !turbo_wait_reg[1];
end
always @(posedge clk28) begin
if (clkcpu != clk14)
turbo_wait_reg <= {turbo_wait_reg[1:0], turbo_wait_cond};
end
reg clkcpu_prev;
assign clkcpu_ck = clkcpu && !clkcpu_prev;
always @(posedge clk28) begin
clkcpu_prev <= clkcpu;
if (contention || hold || turbo_wait)
clkcpu <= clkcpu;
else if (turbo == TURBO_14)
clkcpu <= clk14;
else if (turbo == TURBO_7 && ck14)
clkcpu <= clk7;
else if (turbo == TURBO_5 && ck14 && hc[1])
clkcpu <= clk7;
else if (turbo == TURBO_4 && ck14 && hc[1] && hc[2])
clkcpu <= clk7;
else if (ck7)
clkcpu <= clk35;
end
/* INT GENERATOR */
localparam INT_V_S48 = 248;
localparam INT_H_S48 = 0;
localparam INT_L_S48 = 6'd32;
localparam INT_V_S128 = 248;
localparam INT_H_S128 = 4;
localparam INT_L_S128 = 6'd36;
localparam INT_V_PENT = 239;
localparam INT_H_PENT = 322;
localparam INT_L_PENT = 6'd32;
wire int_begin =
(machine == MACHINE_S48)?
vc == INT_V_S48 && hc == INT_H_S48 :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
vc == INT_V_S128 && hc == INT_H_S128 :
// Pentagon
vc == INT_V_PENT && hc == INT_H_PENT ;
wire [5:0] int_len =
(machine == MACHINE_S48)?
INT_L_S48 :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
INT_L_S128 :
// Pentagon
INT_L_PENT ;
reg [5:0] int_cnt;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
int_cnt <= 0;
n_int_next <= 1'b1;
end
else if ((int_cnt != 0 && clkcpu_ck) || (int_cnt == 0 && int_begin)) begin
int_cnt <= int_cnt + 1'b1;
n_int_next <= (int_cnt < int_len)? 1'b0 : 1'b1;
end
end
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
n_int <= 1'b1;
else if (clkcpu_ck)
n_int <= n_int_next;
end
/* RESET */
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
n_rstcpu_out <= 0;
else if (!init_done_in)
n_rstcpu_out <= 0;
`ifdef TESTBENCH
else if (hc[4])
n_rstcpu_out <= 1'b1;
`endif
else if (vc[8])
n_rstcpu_out <= 1'b1;
end
/* T-STATES COUNTER (for debug) */
`ifdef TESTBENCH
integer tstate;
always @(posedge clkcpu) begin
if (!n_int_next && n_int)
tstate <= -1;
else
tstate <= tstate + 1;
end
`endif
endmodule

View File

@ -1,139 +0,0 @@
import common::*;
module cpucontrol(
input rst_n,
input clk28,
input clk14,
input clk7,
input clk35,
input ck14,
input ck7,
cpu_bus bus,
input [8:0] vc,
input [8:0] hc,
input screen_contention,
input [2:0] rampage128,
input machine_t machine,
input turbo_t turbo,
input init_done_in,
output reg n_rstcpu,
output reg clkcpu,
output clkcpu_ck,
output clkwait,
output reg n_int,
output n_int_next,
output snow
);
/* CONTENTION */
wire iorq_contended = bus.iorq && (~bus.a_reg[0] || (~bus.a_reg[1] && ~bus.a[15] && bus.wr)) && (machine != MACHINE_S3);
reg mreq_delayed, iorq_delayed;
always @(negedge clk28) if (clkcpu_ck)
mreq_delayed <= bus.mreq;
always @(negedge clk28) if (clkcpu_ck)
iorq_delayed <= bus.iorq && ~bus.a_reg[0];
wire contention_mem_page = (machine == MACHINE_S3)? rampage128[2] : rampage128[0];
wire contention_mem_addr = bus.a[14] & (~bus.a[15] | (bus.a[15] & contention_mem_page));
wire contention_mem = iorq_delayed == 1'b0 && mreq_delayed == 1'b0 && contention_mem_addr;
wire contention_io = iorq_delayed == 1'b0 && iorq_contended;
wire contention0 = screen_contention && (contention_mem || contention_io);
wire contention = clkcpu && contention0 && turbo == TURBO_NONE && (machine == MACHINE_S48 || machine == MACHINE_S128 || machine == MACHINE_S3);
assign snow = bus.a[14] && ~bus.a[15] && bus.rfsh && (machine == MACHINE_S48 || machine == MACHINE_S128);
/* CLOCK */
reg [3:0] turbo_wait;
wire turbo_wait_trig0 = turbo == TURBO_14 && bus.mreq && !bus.rfsh;
wire turbo_wait_trig1 = turbo == TURBO_14 && (bus.rd || bus.wr);
reg turbo_wait_trig0_prev, turbo_wait_trig1_prev;
always @(posedge clk28) begin
turbo_wait[0] <= turbo_wait_trig0 && !turbo_wait_trig0_prev;
turbo_wait[1] <= turbo_wait[0] || (turbo_wait_trig1 && !turbo_wait_trig1_prev);
turbo_wait[2] <= turbo_wait[1];
turbo_wait[3] <= turbo_wait[2];
turbo_wait_trig0_prev <= turbo_wait_trig0;
turbo_wait_trig1_prev <= turbo_wait_trig1;
end
reg clkcpu_prev;
assign clkcpu_ck = clkcpu && !clkcpu_prev;
assign clkwait = contention || (|turbo_wait[3:1]);
always @(posedge clk28) begin
clkcpu_prev <= clkcpu;
if (clkwait)
clkcpu <= clkcpu;
else if (turbo == TURBO_14)
clkcpu <= clk14;
else if (turbo == TURBO_7 && ck14)
clkcpu <= clk7;
else if (turbo == TURBO_5 && ck14 && hc[1])
clkcpu <= clk7;
else if (turbo == TURBO_4 && ck14 && hc[1] && hc[2])
clkcpu <= clk7;
else if (ck7)
clkcpu <= clk35;
end
/* INT GENERATOR */
localparam INT_V_S48 = 248;
localparam INT_H_S48 = 0;
localparam INT_V_S128 = 248;
localparam INT_H_S128 = 4;
localparam INT_V_PENT = 239;
localparam INT_H_PENT = 322;
wire int_begin =
(machine == MACHINE_S48)?
vc == INT_V_S48 && hc == INT_H_S48 :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
vc == INT_V_S128 && hc == INT_H_S128 :
// Pentagon
vc == INT_V_PENT && hc == INT_H_PENT ;
reg [4:0] int_cnt;
assign n_int_next = (|int_cnt)? 1'b0 : 1'b1;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
int_cnt <= 0;
n_int <= 1'b1;
end
else begin
if (clkcpu_ck)
n_int <= n_int_next;
if ((int_cnt != 0 && clkcpu_ck) || (int_cnt == 0 && int_begin))
int_cnt <= int_cnt + 1'b1;
end
end
/* RESET */
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
n_rstcpu <= 0;
else if (!init_done_in)
n_rstcpu <= 0;
`ifdef TESTBENCH
else if (hc[4])
n_rstcpu <= 1'b1;
`endif
else if (vc[8])
n_rstcpu <= 1'b1;
end
/* T-STATES COUNTER (for debug) */
`ifdef TESTBENCH
integer tstate;
always @(posedge clkcpu) begin
if (!n_int_next && n_int)
tstate <= -1;
else
tstate <= tstate + 1;
end
`endif
endmodule

View File

@ -19,62 +19,71 @@ module divmmc(
output reg sd_cs,
input rammap,
input magic_mode,
input magic_map,
input mask_hooks,
input mask_nmi_hook,
input basic48_paged,
output reg [3:0] page,
output map,
output automap,
output reg mapram,
output ram,
output ramwr_mask,
output cpuwait
output ext_wait_cycle2
);
reg automap0;
reg automap_next;
reg rom_m1_access, rom_m1_access0;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
automap_next <= 0;
automap0 <= 0;
rom_m1_access <= 0;
rom_m1_access0 <= 0;
end
else if (bus.m1 && bus.memreq && !magic_map) begin
if (!en_hooks || !en || rammap) begin
automap_next <= 0;
else if (bus.m1) begin
rom_m1_access0 <= bus.a_raw[15:14] == 2'b00;
end
else if (bus.a_reg[15:3] == 13'h3FF) begin // exit vectors 1FF8-1FFF
automap_next <= 0;
end
else if (
bus.a_reg == 16'h0000 || // power-on/reset/rst0/software restart
bus.a_reg == 16'h0008 || // syntax error
bus.a_reg == 16'h0038 || // im1 interrupt/rst #38
(bus.a_reg == 16'h0066 && !magic_mode) || // nmi routine
bus.a_reg == 16'h04C6 || // tape save routine
bus.a_reg == 16'h0562 // tape load and verify routine
) begin
automap_next <= 1'b1;
end
else if (bus.a_reg[15:8] == 8'h3D) begin // tr-dos mapping area
automap_next <= 1'b1;
automap0 <= 1'b1;
end
end
else if (!bus.m1) begin
automap0 <= automap_next;
else begin
rom_m1_access <= rom_m1_access0;
end
end
// #3Dxx entrypoint is critical for timings, so we're arming 'map' signal as soon as possible
assign automap = automap0 || (bus.m1 && bus.memreq && !magic_map && en_hooks && en && !rammap && bus.a_reg[15:8] == 8'h3D);
reg automap, automap_next;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
automap_next <= 0;
automap <= 0;
end
else if (bus.m1 && bus.memreq_rise && !mask_hooks) begin
if (!en_hooks || !en || rammap) begin
automap_next <= 0;
end
else if (bus.a[15:3] == 13'h3FF) begin // exit vectors 1FF8-1FFF
automap_next <= 0;
end
else if (
(bus.a == 16'h0000) || // power-on/reset/rst0/software restart
(bus.a == 16'h0008 && (basic48_paged || !rom_m1_access)) || // syntax error
(bus.a == 16'h0038 && (basic48_paged || !rom_m1_access)) || // im1 interrupt/rst #38
(bus.a == 16'h0066 && !mask_nmi_hook) || // nmi routine
(bus.a == 16'h04C6 && (basic48_paged || !rom_m1_access)) || // tape save routine
(bus.a == 16'h0562 && (basic48_paged || !rom_m1_access)) // tape load and verify routine
) begin
automap_next <= 1'b1;
end
else if (bus.a[15:8] == 8'h3D && (basic48_paged || !rom_m1_access)) begin // tr-dos mapping area
automap_next <= 1'b1;
automap <= 1'b1;
end
end
else if (!bus.m1) begin
automap <= automap_next;
end
end
reg conmem, mapram;
wire port_e3_cs = en && bus.ioreq && bus.a_reg[7:0] == 8'hE3;
wire port_e7_cs = en && bus.ioreq && bus.a_reg[7:0] == 8'hE7;
wire port_eb_cs = en && bus.ioreq && bus.a_reg[7:0] == 8'hEB;
wire port_57_cs = en_zc && bus.ioreq && bus.a_reg[7:0] == 8'h57;
wire port_77_cs = en_zc && bus.ioreq && bus.a_reg[7:0] == 8'h77;
reg conmem;
wire port_e3_cs = en && bus.ioreq && bus.a[7:0] == 8'hE3;
wire port_e7_cs = en && bus.ioreq && bus.a[7:0] == 8'hE7;
wire port_eb_cs = en && bus.ioreq && bus.a[7:0] == 8'hEB;
wire port_57_cs = en_zc && bus.ioreq && bus.a[7:0] == 8'h57;
wire port_77_cs = en_zc && bus.ioreq && bus.a[7:0] == 8'h77;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
page <= 0;
@ -84,15 +93,15 @@ always @(posedge clk28 or negedge rst_n) begin
end
else begin
if (port_e3_cs && bus.wr) begin
page <= bus.d_reg[3:0];
mapram <= bus.d_reg[6] | mapram;
conmem <= bus.d_reg[7];
page <= bus.d[3:0];
mapram <= bus.d[6] | mapram;
conmem <= bus.d[7];
end
if (port_e7_cs && bus.wr) begin
sd_cs <= bus.d_reg[0];
sd_cs <= bus.d[0];
end
else if (port_77_cs && bus.wr) begin
sd_cs <= bus.d_reg[1] | ~bus.d_reg[0];
sd_cs <= bus.d[1] | ~bus.d[0];
end
end
end
@ -112,7 +121,7 @@ end
reg [3:0] spi_cnt;
wire spi_cnt_en = ~spi_cnt[3] | spi_cnt[2] | spi_cnt[1] | spi_cnt[0];
assign cpuwait = ~spi_cnt[3];
assign ext_wait_cycle2 = ~spi_cnt[3];
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
spi_cnt <= 0;
@ -138,7 +147,7 @@ always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
spi_reg <= 0;
else if ((port_eb_cs || port_57_cs) && bus.wr)
spi_reg <= bus.d_reg;
spi_reg <= bus.d;
else if (spi_cnt[3] == 1'b0 && ck7)
spi_reg[7:0] <= {spi_reg[6:0], sd_miso};
end
@ -151,12 +160,12 @@ end
assign map = automap | conmem;
assign ram =
(automap && bus.a[13]) ||
(conmem && bus.a[13]) ||
(automap && bus.a_raw[13]) ||
(conmem && bus.a_raw[13]) ||
(!conmem && automap && mapram);
assign ramwr_mask =
!bus.a[15] && !bus.a[14] &&
(!bus.a[13] || page == 4'b0011) &&
!bus.a_raw[15] && !bus.a_raw[14] &&
(!bus.a_raw[13] || page == 4'b0011) &&
!conmem && automap && mapram;
assign d_out_active = zc_rd | spi_rd;

View File

@ -2,6 +2,7 @@ import common::*;
module magic(
input rst_n,
input clk28,
input ck35,
cpu_bus bus,
output [7:0] d_out,
@ -13,10 +14,11 @@ module magic(
input magic_button,
input pause_button,
input div_automap,
input div_paged,
input basic48_paged,
output reg magic_mode,
output magic_map,
output reg magic_map,
output reg magic_reboot,
output reg magic_beeper,
@ -29,17 +31,19 @@ module magic(
output reg ulaplus_en,
output reg ay_en,
output reg covox_en,
output reg soundrive_en
output reg soundrive_en,
output reg sd_indication_en
);
localparam magic_on_start = 1'b1;
reg magic_unmap_next;
reg magic_map_next;
reg magic_map0;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
n_nmi <= 1'b1;
magic_mode <= 1'b1;
magic_map0 <= 1'b1;
magic_mode <= magic_on_start;
magic_map <= magic_on_start;
magic_map_next <= 0;
magic_unmap_next <= 0;
end
@ -50,38 +54,37 @@ always @(posedge clk28 or negedge rst_n) begin
magic_mode <= 1'b1;
end
if (magic_map0 && bus.memreq && bus.rd && bus.a_reg == 16'hf000 && !magic_map_next) begin
if (magic_map && bus.memreq && bus.rd && bus.a == 16'hf000 && !magic_map_next) begin
magic_unmap_next <= 1'b1;
magic_mode <= 1'b0;
end
else if (magic_map0 && bus.memreq && bus.rd && bus.a_reg == 16'hf008) begin
else if (magic_map && bus.memreq && bus.rd && bus.a == 16'hf008) begin
magic_unmap_next <= 1'b1;
magic_map_next <= 1'b1;
end
else if (magic_unmap_next && !bus.memreq) begin
magic_map0 <= 1'b0;
magic_map <= 1'b0;
magic_unmap_next <= 1'b0;
end
else if (magic_mode && bus.m1 && bus.memreq && (bus.a_reg == 16'h0066 || magic_map_next)) begin
else if (magic_mode && bus.m1 && bus.memreq_rise && (bus.a == 16'h0066 || magic_map_next)) begin
n_nmi <= 1'b1;
magic_map0 <= 1'b1;
magic_map <= 1'b1;
magic_map_next <= 1'b0;
end
end
end
// this signal is critical for timings, so we're arming it as soon as possible
assign magic_map = magic_map0 || (magic_mode && bus.m1 && bus.memreq && (bus.a_reg == 16'h0066 || magic_map_next) && !magic_unmap_next);
/* MAGIC CONFIG */
wire config_cs = magic_map && bus.ioreq && bus.a_reg[7:0] == 8'hFF;
turbo_t turbo0;
reg autoturbo_en;
wire config_cs = magic_map && bus.ioreq && bus.a[7:0] == 8'hFF;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
magic_reboot <= 0;
magic_beeper <= 0;
machine <= MACHINE_PENT;
turbo <= TURBO_NONE;
turbo0 <= TURBO_NONE;
panning <= PANNING_ABC;
joy_sinclair <= 0;
divmmc_en <= 0;
@ -90,27 +93,64 @@ always @(posedge clk28 or negedge rst_n) begin
ay_en <= 1'b1;
covox_en <= 1'b1;
soundrive_en <= 1'b1;
sd_indication_en <= 1'b1;
autoturbo_en <= 1'b0;
end
else if (config_cs && bus.wr) case (bus.a_reg[15:8])
8'h01: {magic_reboot, magic_beeper} <= bus.d_reg[1:0];
8'h02: machine <= machine_t'(bus.d_reg[2:0]);
8'h03: turbo <= turbo_t'(bus.d_reg[2:0]);
8'h04: panning <= panning_t'(bus.d_reg[1:0]);
8'h07: joy_sinclair <= bus.d_reg[0];
8'h08: ay_en <= bus.d_reg[0];
8'h09: {zc_en, divmmc_en} <= bus.d_reg[1:0];
8'h0a: ulaplus_en <= bus.d_reg[0];
8'h0b: {soundrive_en, covox_en} <= bus.d_reg[1:0];
else if (config_cs && bus.wr) case (bus.a[15:8])
8'h01: {magic_reboot, magic_beeper} <= bus.d[1:0];
8'h02: machine <= machine_t'(bus.d[2:0]);
8'h03: turbo0 <= turbo_t'(bus.d[2:0]);
8'h04: panning <= panning_t'(bus.d[1:0]);
8'h07: joy_sinclair <= bus.d[0];
8'h08: ay_en <= bus.d[0];
8'h09: {zc_en, divmmc_en} <= bus.d[1:0];
8'h0A: ulaplus_en <= bus.d[0];
8'h0B: {soundrive_en, covox_en} <= bus.d[1:0];
8'h0C: sd_indication_en <= bus.d[0];
8'h0E: autoturbo_en <= bus.d[0];
endcase
end
reg config_rd;
wire [7:0] config_data = {4'b0000, div_automap, 1'b1, pause_button, magic_button};
wire [7:0] config_data = {4'b0000, div_paged, 1'b1, pause_button, magic_button};
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
config_rd <= 0;
else
config_rd <= config_cs && bus.rd && bus.a_reg[15:8] == 8'h00;
config_rd <= config_cs && bus.rd && bus.a[15:8] == 8'h00;
end
/* AUTOMATIC TURBO */
reg [11:0] portfe_noturbo; // 1170uS
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
portfe_noturbo <= 0;
else if (bus.ioreq && !bus.a[0])
portfe_noturbo <= 1'b1;
else if (|portfe_noturbo && ck35)
portfe_noturbo <= portfe_noturbo + 1'b1;
end
reg basic48_ramclear_turbo;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
basic48_ramclear_turbo <= 0;
else if (basic48_paged && bus.m1 && bus.a[15:6] == 10'b0001000111)
basic48_ramclear_turbo <= 1'b1;
else if (!basic48_paged || (bus.m1 && bus.a[15:6] != 10'b0001000111))
basic48_ramclear_turbo <= 0;
end
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
turbo <= TURBO_NONE;
else if (autoturbo_en && div_paged && !magic_map)
turbo <= TURBO_14;
else if (autoturbo_en && |portfe_noturbo)
turbo <= TURBO_NONE;
else if (autoturbo_en && basic48_ramclear_turbo)
turbo <= TURBO_14;
else
turbo <= turbo0;
end

207
fpga/rtl/mem.sv Normal file
View File

@ -0,0 +1,207 @@
import common::*;
module mem(
input rst_n,
input clk28,
cpu_bus bus,
output reg [18:0] va,
inout [7:0] vd,
output reg n_vrd,
output reg n_vwr,
output bus_valid,
output cpuwait,
output basic48_paged,
input machine_t machine,
input turbo_t turbo,
input cpu_contention,
input magic_map,
input [2:0] ram_page128,
input rom_page128,
input [2:0] port_1ffd,
input [4:0] port_dffd,
input [2:0] ram_pageext,
input div_ram,
input div_map,
input div_ramwr_mask,
input [3:0] div_page,
input snow,
input video_page,
input video_read_req,
input [14:0] video_read_addr,
output video_read_req_ack,
output video_data_valid,
input [16:0] rom2ram_ram_address,
input rom2ram_ram_wren,
input [7:0] rom2ram_dataout,
input magic_dout_active,
input [7:0] magic_dout,
input up_dout_active,
input [7:0] up_dout,
input div_dout_active,
input [7:0] div_dout,
input turbosound_dout_active,
input [7:0] turbosound_dout,
input ports_dout_active,
input [7:0] ports_dout
);
/* VA[18:13] map
* 00xxxx 112Kb of roms
* 00111x 16Kb of magic ram
* 01xxxx 128Kb of divmmc memory
* 10xxxx 128Kb of extended ram (via port dffd)
* 11xxxx 128Kb of main ram
*/
reg romreq, ramreq, ramreq_wr;
reg [18:13] va_18_13;
wire [15:0] a = bus.a_raw[15:0];
always @* begin
romreq = a[15:14] == 2'b00 &&
(magic_map || (!div_ram && div_map) || (!div_ram && !port_dffd[4] && !port_1ffd[0]));
ramreq = !romreq;
ramreq_wr = ramreq && div_ramwr_mask == 0;
if (romreq) va_18_13 =
(magic_map) ? {5'd2, 1'b0} :
(div_map) ? {5'd2, 1'b1} :
(machine == MACHINE_S3 && port_1ffd[2] == 1'b0 && rom_page128 == 1'b0) ? {5'd4, a[13]} :
(machine == MACHINE_S3 && port_1ffd[2] == 1'b0 && rom_page128 == 1'b1) ? {5'd5, a[13]} :
(machine == MACHINE_S3 && port_1ffd[2] == 1'b1 && rom_page128 == 1'b0) ? {5'd6, a[13]} :
(machine == MACHINE_S48) ? {5'd3, a[13]} :
(rom_page128 == 1'b1) ? {5'd1, a[13]} :
{5'd0, a[13]} ;
else va_18_13 =
(magic_map && a[15:14] == 2'b11) ? {2'b00, 3'b111, a[13]} :
(magic_map) ? {3'b111, video_page, a[14:13]} :
(div_map && a[15:13] == 3'b001) ? {2'b01, div_page} :
(div_map && a[15:14] == 2'b00) ? {2'b01, 4'b0011} :
(port_dffd[3] & a[15]) ? {2'b11, a[14], a[15], a[14], a[13]} :
(port_dffd[3] & a[14]) ? {1'b1, ~ram_pageext[0], ram_page128, a[13]} :
(port_1ffd[2] == 1'b0 && port_1ffd[0] == 1'b1) ? {2'b11, port_1ffd[1], a[15], a[14], a[13]} :
(port_1ffd == 3'b101) ? {2'b11, ~(a[15] & a[14]), a[15], a[14], a[13]} :
(port_1ffd == 3'b111) ? {2'b11, ~(a[15] & a[14]), (a[15] | a[14]), a[14], a[13]} :
(a[15:14] == 2'b11) ? {1'b1, ~ram_pageext[0], ram_page128, a[13]} :
{2'b11, a[14], a[15], a[14], a[13]} ;
end
assign basic48_paged = (va_18_13[18:14] == 5'd1) ||
(va_18_13[18:14] == 5'd3) ;
assign vd[7:0] =
~n_vrd ? {8{1'bz}} :
bus.wr ? {8{1'bz}} :
rom2ram_ram_wren ? rom2ram_dataout :
magic_dout_active ? magic_dout :
up_dout_active ? up_dout :
div_dout_active ? div_dout :
turbosound_dout_active ? turbosound_dout :
ports_dout_active ? ports_dout :
(bus.m1 && bus.iorq) ? 8'hFF :
bus.rd ? 8'hFF :
{8{1'bz}} ;
localparam BUS_VALID_LATENCY = 2'd1;
reg [1:0] bus_valid_step;
localparam LATENCY = 2'd2;
reg [1:0] step;
localparam REQ_NONE = 3'd0;
localparam REQ_CPU_RD = 3'd1;
localparam REQ_CPU_WR = 3'd2;
localparam REQ_VIDEO_RD = 3'd3;
localparam REQ_ROM2RAM_WR = 3'd4;
reg [2:0] current_req;
reg cpuwait_reg;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b1;
n_vwr <= 1'b1;
cpuwait_reg <= 0;
bus_valid_step <= 0;
step <= 0;
current_req <= REQ_NONE;
end
else begin
if (step)
step <= step - 1'd1;
if (bus_valid_step)
bus_valid_step <= bus_valid_step - 1'd1;
if (!(bus.mreq && bus.rd))
cpuwait_reg <= 0;
if (rom2ram_ram_wren) begin
if (current_req != REQ_ROM2RAM_WR)
step <= LATENCY;
va <= {2'b00, rom2ram_ram_address};
n_vrd <= 1'b1;
n_vwr <= (current_req == REQ_ROM2RAM_WR && step == 0)? 1'b1 : 1'b0;
bus_valid_step <= BUS_VALID_LATENCY;
current_req <= REQ_ROM2RAM_WR;
end
else if (turbo == TURBO_14 && current_req == REQ_VIDEO_RD && step) begin
// complete current request
bus_valid_step <= BUS_VALID_LATENCY;
end
else if (bus.mreq && bus.wr && ramreq_wr) begin
if (current_req != REQ_CPU_WR)
step <= LATENCY;
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b1;
n_vwr <= (current_req == REQ_CPU_WR && step == 0)? 1'b1 : 1'b0;
current_req <= REQ_CPU_WR;
end
else if (bus.mreq && bus.rd) begin
if (current_req != REQ_CPU_RD) begin
step <= LATENCY;
end
else if (va[18:13] != va_18_13) begin
cpuwait_reg <= 1'b1;
step <= LATENCY;
end
else if (!step) begin
cpuwait_reg <= 1'b0;
end
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b0;
n_vwr <= 1'b1;
current_req <= REQ_CPU_RD;
end
else if ((bus.mreq || bus.iorq) && !bus.rfsh && !cpu_contention) begin
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b1;
n_vwr <= 1'b1;
current_req <= REQ_NONE;
end
else if (video_read_req) begin
if (current_req != REQ_VIDEO_RD || !step)
step <= LATENCY;
va <= snow? {3'b111, video_page, video_read_addr[14:7], {7{1'bz}}} :
{3'b111, video_page, video_read_addr} ;
n_vrd <= 1'b0;
n_vwr <= 1'b1;
bus_valid_step <= BUS_VALID_LATENCY;
current_req <= REQ_VIDEO_RD;
end
else begin
va <= {va_18_13, {13{1'bz}}};
n_vrd <= 1'b1;
n_vwr <= 1'b1;
current_req <= REQ_NONE;
end
end
end
assign cpuwait = cpuwait_reg || (bus.mreq && bus.rd && current_req == REQ_CPU_RD && va[18:13] != va_18_13);
assign bus_valid = bus_valid_step == 0;
assign video_data_valid = current_req == REQ_VIDEO_RD && step == 0;
assign video_read_req_ack = current_req == REQ_VIDEO_RD && step == 1'd1 && (!((bus.mreq || bus.iorq) && !bus.rfsh && !cpu_contention) || turbo == TURBO_14);
endmodule

View File

@ -1,107 +0,0 @@
import common::*;
module memcontrol(
input clk28,
cpu_bus bus,
output [18:0] va,
inout [7:0] vd,
output n_vrd,
output n_vwr,
input machine_t machine,
input screenpage,
input screen_fetch,
input screen_fetch_up,
input snow,
input [14:0] screen_addr,
input magic_map,
input [2:0] rampage128,
input rompage128,
input [2:0] port_1ffd,
input [4:0] port_dffd,
input [2:0] rampage_ext,
input divmmc_en,
input div_ram,
input div_map,
input div_ramwr_mask,
input [3:0] div_page,
input [16:0] rom2ram_ram_address,
input rom2ram_ram_wren,
input [7:0] rom2ram_dataout,
input magic_dout_active,
input [7:0] magic_dout,
input up_dout_active,
input [7:0] up_dout,
input div_dout_active,
input [7:0] div_dout,
input turbosound_dout_active,
input [7:0] turbosound_dout,
input ports_dout_active,
input [7:0] ports_dout
);
/* VA[18:13] map
* 00xxxx 112Kb of roms
* 00111x 16Kb of magic ram
* 01xxxx 128Kb of divmmc memory
* 10xxxx 128Kb of extended ram (via port dffd)
* 11xxxx 128Kb of main ram
*/
reg romreq, ramreq, ramreq_wr;
reg [18:13] va_18_13;
always @(negedge clk28) begin
romreq = bus.mreq && bus.a[15:14] == 2'b00 &&
(magic_map || (!div_ram && div_map) || (!div_ram && !port_dffd[4] && !port_1ffd[0]));
ramreq = bus.mreq && !romreq;
ramreq_wr = ramreq && bus.wr && div_ramwr_mask == 0;
if (romreq) va_18_13 = {2'd0,
magic_map? {3'd2, 1'b0} :
div_map? {3'd2, 1'b1} :
(machine == MACHINE_S3 && port_1ffd[2] == 1'b0 && rompage128 == 1'b0)? {3'd4, bus.a[13]} :
(machine == MACHINE_S3 && port_1ffd[2] == 1'b0 && rompage128 == 1'b1)? {3'd5, bus.a[13]} :
(machine == MACHINE_S3 && port_1ffd[2] == 1'b1 && rompage128 == 1'b0)? {3'd6, bus.a[13]} :
(machine == MACHINE_S48)? {3'd3, bus.a[13]} :
(rompage128 == 1'b1)? {3'd1, bus.a[13]} :
{3'd0, bus.a[13]} };
else va_18_13 =
magic_map & bus.a[15] & bus.a[14]? {2'b00, 3'b111, bus.a[13]} :
magic_map? {3'b111, screenpage, bus.a[14:13]} :
div_map & ~bus.a[15] & ~bus.a[14] & bus.a[13]? {2'b01, div_page} :
div_map & ~bus.a[15] & ~bus.a[14]? {2'b01, 4'b0011} :
port_dffd[3] & bus.a[15]? {2'b11, bus.a[14], bus.a[15], bus.a[14], bus.a[13]} :
port_dffd[3] & bus.a[14]? {1'b1, ~rampage_ext[0], rampage128, bus.a[13]} :
(port_1ffd[2] == 1'b0 && port_1ffd[0] == 1'b1)? {2'b11, port_1ffd[1], bus.a[15], bus.a[14], bus.a[13]} :
(port_1ffd == 3'b101)? {2'b11, ~(bus.a[15] & bus.a[14]), bus.a[15], bus.a[14], bus.a[13]} :
(port_1ffd == 3'b111)? {2'b11, ~(bus.a[15] & bus.a[14]), (bus.a[15] | bus.a[14]), bus.a[14], bus.a[13]} :
bus.a[15] & bus.a[14]? {1'b1, ~rampage_ext[0], rampage128, bus.a[13]} :
{2'b11, bus.a[14], bus.a[15], bus.a[14], bus.a[13]} ;
end
assign n_vrd = (((bus.mreq && bus.rd) || screen_fetch) && !rom2ram_ram_wren)? 1'b0 : 1'b1;
assign n_vwr = ((ramreq_wr && bus.wr && !screen_fetch) || rom2ram_ram_wren)? 1'b0 : 1'b1;
assign va[18:0] =
rom2ram_ram_wren? {2'b00, rom2ram_ram_address} :
screen_fetch && snow? {3'b111, screenpage, screen_addr[14:8], {8{1'bz}}} :
screen_fetch? {3'b111, screenpage, screen_addr} :
{va_18_13, {13{1'bz}}};
assign vd[7:0] =
~n_vrd? {8{1'bz}} :
bus.wr? {8{1'bz}} :
rom2ram_ram_wren? rom2ram_dataout :
magic_dout_active? magic_dout :
up_dout_active? up_dout :
div_dout_active? div_dout :
turbosound_dout_active? turbosound_dout :
ports_dout_active? ports_dout :
(bus.m1 && bus.iorq)? 8'hFF :
bus.rd? 8'hFF :
{8{1'bz}};
endmodule

View File

@ -30,45 +30,32 @@ assign dac_l = dac_l_cnt[WIDTH];
assign dac_r = dac_r_cnt[WIDTH];
wire [WIDTH-1:0] dac_next_l =
{sd_l0, 1'b0} +
{sd_l1, 1'b0} +
{ay_a0, 1'b0} +
{ay_a1, 1'b0} +
(ay_acb? ay_c0 : ay_b0) +
ay_b1 +
{beeper, tape_out, tape_in, 7'b000000}
{ay_a1, 1'b0} +
{1'b0, ay_b1} +
{sd_l0, 1'b0} +
{sd_l1, 1'b0}
;
wire [WIDTH-1:0] dac_next_r =
{sd_r0, 1'b0} +
{sd_r1, 1'b0} +
(ay_acb? {ay_b0, 1'b0} : {ay_c0, 1'b0}) +
{ay_c1, 1'b0} +
(ay_acb? ay_c0 : ay_b0) +
ay_b1 +
{beeper, tape_out, tape_in, 7'b000000}
;
wire [WIDTH-1:0] dac_next_mono =
sd_r0 +
sd_r1 +
sd_l0 +
sd_l1 +
ay_a0 +
ay_a1 +
ay_b0 +
ay_b1 +
ay_c0 +
ay_c1 +
{beeper, tape_out, tape_in, 7'b000000}
{1'b0, ay_b1} +
{ay_c1, 1'b0} +
{sd_r0, 1'b0} +
{sd_r1, 1'b0}
;
wire [WIDTH-1:0] dac_next_lr = {beeper, tape_out, tape_in, 7'd0};
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
dac_l_cnt <= 0;
dac_r_cnt <= 0;
end
else begin
dac_l_cnt <= dac_l_cnt[WIDTH-1:0] + (mono? dac_next_mono : dac_next_l);
dac_r_cnt <= dac_r_cnt[WIDTH-1:0] + (mono? dac_next_mono : dac_next_r);
dac_l_cnt <= dac_l_cnt[WIDTH-1:0] + dac_next_lr + dac_next_l + (mono? dac_next_r : {WIDTH{1'b0}});
dac_r_cnt <= dac_r_cnt[WIDTH-1:0] + dac_next_lr + dac_next_r + (mono? dac_next_l : {WIDTH{1'b0}});
end
end

View File

@ -20,10 +20,10 @@ module ports(
output reg tape_out,
output reg beeper,
output reg [2:0] border,
output reg screenpage,
output reg rompage128,
output reg [2:0] rampage128,
output reg [2:0] rampage_ext,
output reg video_page,
output reg rom_page128,
output reg [2:0] ram_page128,
output reg [2:0] ram_pageext,
output reg [2:0] port_1ffd,
output reg [4:0] port_dffd
@ -37,12 +37,12 @@ always @(posedge clk28 or negedge rst_n) begin
port_ff_rd <= 0;
else
port_ff_rd <= bus.rd && bus.ioreq && !magic_map && port_ff_active &&
(machine != MACHINE_S3) && (machine != MACHINE_PENT || bus.a_reg[7:0] == 8'hFF);
(machine != MACHINE_S3) && (machine != MACHINE_PENT || bus.a[7:0] == 8'hFF);
end
/* PORT #FE */
wire port_fe_cs = bus.ioreq && bus.a_reg[0] == 0;
wire port_fe_cs = bus.ioreq && bus.a[0] == 0;
reg port_fe_rd;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
@ -60,9 +60,9 @@ always @(negedge clk28 or negedge rst_n) begin
border <= 0;
end
else if (port_fe_cs && bus.wr) begin
beeper <= bus.d_reg[4];
tape_out <= bus.d_reg[3];
border <= bus.d_reg[2:0];
beeper <= bus.d[4];
tape_out <= bus.d[3];
border <= bus.d[2:0];
end
end
@ -72,8 +72,8 @@ always @(posedge clk28 or negedge rst_n) begin
end
else if (en_sinclair) begin
kd0 <= kd
& (bus.a_reg[12] == 0? {~kempston_data[1], ~kempston_data[0], ~kempston_data[2], ~kempston_data[3], ~kempston_data[4]} : 5'b11111) // 6-0 keys
& (bus.a_reg[15] == 0? {1'b1, ~kempston_data[6], ~kempston_data[5], 2'b11} : 5'b11111 ) ; // b-space keys
& (bus.a[12] == 0? {~kempston_data[1], ~kempston_data[0], ~kempston_data[2], ~kempston_data[3], ~kempston_data[4]} : 5'b11111) // 6-0 keys
& (bus.a[15] == 0? {1'b1, ~kempston_data[6], ~kempston_data[5], 2'b11} : 5'b11111 ) ; // b-space keys
end
else begin
kd0 <= kd;
@ -83,49 +83,49 @@ end
/* PORT #7FFD */
reg lock_7ffd;
wire port_7ffd_cs = bus.ioreq && bus.a_reg[1] == 0 && bus.a_reg[15] == 0 &&
(bus.a_reg[14] == 1'b1 || (!magic_map && machine != MACHINE_S3)) &&
wire port_7ffd_cs = bus.ioreq && bus.a[1] == 0 && bus.a[15] == 0 &&
(bus.a[14] == 1'b1 || (!magic_map && machine != MACHINE_S3)) &&
(machine != MACHINE_S48 || magic_map) &&
(lock_7ffd == 0 || port_dffd[4] == 1'b1);
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
rampage128 <= 0;
screenpage <= 0;
rompage128 <= 0;
ram_page128 <= 0;
video_page <= 0;
rom_page128 <= 0;
lock_7ffd <= 0;
end
else if (port_7ffd_cs && bus.wr) begin
rampage128 <= bus.d_reg[2:0];
screenpage <= bus.d_reg[3];
rompage128 <= bus.d_reg[4];
lock_7ffd <= bus.d_reg[5];
ram_page128 <= bus.d[2:0];
video_page <= bus.d[3];
rom_page128 <= bus.d[4];
lock_7ffd <= bus.d[5];
end
end
/* PORT #DFFD */
wire port_dffd_cs = bus.ioreq && bus.a_reg == 16'hDFFD && (machine == MACHINE_PENT || magic_map);
wire port_dffd_cs = bus.ioreq && bus.a == 16'hDFFD && (machine == MACHINE_PENT || magic_map);
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
rampage_ext <= 0;
ram_pageext <= 0;
port_dffd <= 0;
end
else if (port_dffd_cs && bus.wr) begin
rampage_ext <= bus.d_reg[2:0];
port_dffd <= bus.d_reg[4:0];
ram_pageext <= bus.d[2:0];
port_dffd <= bus.d[4:0];
end
end
/* PORT #1FFD */
wire port_1ffd_cs = bus.ioreq && bus.a_reg[15:12] == 4'b0001 && !bus.a_reg[1] &&
wire port_1ffd_cs = bus.ioreq && bus.a[15:12] == 4'b0001 && !bus.a[1] &&
(machine == MACHINE_S3 || magic_map);
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
port_1ffd <= 0;
end
else if (port_1ffd_cs && bus.wr) begin
port_1ffd <= bus.d_reg[2:0];
port_1ffd <= bus.d[2:0];
end
end
@ -136,7 +136,7 @@ always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
kempston_rd <= 0;
else
kempston_rd <= en_kempston && bus.ioreq && bus.rd && bus.a_reg[5:0] == 6'h1F;
kempston_rd <= en_kempston && bus.ioreq && bus.rd && bus.a[5:0] == 6'h1F;
end

View File

@ -16,7 +16,7 @@ module ps2_rxtx#(
localparam CLKWAIT_US = 1;
localparam TOUT_US = 150;
localparam TOUT_US = 200;
localparam CLKWAIT_TICKS = int'(CLKWAIT_US*CLK_FREQ/1e6) + 1'b1;
localparam TOUT_TICKS = int'(TOUT_US*CLK_FREQ/1e6) + 1'b1;
reg [$clog2(TOUT_TICKS)-1:0] timer;

View File

@ -14,12 +14,12 @@ module soundrive(
output reg [7:0] ch_r1
);
wire covox_cs = en_covox && bus.ioreq && bus.a_reg[7:0] == 8'hFB;
wire specdrum_cs = en_specdrum && bus.ioreq && bus.a_reg[7:0] == 8'hDF;
wire soundrive_a_cs = en_soundrive && bus.ioreq && bus.a_reg[7:0] == 8'h0F;
wire soundrive_b_cs = en_soundrive && bus.ioreq && bus.a_reg[7:0] == 8'h1F;
wire soundrive_c_cs = en_soundrive && bus.ioreq && bus.a_reg[7:0] == 8'h4F;
wire soundrive_d_cs = en_soundrive && bus.ioreq && bus.a_reg[7:0] == 8'h5F;
wire covox_cs = en_covox && bus.ioreq && bus.a[7:0] == 8'hFB;
wire specdrum_cs = en_specdrum && bus.ioreq && bus.a[7:0] == 8'hDF;
wire soundrive_a_cs = en_soundrive && bus.ioreq && bus.a[7:0] == 8'h0F;
wire soundrive_b_cs = en_soundrive && bus.ioreq && bus.a[7:0] == 8'h1F;
wire soundrive_c_cs = en_soundrive && bus.ioreq && bus.a[7:0] == 8'h4F;
wire soundrive_d_cs = en_soundrive && bus.ioreq && bus.a[7:0] == 8'h5F;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
@ -30,13 +30,13 @@ always @(posedge clk28 or negedge rst_n) begin
end
else begin
if ((covox_cs || specdrum_cs || soundrive_a_cs) && bus.wr)
ch_l0 <= bus.d_reg;
ch_l0 <= bus.d;
if ((covox_cs || specdrum_cs || soundrive_b_cs) && bus.wr)
ch_l1 <= bus.d_reg;
ch_l1 <= bus.d;
if ((covox_cs || specdrum_cs || soundrive_c_cs) && bus.wr)
ch_r0 <= bus.d_reg;
ch_r0 <= bus.d;
if ((covox_cs || specdrum_cs || soundrive_d_cs) && bus.wr)
ch_r1 <= bus.d_reg;
ch_r1 <= bus.d;
end
end

View File

@ -58,36 +58,18 @@ wire ps2_key_reset, ps2_key_pause;
wire [2:0] border;
wire magic_reboot, magic_beeper;
wire up_active;
wire clkwait;
wire [2:0] rampage128;
wire [2:0] ram_page128;
wire init_done;
wire screen_fetch, screen_fetch_next;
wire mem_bus_valid;
wire mem_wait;
wire basic48_paged;
wire sd_indication;
/* CPU BUS */
cpu_bus bus();
reg bus_memreq, bus_ioreq;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
bus_ioreq <= 0;
bus_memreq <= 0;
end
else if (!screen_fetch && !screen_fetch_next) begin
bus.a_reg <= {a[15:13], va[12:0]};
bus.d_reg <= vd;
bus_ioreq <= n_iorq == 1'b0 && n_m1 == 1'b1;
bus_memreq <= n_mreq == 1'b0 && n_rfsh == 1'b1;
end
else begin
if (n_iorq)
bus_ioreq <= 0;
if (n_mreq)
bus_memreq <= 0;
end
end
always @(posedge clk168) begin
bus.a <= {a[15:13], va[12:0]};
bus.d <= vd;
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;
@ -95,8 +77,13 @@ always @(posedge clk168) begin
bus.rd <= ~n_rd;
bus.wr <= ~n_wr;
end
assign bus.ioreq = bus_ioreq & bus.iorq;
assign bus.memreq = bus_memreq & bus.mreq;
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 */
@ -106,25 +93,23 @@ always @(posedge clk28) begin
end
/* SCREEN CONTROLLER */
wire blink;
wire [2:0] screen_border = {border[2] ^ ~sd_cs, border[1] ^ magic_beeper, border[0]};
/* VIDEO CONTROLLER */
wire [5:0] r, g, b;
wire hsync, vsync, csync0;
wire screen_contention, port_ff_active;
wire [14:0] screen_addr;
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, up_paper;
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;
screen screen0(
video video0(
.rst_n(usrrst_n),
.clk28(clk28),
.machine(machine),
.turbo(turbo),
.border(screen_border),
.border({border[2] ^ sd_indication, border[1] ^ magic_beeper, border[0]}),
.r(r),
.g(g),
@ -133,20 +118,19 @@ screen screen0(
.vsync(vsync),
.hsync(hsync),
.fetch_allow((!bus.iorq && !bus.mreq) || bus.rfsh || (clkwait && turbo == TURBO_NONE)),
.fetch(screen_fetch),
.addr(screen_addr),
.fetch_next(screen_fetch_next),
.fetch_data(bus.d),
.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_ink(up_ink),
.up_paper(up_paper),
.up_paper_data(up_paper_data),
.contention(screen_contention),
.blink(blink),
.contention(video_contention),
.port_ff_active(port_ff_active),
.port_ff_data(port_ff_data),
@ -184,7 +168,7 @@ ps2 #(.CLK_FREQ(28_000_000)) ps2_0(
.clk(clk28),
.ps2_clk_in(ps2_clk),
.ps2_dat_in(ps2_dat),
.zxkb_addr(bus.a_reg[15:8]),
.zxkb_addr(bus.a[15:8]),
.zxkb_data(ps2_kd),
.key_magic(ps2_key_magic),
.key_reset(ps2_key_reset),
@ -198,8 +182,8 @@ ps2 #(.CLK_FREQ(28_000_000)) ps2_0(
/* CPU CONTROLLER */
wire n_int_next, clkcpu_ck, snow;
cpucontrol cpucontrol0(
wire n_int_next, clkcpu_ck, snow, cpu_contention;
cpu cpu0(
.rst_n(usrrst_n),
.clk28(clk28),
.clk14(clk14),
@ -212,34 +196,38 @@ cpucontrol cpucontrol0(
.vc(vc),
.hc(hc),
.rampage128(rampage128),
.ram_page128(ram_page128),
.machine(machine),
.turbo(turbo),
.screen_contention(screen_contention),
.hold(mem_wait),
.video_contention(video_contention),
.init_done_in(init_done),
.n_rstcpu(n_rstcpu),
.n_rstcpu_out(n_rstcpu),
.clkcpu(clkcpu),
.clkcpu_ck(clkcpu_ck),
.clkwait(clkwait),
.n_int(n_int),
.n_int_next(n_int_next),
.snow(snow)
.snow(snow),
.contention(cpu_contention)
);
/* MAGIC */
wire div_automap;
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;
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),
@ -251,7 +239,8 @@ magic magic0(
.magic_button(ps2_key_magic),
.pause_button(ps2_key_pause),
.div_automap(div_automap),
.div_paged(div_map && !div_mapram),
.basic48_paged(basic48_paged),
.magic_mode(magic_mode),
.magic_map(magic_map),
@ -267,7 +256,8 @@ magic magic0(
.ulaplus_en(up_en),
.ay_en(ay_en),
.covox_en(covox_en),
.soundrive_en(soundrive_en)
.soundrive_en(soundrive_en),
.sd_indication_en(sd_indication_en)
);
@ -275,9 +265,9 @@ magic magic0(
wire [7:0] ports_dout;
wire ports_dout_active;
wire beeper, tape_out;
wire screenpage;
wire rompage128;
wire [2:0] rampage_ext;
wire video_page;
wire rom_page128;
wire [2:0] ram_pageext;
wire [2:0] port_1ffd;
wire [4:0] port_dffd;
ports ports0 (
@ -302,10 +292,10 @@ ports ports0 (
.tape_out(tape_out),
.beeper(beeper),
.border(border),
.screenpage(screenpage),
.rompage128(rompage128),
.rampage128(rampage128),
.rampage_ext(rampage_ext),
.video_page(video_page),
.rom_page128(rom_page128),
.ram_page128(ram_page128),
.ram_pageext(ram_pageext),
.port_1ffd(port_1ffd),
.port_dffd(port_dffd)
);
@ -338,7 +328,7 @@ turbosound turbosound0(
/* COVOX & SOUNDRIVE */
wire [7:0] soundrive_l0, soundrive_l1, soundrive_r0, soundrive_r1;
soundrive soundrive0(
.rst_n(usrrst_n),
.rst_n(n_rstcpu),
.clk28(clk28),
.en_covox(covox_en),
.en_specdrum(covox_en),
@ -360,7 +350,7 @@ mixer mixer0(
.beeper(beeper ^ magic_beeper),
.tape_out(tape_out),
.tape_in(sd_miso_tape_in),
.tape_in((divmmc_en || zc_en)? sd_indication : sd_miso_tape_in),
.ay_a0(ay_a0),
.ay_b0(ay_b0),
.ay_c0(ay_c0),
@ -381,7 +371,7 @@ mixer mixer0(
/* DIVMMC */
wire div_map, div_ram, div_ramwr_mask, div_dout_active;
wire div_ram, div_ramwr_mask, div_dout_active;
wire [7:0] div_dout;
wire [3:0] div_page;
wire sd_mosi0;
@ -405,16 +395,17 @@ divmmc divmmc0(
.sd_cs(sd_cs),
.rammap(port_dffd[4] | port_1ffd[0]),
.magic_mode(magic_mode),
.magic_map(magic_map),
.mask_hooks(magic_map),
.mask_nmi_hook(magic_mode),
.basic48_paged(basic48_paged),
.page(div_page),
.map(div_map),
.automap(div_automap),
.mapram(div_mapram),
.ram(div_ram),
.ramwr_mask(div_ramwr_mask)
);
assign sd_mosi_tape_out = (!divmmc_en && !zc_en)? tape_out : sd_mosi0;
assign sd_mosi_tape_out = (divmmc_en || zc_en)? sd_mosi0 : tape_out;
/* ULAPLUS */
@ -430,10 +421,10 @@ ulaplus ulaplus0(
.d_out_active(up_dout_active),
.active(up_active),
.ink_addr(up_ink_addr),
.paper_addr(up_paper_addr),
.ink(up_ink),
.paper(up_paper)
.read_addr1(up_ink_addr),
.read_data1(up_ink_data),
.read_addr2(up_paper_addr),
.read_data2(up_paper_data)
);
@ -483,7 +474,8 @@ asmi asmi0(
/* MEMORY CONTROLLER */
memcontrol memcontrol0(
mem mem0(
.rst_n(rst_n),
.clk28(clk28),
.bus(bus),
.va(va),
@ -491,26 +483,35 @@ memcontrol memcontrol0(
.n_vrd(n_vrd),
.n_vwr(n_vwr),
.bus_valid(mem_bus_valid),
.cpuwait(mem_wait),
.basic48_paged(basic48_paged),
.machine(machine),
.screenpage(screenpage),
.screen_fetch(screen_fetch),
.snow(snow),
.screen_addr(screen_addr),
.turbo(turbo),
.cpu_contention(cpu_contention),
.magic_map(magic_map),
.rampage128(rampage128),
.rompage128(rompage128),
.ram_page128(ram_page128),
.rom_page128(rom_page128),
.port_1ffd(port_1ffd),
.port_dffd(port_dffd),
.rampage_ext(rampage_ext),
.divmmc_en(divmmc_en),
.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),

View File

@ -27,8 +27,8 @@ module turbosound(
reg ay_bdir;
reg ay_bc1;
reg ay_sel;
wire port_bffd = en && bus.ioreq && bus.a_reg[15] == 1'b1 && bus.a_reg[1] == 0;
wire port_fffd = en && bus.ioreq && bus.a_reg[15] == 1'b1 && bus.a_reg[14] == 1'b1 && bus.a_reg[1] == 0;
wire port_bffd = en && bus.ioreq && bus.a[15] == 1'b1 && bus.a[1] == 0;
wire port_fffd = en && bus.ioreq && bus.a[15] == 1'b1 && bus.a[14] == 1'b1 && bus.a[1] == 0;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
ay_bc1 <= 0;
@ -40,8 +40,8 @@ always @(posedge clk28 or negedge rst_n) begin
ay_bdir <= port_bffd && bus.wr;
if (!en_ts)
ay_sel <= 0;
else if (bus.ioreq && port_fffd && bus.wr && bus.d_reg[7:3] == 5'b11111)
ay_sel <= bus.d_reg[0];
else if (bus.ioreq && port_fffd && bus.wr && bus.d[7:3] == 5'b11111)
ay_sel <= bus.d[0];
end
end
@ -65,7 +65,7 @@ YM2149 ym2149_0(
.A8(~ay_sel),
.BDIR(ay_bdir),
.BC(ay_bc1),
.DI(bus.d_reg),
.DI(bus.d),
.DO(ay_dout0),
.SEL(1'b0),
.MODE(1'b1),
@ -80,7 +80,7 @@ YM2149 ym2149_1(
.A8(ay_sel),
.BDIR(ay_bdir),
.BC(ay_bc1),
.DI(bus.d_reg),
.DI(bus.d),
.DO(ay_dout1),
.SEL(1'b0),
.MODE(1'b0),

View File

@ -9,19 +9,21 @@ module ulaplus(
output d_out_active,
output reg active,
input [5:0] ink_addr,
input [5:0] paper_addr,
output reg [7:0] ink,
output reg [7:0] paper
input [5:0] read_addr1,
output reg [7:0] read_data1,
input [5:0] read_addr2,
output reg [7:0] read_data2
);
wire port_bf3b_cs = en && bus.ioreq && bus.a_reg == 16'hbf3b;
wire port_ff3b_cs = en && bus.ioreq && bus.a_reg == 16'hff3b;
wire port_bf3b_cs = en && bus.ioreq && bus.a == 16'hbf3b;
wire port_ff3b_cs = en && bus.ioreq && bus.a == 16'hff3b;
reg port_ff3b_rd;
wire [7:0] port_ff3b_data = {7'b0000000, active};
reg [7:0] addr_reg;
reg [2:0] read_req;
reg [1:0] write_req;
always @(posedge clk28 or negedge rst_n) begin
@ -33,10 +35,11 @@ always @(posedge clk28 or negedge rst_n) begin
end
else begin
if (port_bf3b_cs && bus.wr)
addr_reg <= bus.d_reg;
addr_reg <= bus.d;
if (port_ff3b_cs && bus.wr && addr_reg == 8'b01000000)
active <= bus.d_reg[0];
active <= bus.d[0];
read_req <= {read_req[1:0], port_ff3b_cs && bus.rd && addr_reg[7:6] == 2'b00};
write_req <= {write_req[0], port_ff3b_cs && bus.wr && addr_reg[7:6] == 2'b00};
port_ff3b_rd <= port_ff3b_cs && bus.rd;
@ -45,13 +48,7 @@ always @(posedge clk28 or negedge rst_n) begin
end
end
wire write_req0 = write_req[0] && !write_req[1];
reg read_step;
wire [5:0] ram_a = write_req0? addr_reg[5:0] : read_step? ink_addr : paper_addr;
wire [7:0] ram_q;
ulaplus_ram pallete(ram_q, ram_a, bus.d_reg, write_req0, clk28);
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
read_step <= 0;
@ -59,15 +56,24 @@ always @(posedge clk28 or negedge rst_n) begin
read_step <= !read_step;
end
wire read_req0 = read_req[0] && !read_req[1];
wire write_req0 = write_req[0] && !write_req[1];
wire [5:0] ram_a = (write_req0 || read_req0)? addr_reg[5:0] : read_step? read_addr2 : read_addr1;
wire [7:0] ram_q;
ulaplus_ram pallete(ram_q, ram_a, bus.d, write_req0, clk28);
reg [7:0] ram_q_reg;
always @(posedge clk28) begin
if (read_step)
paper <= ram_q;
if (read_req[1] && !read_req[2])
ram_q_reg <= ram_q;
else if (read_step)
read_data1 <= ram_q;
else
ink <= ram_q;
read_data2 <= ram_q;
end
assign d_out = port_ff3b_data;
assign d_out = (addr_reg[7:6] == 2'b00)? ram_q_reg : port_ff3b_data;
assign d_out_active = port_ff3b_rd;
endmodule

175
fpga/rtl/screen.sv → fpga/rtl/video.sv Executable file → Normal file
View File

@ -1,11 +1,9 @@
`include "util.vh"
import common::*;
module screen(
module video(
input rst_n,
input clk28,
input machine_t machine,
input turbo_t turbo,
input [2:0] border,
output reg [5:0] r,
@ -15,23 +13,22 @@ module screen(
output reg hsync,
output reg csync,
input fetch_allow,
output reg fetch,
output fetch_next,
output [14:0] addr,
input [7:0] fetch_data,
output read_req,
output [14:0] read_req_addr,
input read_req_ack,
input read_data_valid,
input [7:0] read_data,
output contention,
output blink,
output reg even_line,
output port_ff_active,
output [7:0] port_ff_data,
input up_en,
output [5:0] up_ink_addr,
input [7:0] up_ink_data,
output [5:0] up_paper_addr,
input [7:0] up_ink,
input [7:0] up_paper,
input [7:0] up_paper_data,
output [8:0] hc_out,
output [8:0] vc_out,
@ -43,7 +40,21 @@ module screen(
output ck35
);
/* SCREEN CONTROLLER */
reg [8:0] vc;
reg [10:0] hc0;
wire [8:0] hc = hc0[10:2];
assign vc_out = vc;
assign hc_out = hc;
assign clk14 = hc0[0];
assign clk7 = hc0[1];
assign clk35 = hc0[2];
assign ck14 = hc0[0];
assign ck7 = hc0[0] & hc0[1];
assign ck35 = hc0[0] & hc0[1] & hc0[2];
/* SYNC SIGNALS */
localparam H_AREA = 256;
localparam V_AREA = 192;
localparam SCREEN_DELAY = 13;
@ -81,20 +92,6 @@ localparam V_SYNC_PENT = 8;
localparam V_TBORDER_PENT = 64;
localparam V_TOTAL_PENT = V_AREA + V_BBORDER_PENT + V_SYNC_PENT + V_TBORDER_PENT;
reg [8:0] vc;
reg [10:0] hc0;
wire [8:0] hc = hc0[10:2];
assign vc_out = vc;
assign hc_out = hc;
assign clk14 = hc0[0];
assign clk7 = hc0[1];
assign clk35 = hc0[2];
assign ck14 = hc0[0];
assign ck7 = hc0[0] & hc0[1];
assign ck35 = hc0[0] & hc0[1] & hc0[2];
wire hc0_reset =
(machine == MACHINE_S48)?
hc0 == (H_TOTAL_S48<<2) - 1'b1 :
@ -111,14 +108,11 @@ wire vc_reset =
vc == V_TOTAL_PENT - 1'b1 ;
wire hsync0 =
(machine == MACHINE_S48)?
(hc >= (H_AREA + H_RBORDER_S48 + H_BLANK1_S48)) &&
(hc < (H_AREA + H_RBORDER_S48 + H_BLANK1_S48 + H_SYNC_S48)) :
(hc >= (H_AREA + H_RBORDER_S48 + H_BLANK1_S48)) && (hc < (H_AREA + H_RBORDER_S48 + H_BLANK1_S48 + H_SYNC_S48)) :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
(hc >= (H_AREA + H_RBORDER_S128 + H_BLANK1_S128)) &&
(hc < (H_AREA + H_RBORDER_S128 + H_BLANK1_S128 + H_SYNC_S128)) :
(hc >= (H_AREA + H_RBORDER_S128 + H_BLANK1_S128)) && (hc < (H_AREA + H_RBORDER_S128 + H_BLANK1_S128 + H_SYNC_S128)) :
// Pentagon
(hc >= (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT)) &&
(hc < (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT + H_SYNC_PENT)) ;
(hc >= (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT)) && (hc < (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT + H_SYNC_PENT)) ;
wire vsync0 =
(machine == MACHINE_S48)?
(vc >= (V_AREA + V_BBORDER_S48)) && (vc < (V_AREA + V_BBORDER_S48 + V_SYNC_S48)) :
@ -140,7 +134,6 @@ wire blank =
((hc >= (H_AREA + H_RBORDER_PENT)) &&
(hc < (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT + H_SYNC_PENT + H_BLANK2_PENT))) ;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
hc0 <= 0;
@ -160,9 +153,8 @@ always @(posedge clk28 or negedge rst_n) begin
end
end
reg [4:0] blink_cnt;
assign blink = blink_cnt[$bits(blink_cnt)-1];
wire blink = blink_cnt[$bits(blink_cnt)-1];
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
blink_cnt <= 0;
@ -181,11 +173,24 @@ always @(posedge clk28 or negedge rst_n) begin
end
/* SCREEN CONTROLLER */
wire screen_show = (vc < V_AREA) && (hc0 >= (SCREEN_DELAY<<2) - 1) && (hc0 < ((H_AREA + SCREEN_DELAY)<<2) - 1);
wire screen_update = hc0[4:0] == 5'b10011;
wire border_update = (hc0[4:0] == 5'b10011) || (machine == MACHINE_PENT && ck7);
wire bitmap_shift = hc0[1:0] == 2'b11;
wire next_addr = hc0[4:0] == 5'b10000;
wire next_addr = hc0[4:0] == 5'b10001;
reg screen_read, up_read;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
screen_read <= 0;
up_read <= 0;
end
else begin
screen_read <= (vc < V_AREA) && (hc0 > 17) && (hc0 < (H_AREA<<2) + 17);
up_read <= screen_read && (screen_update || up_read);
end
end
reg [7:0] vaddr;
reg [7:3] haddr;
@ -200,71 +205,57 @@ always @(posedge clk28 or negedge rst_n) begin
end
end
reg loading, loading_up;
reg [7:0] bitmap, attr, bitmap_next, attr_next;
reg [7:0] up_ink, up_paper;
reg read_step, read_step_cur;
assign read_req = 1'b1; // just to simplify logic
assign read_req_addr = (read_step == 1'd1)?
{ 2'b10, vaddr[7:6], vaddr[2:0], vaddr[5:3], haddr[7:3] } :
{ 5'b10110, vaddr[7:3], haddr[7:3] };
assign up_ink_addr = up_read? { attr_next[7:6], 1'b0, attr_next[2:0] } : { 3'b0, border[2:0] };
assign up_paper_addr = up_read? { attr_next[7:6], 1'b1, attr_next[5:3] } : { 3'b0, border[2:0] };
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
loading <= 0;
loading_up <= 0;
read_step <= 0;
read_step_cur <= 0;
attr_next <= 0;
bitmap_next <= 0;
end
else begin
loading <= (vc < V_AREA) && (hc0 > 15) && (hc0 < (H_AREA<<2) + 17);
loading_up <= loading && (screen_update || loading_up);
if (next_addr)
read_step <= 0;
else if (read_req_ack)
read_step <= read_step + 1'd1;
if (read_req_ack)
read_step_cur <= read_step;
if (read_data_valid && read_step_cur == 2'd0 && screen_read)
attr_next <= read_data;
else if (!screen_read && hc0[0])
attr_next <= {2'b00, border[2:0], border[2:0]};
if (read_data_valid && read_step_cur == 2'd1 && screen_read)
bitmap_next <= read_data;
else if (!screen_read && hc0[0])
bitmap_next <= 0;
end
end
wire [7:0] attr_border = {2'b00, border[2:0], border[2:0]};
reg [7:0] bitmap, attr, bitmap_next, attr_next;
reg [7:0] up_ink0, up_paper0;
reg [1:0] fetch_cnt;
localparam FETCH_CYCLES = 2'd2;
assign fetch_next = loading && (fetch_allow || (|fetch_cnt && fetch_cnt != FETCH_CYCLES && turbo == TURBO_14));
reg fetch_step;
wire fetch_bitmap = fetch && fetch_step == 1'd0 && fetch_cnt == FETCH_CYCLES;
wire fetch_attr = fetch && fetch_step == 1'd1 && fetch_cnt == FETCH_CYCLES;
assign addr = (fetch_step == 1'd0)?
{ 2'b10, vaddr[7:6], vaddr[2:0], vaddr[5:3], haddr[7:3] } :
{ 5'b10110, vaddr[7:3], haddr[7:3] };
assign up_ink_addr = loading_up? { attr_next[7:6], 1'b0, attr_next[2:0] } : { 3'b0, attr_border[2:0] };
assign up_paper_addr = loading_up? { attr_next[7:6], 1'b1, attr_next[5:3] } : { 3'b0, attr_border[2:0] };
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
fetch <= 0;
fetch_step <= 0;
fetch_cnt <= 0;
attr <= 0;
bitmap <= 0;
attr_next <= 0;
bitmap_next <= 0;
up_ink0 <= 0;
up_paper0 <= 0;
up_ink <= 0;
up_paper <= 0;
end
else begin
fetch <= fetch_next;
if (fetch_cnt == FETCH_CYCLES) begin
if (fetch_step == 1'd1)
attr_next <= fetch_data;
if (fetch_step == 1'd0)
bitmap_next <= fetch_data;
fetch_step <= fetch_step + 1'b1;
fetch_cnt <= 0;
end
else if (fetch && fetch_next && !next_addr) begin
fetch_cnt <= fetch_cnt + 1'b1;
end
else begin
fetch_cnt <= 0;
end
if (screen_show && screen_update)
attr <= attr_next;
else if (!screen_show && border_update)
attr <= attr_border;
attr <= {2'b00, border[2:0], border[2:0]};
if (screen_update)
bitmap <= bitmap_next;
@ -272,9 +263,9 @@ always @(posedge clk28 or negedge rst_n) begin
bitmap <= {bitmap[6:0], 1'b0};
if (screen_update)
up_ink0 <= up_ink;
up_ink <= up_ink_data;
if (screen_update)
up_paper0 <= up_paper;
up_paper <= up_paper_data;
end
end
@ -282,7 +273,7 @@ end
/* ATTRIBUTE PORT */
wire port_ff_attr = (machine == MACHINE_PENT) || hc[3:1] == 3'h6 || hc[3:1] == 3'h0;
wire port_ff_bitmap = (hc[3] && hc[1]);
assign port_ff_active = loading && (port_ff_attr || port_ff_bitmap);
assign port_ff_active = screen_read && (port_ff_attr || port_ff_bitmap);
assign port_ff_data =
port_ff_attr? attr_next :
port_ff_bitmap? bitmap_next :
@ -291,15 +282,15 @@ assign port_ff_data =
assign contention = (vc < V_AREA) && (hc < H_AREA) && (hc[2] || hc[3]);
/* RGBS generation */
/* RGBS OUTPUT */
wire pixel = bitmap[7];
always @(posedge clk28) begin
if (blank)
{g, r, b} = 0;
else if (up_en) begin
g[5:3] = pixel? up_ink0[7:5] : up_paper0[7:5];
r[5:3] = pixel? up_ink0[4:2] : up_paper0[4:2];
b[5:4] = pixel? up_ink0[1:0] : up_paper0[1:0];
g[5:3] = pixel? up_ink[7:5] : up_paper[7:5];
r[5:3] = pixel? up_ink[4:2] : up_paper[4:2];
b[5:4] = pixel? up_ink[1:0] : up_paper[1:0];
g[2:0] = g[5:3];
r[2:0] = r[5:3];
b[3:0] = {b[5:4], b[5:4]};

View File

@ -12,6 +12,9 @@ sof2jic:
mv output/zx_ula.jic "output/${REVISION}.jic"
rm output/zx_ula.sof
rbf2bin:
srec_cat output/rev_${REV}.rbf -binary -Bit_Reverse 2 -Byte_Swap 2 -o output/rev_${REV}.bin -binary
program_sof:
quartus_pgm --no_banner --mode=jtag -o "P;output/${REVISION}.sof"
@ -24,6 +27,6 @@ clean:
report:
cat output/${REVISION}.*.smsg output/${REVISION}.*.rpt |grep -e Error -e Critical -e Warning |grep -v -e "Family doesn't support jitter analysis" -e "Force Fitter to Avoid Periphery Placement Warnings"
export PATH:=/opt/quartus13.0sp1/quartus/bin:/cygdrive/c/Hwdev/quartus130sp1/quartus/bin:${PATH}
export PATH:=/opt/quartus13.0sp1/quartus/bin:/cygdrive/c/Hwdev/quartus130sp1/quartus/bin:/cygdrive/c/Dev/srec/bin/:${PATH}
-include Makefile.local

View File

@ -1,7 +1,7 @@
create_clock -period 28MHz -name {clk28} [get_ports {clk_in}]
create_generated_clock -name {clkcpu} -divide_by 2 -source [get_ports {clk_in}] [get_registers {cpucontrol:cpucontrol0|clkcpu}]
create_generated_clock -name {hc0[1]} -divide_by 4 -source [get_ports {clk_in}] [get_registers {screen:screen0|hc0[1]}]
create_generated_clock -name {clkcpu} -divide_by 2 -source [get_ports {clk_in}] [get_registers {cpu:cpu0|clkcpu}]
create_generated_clock -name {hc0[1]} -divide_by 4 -source [get_ports {clk_in}] [get_registers {video:video0|hc0[1]}]
derive_pll_clocks
derive_clocks -period 14MHz
@ -9,12 +9,12 @@ derive_clocks -period 14MHz
set_multicycle_path -from {vencode:*|*} -to {vencode:*|*} -setup 4
set_multicycle_path -from {vencode:*|*} -to {vencode:*|*} -hold 3
# One screen read cycle = ~71ns. SRAM speed = 55ns
# One video read cycle = ~71ns. SRAM speed = 55ns
# So we have about 16ns to setup control signals (n_vrd, n_vwr, va - 10ns) and read back data (vd - 6ns)
set_max_delay -from [get_pins -compatibility_mode screen0|*] -to [get_ports n_vrd] 10ns
set_max_delay -from [get_pins -compatibility_mode screen0|*] -to [get_ports n_vwr] 10ns
set_max_delay -from [get_pins -compatibility_mode screen0|*] -to [get_ports va[*]] 10ns
set_max_delay -from [get_ports vd[*]] -to [get_pins -compatibility_mode screen0|*] 6ns
set_max_delay -from [get_pins -compatibility_mode video0|*] -to [get_ports n_vrd] 10ns
set_max_delay -from [get_pins -compatibility_mode video0|*] -to [get_ports n_vwr] 10ns
set_max_delay -from [get_pins -compatibility_mode video0|*] -to [get_ports va[*]] 10ns
set_max_delay -from [get_ports vd[*]] -to [get_pins -compatibility_mode video0|*] 6ns
set_false_path -from * -to [get_ports {snd_l}]
set_false_path -from * -to [get_ports {snd_r}]

View File

@ -171,12 +171,12 @@ set_global_assignment -name VHDL_FILE ../rtl/vencode.vhd
set_global_assignment -name VERILOG_INCLUDE_FILE ../rtl/ps2_codes.vh
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/mixer.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/soundrive.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/screen.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/video.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/ports.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/magic.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/divmmc.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/cpucontrol.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/memcontrol.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/cpu.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/mem.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/turbosound.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/ulaplus.sv
set_global_assignment -name VERILOG_FILE ../rtl/ps2.v
@ -197,4 +197,6 @@ set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON
set_global_assignment -name PHYSICAL_SYNTHESIS_EFFORT EXTRA
set_global_assignment -name TIMEQUEST_DO_CCPP_REMOVAL ON
set_global_assignment -name CYCLONE_OPTIMIZATION_TECHNIQUE BALANCED
set_global_assignment -name GENERATE_RBF_FILE ON
set_global_assignment -name ON_CHIP_BITSTREAM_DECOMPRESSION OFF
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@ -170,12 +170,12 @@ set_global_assignment -name VHDL_FILE ../rtl/vencode.vhd
set_global_assignment -name VERILOG_INCLUDE_FILE ../rtl/ps2_codes.vh
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/mixer.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/soundrive.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/screen.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/video.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/ports.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/magic.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/divmmc.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/cpucontrol.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/memcontrol.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/cpu.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/mem.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/turbosound.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/ulaplus.sv
set_global_assignment -name VERILOG_FILE ../rtl/ps2.v
@ -197,4 +197,6 @@ set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON
set_global_assignment -name PHYSICAL_SYNTHESIS_EFFORT EXTRA
set_global_assignment -name TIMEQUEST_DO_CCPP_REMOVAL ON
set_global_assignment -name CYCLONE_OPTIMIZATION_TECHNIQUE BALANCED
set_global_assignment -name GENERATE_RBF_FILE ON
set_global_assignment -name ON_CHIP_BITSTREAM_DECOMPRESSION OFF
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@ -170,12 +170,12 @@ set_global_assignment -name VHDL_FILE ../rtl/vencode.vhd
set_global_assignment -name VERILOG_INCLUDE_FILE ../rtl/ps2_codes.vh
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/mixer.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/soundrive.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/screen.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/video.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/ports.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/magic.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/divmmc.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/cpucontrol.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/memcontrol.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/cpu.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/mem.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/turbosound.sv
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/ulaplus.sv
set_global_assignment -name VERILOG_FILE ../rtl/ps2.v
@ -198,4 +198,6 @@ set_global_assignment -name PHYSICAL_SYNTHESIS_EFFORT EXTRA
set_global_assignment -name CYCLONE_OPTIMIZATION_TECHNIQUE BALANCED
set_global_assignment -name TIMEQUEST_DO_CCPP_REMOVAL ON
set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON
set_global_assignment -name GENERATE_RBF_FILE ON
set_global_assignment -name ON_CHIP_BITSTREAM_DECOMPRESSION OFF
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@ -44,13 +44,21 @@ Loop:
ORG #8000 // mapped #0000
MagicROM_Start:
ld sp, #8000
ld bc, #09ff ; divmmc = 1
ld a, 1 ; ...
out (c), a ; ...
ld bc, #03ff ; cpu freq = 7mhz
ld a, 3 ; ...
ld bc, #02ff ; machine = 128
ld a, 1 ; ...
out (c), a ; ...
ld bc, #03ff ; cpu freq = 14mhz
ld a, 4 ; ...
out (c), a ; ...
.100 in a, (#fe)
ld bc, #0000
ld de, #5000
ld hl, #6000
ldir
push bc
jp #f008
ORG #F000

BIN
out/fpga.rev.A.bin vendored Normal file

Binary file not shown.

BIN
out/fpga.rev.B.bin vendored Normal file

Binary file not shown.

BIN
out/fpga.zero.rev.A.bin vendored Normal file

Binary file not shown.

View File

@ -1,7 +1,11 @@
ifneq ($(wildcard ../.git),)
VERSION := $(shell git describe --abbrev=6 --long --dirty --always --tags --first-parent)
endif
export PATH:=/cygdrive/c/Hwdev/sjasmplus/:/cygdrive/c/Dev/srec/:${PATH}
REV=D
SJOPTS=-DSIZIFXXS -DREV_${REV}
SJOPTS=-DSIZIFXXS -DREV_${REV} -DVERSION=\"${VERSION}\"
.PHONY: all clean .FORCE
.FORCE:
@ -19,3 +23,5 @@ clean:
srec_cat $< -binary -o $@ -intel
test: main_test.bin
-include Makefile.local

View File

@ -31,6 +31,9 @@ ay DB 1
sd DB 2
ulaplus DB 1
dac DB 3
sdind DB 1
_reserv4 DB 0
autoturbo DB 0
ENDS
CFG_DEFAULT CFG_T

View File

@ -1,5 +1,6 @@
ASSERT __SJASMPLUS__ >= 0x011402 ; SjASMPlus 1.20.2
OPT --syntax=abf
DEVICE ZXSPECTRUM48
OPT --syntax=F
; Startup handler
ORG #0000
@ -497,13 +498,22 @@ wait_for_keys_release:
include font.asm
include strings.asm
DISPLAY "Free space: ",/D,#1FE8-$
ASSERT $ < #1FE8
DISPLAY "Free space: ",/D,fwinfo-$," (",$,")"
ASSERT $ < fwinfo
; Just some string at the end of ROM
ORG #1FE8
DB 0,"End of Sizif Magic ROM",0
; Just some firmware info at the end of ROM
ORG #2000-(fwinfo.end-fwinfo)
fwinfo:
DB 0
.version:
DB VERSION, 0
.date
DB __DATE__, 0
.time:
DB __TIME__, 0
DB "End of Sizif Magic ROM", 0
.end
; Variables
ORG #C000

View File

@ -37,10 +37,18 @@ menudefault: MENU_DEF 20
MENUENTRY_T str_sd menu_sd_value_cb menu_sd_cb
MENUENTRY_T str_ulaplus menu_ulaplus_value_cb menu_ulaplus_cb
MENUENTRY_T str_dac menu_dac_value_cb menu_dac_cb
MENUENTRY_T str_menuadv 0 menu_menuadv_cb
MENUENTRY_T str_exit menu_exit_value_cb menu_exit_cb
MENUENTRY_T 0
.end:
menuadv: MENU_DEF 22
MENUENTRY_T str_sd_indication menu_sdind_value_cb menu_sdind_cb
MENUENTRY_T str_autoturbo menu_autoturbo_value_cb menu_autoturbo_cb
MENUENTRY_T str_back 0 menu_back_cb
MENUENTRY_T 0
.end:
menu_machine_value_cb:
@ -48,73 +56,89 @@ menu_machine_value_cb:
ld a, (cfg.machine)
jp menu_value_get
.values_table:
DW str_machine_48_end-2
DW str_machine_128_end-2
DW str_machine_3e_end-2
DW str_machine_pentagon_end-2
DW str_machine_48.end-2
DW str_machine_128.end-2
DW str_machine_3e.end-2
DW str_machine_pentagon.end-2
menu_clock_value_cb:
ld ix, .values_table
ld a, (cfg.clock)
jp menu_value_get
.values_table:
DW str_cpu_35_end-2
DW str_cpu_44_end-2
DW str_cpu_52_end-2
DW str_cpu_7_end-2
DW str_cpu_14_end-2
DW str_cpu_35.end-2
DW str_cpu_44.end-2
DW str_cpu_52.end-2
DW str_cpu_7.end-2
DW str_cpu_14.end-2
menu_panning_value_cb:
ld ix, .values_table
ld a, (cfg.panning)
jp menu_value_get
.values_table:
DW str_panning_mono_end-2
DW str_panning_abc_end-2
DW str_panning_acb_end-2
DW str_panning_mono.end-2
DW str_panning_abc.end-2
DW str_panning_acb.end-2
menu_joystick_value_cb:
ld ix, .values_table
ld a, (cfg.joystick)
jp menu_value_get
.values_table:
DW str_joystick_kempston_end-2
DW str_joystick_sinclair_end-2
DW str_joystick_kempston.end-2
DW str_joystick_sinclair.end-2
menu_sd_value_cb:
ld ix, .values_table
ld a, (cfg.sd)
jp menu_value_get
.values_table:
DW str_off_end-2
DW str_divmmc_end-2
DW str_zc3e_end-2
DW str_off.end-2
DW str_divmmc.end-2
DW str_zc3e.end-2
menu_ulaplus_value_cb:
ld ix, .values_table
ld a, (cfg.ulaplus)
jp menu_value_get
.values_table:
DW str_off_end-2
DW str_on_end-2
DW str_off.end-2
DW str_on.end-2
menu_dac_value_cb:
ld ix, .values_table
ld a, (cfg.dac)
jp menu_value_get
.values_table:
DW str_off_end-2
DW str_dac_covox_end-2
DW str_dac_sd_end-2
DW str_dac_covoxsd_end-2
DW str_off.end-2
DW str_dac_covox.end-2
DW str_dac_sd.end-2
DW str_dac_covoxsd.end-2
menu_exit_value_cb:
ld ix, .values_table
ld a, (var_exit_reboot)
jp menu_value_get
.values_table:
DW str_exit_no_reboot_end-2
DW str_exit_reboot_end-2
DW str_exit_no_reboot.end-2
DW str_exit_reboot.end-2
menu_sdind_value_cb:
ld ix, .values_table
ld a, (cfg.sdind)
jp menu_value_get
.values_table:
DW str_off_short.end-2
DW str_on_short.end-2
menu_autoturbo_value_cb:
ld ix, .values_table
ld a, (cfg.autoturbo)
jp menu_value_get
.values_table:
DW str_off_short.end-2
DW str_on_short.end-2
menu_value_get:
sla a
@ -203,6 +227,34 @@ menu_exit_cb:
ld (var_exit_flag), a
ret
menu_menuadv_cb:
ld hl, menuadv
call menu_init
ret
menu_sdind_cb:
ld a, (cfg.sdind)
ld c, 1
call menu_handle_press
ld (cfg.sdind), a
ld bc, #0cff
out (c), a
ret
menu_autoturbo_cb:
ld a, (cfg.autoturbo)
ld c, 1
call menu_handle_press
ld (cfg.autoturbo), a
ld bc, #0eff
out (c), a
ret
menu_back_cb:
call restore_screen
ld hl, (var_menumain)
jp menu_init
; IN - A - variable to change
; IN - C - max value

View File

@ -1,100 +1,45 @@
MACRO DEFSTR _string
DB _string,0
@.end:
ENDM
DB 0
str_sizif: DB "SIZIF-XXS",0
str_sizif_end:
str_pause DB " PAUSE ",0
str_pause_end:
str_exit: DB "Exit",0
str_exit_end:
str_exit_reboot: DB "& reboot ",0
str_exit_reboot_end:
str_exit_no_reboot: DB " ",0
str_exit_no_reboot_end:
str_on: DB " ON",0
str_on_end:
str_off: DB " OFF",0
str_off_end:
str_machine: DB "Machine",0
str_machine_end:
str_machine_48: DB " 48",0
str_machine_48_end:
str_machine_128: DB " 128",0
str_machine_128_end:
str_machine_3e: DB " +3e",0
str_machine_3e_end:
str_machine_pentagon: DB "Pentagon",0
str_machine_pentagon_end:
str_cpu: DB "CPU freq",0
str_cpu_end:
str_cpu_35: DB "3.5MHz",0
str_cpu_35_end:
str_cpu_44: DB "4.4MHz",0
str_cpu_44_end:
str_cpu_52: DB "5.2MHz",0
str_cpu_52_end:
str_cpu_7: DB " 7MHz",0
str_cpu_7_end:
str_cpu_14: DB " 14MHz",0
str_cpu_14_end:
str_panning: DB "Panning",0
str_panning_end:
str_panning_abc: DB " ABC",0
str_panning_abc_end:
str_panning_acb: DB " ACB",0
str_panning_acb_end:
str_panning_mono: DB "Mono",0
str_panning_mono_end:
str_joystick: DB "Joystick",0
str_joystick_end:
str_joystick_kempston: DB "Kempston",0
str_joystick_kempston_end:
str_joystick_sinclair: DB "Sinclair",0
str_joystick_sinclair_end:
str_sd: DB "SD card",0
str_sd_end:
str_divmmc: DB "DivMMC",0
str_divmmc_end:
str_zc3e: DB "ZC/+3e",0
str_zc3e_end:
str_ulaplus: DB "ULA+",0
str_ulaplus_end
str_dac: DB "DAC",0
str_dac_end
str_dac_covox: DB " Covox",0
str_dac_covox_end
str_dac_sd: DB " SD",0
str_dac_sd_end
str_dac_covoxsd: DB "Covox+SD",0
str_dac_covoxsd_end
str_sizif: DEFSTR "SIZIF-XXS"
str_pause: DEFSTR " PAUSE "
str_exit: DEFSTR "Exit"
str_exit_reboot: DEFSTR "& reboot "
str_exit_no_reboot: DEFSTR " "
str_on: DEFSTR " ON"
str_off: DEFSTR " OFF"
str_on_short: DEFSTR " ON"
str_off_short: DEFSTR "OFF"
str_machine: DEFSTR "Machine"
str_machine_48: DEFSTR " 48"
str_machine_128: DEFSTR " 128"
str_machine_3e: DEFSTR " +3e"
str_machine_pentagon: DEFSTR "Pentagon"
str_cpu: DEFSTR "CPU freq"
str_cpu_35: DEFSTR "3.5MHz"
str_cpu_44: DEFSTR "4.4MHz"
str_cpu_52: DEFSTR "5.2MHz"
str_cpu_7: DEFSTR " 7MHz"
str_cpu_14: DEFSTR " 14MHz"
str_panning: DEFSTR "Panning"
str_panning_abc: DEFSTR " ABC"
str_panning_acb: DEFSTR " ACB"
str_panning_mono: DEFSTR "Mono"
str_joystick: DEFSTR "Joystick"
str_joystick_kempston: DEFSTR "Kempston"
str_joystick_sinclair: DEFSTR "Sinclair"
str_sd: DEFSTR "SD card"
str_divmmc: DEFSTR "DivMMC"
str_zc3e: DEFSTR "ZC/+3e"
str_ulaplus: DEFSTR "ULA+"
str_dac: DEFSTR "DAC"
str_dac_covox: DEFSTR " Covox"
str_dac_sd: DEFSTR " SD"
str_dac_covoxsd: DEFSTR "Covox+SD"
str_menuadv: DEFSTR "Advanced..."
str_sd_indication: DEFSTR "SD indication"
str_autoturbo: DEFSTR "Auto CPU freq"
str_back: DEFSTR "Go back..."