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

merge latest changes from sizif-512

* add 4.4 MHz and 5.2 MHz turbo modes
* handle magic key press if initialization wasn't completed before
* replace 'timings', 'ram', 'plus3' settings with one 'machine' setting
* refactor memory controller
* significantly improve classic timings
* magic rom: fix 'h' font character
* fix hanging of esxdos browser after magic key double press
* enable divmmc (esxdos OS) by magic rom on poweron; add NO-OS option
* improve pause ('f12' on ps/2 keyboard or 'start' on gamepad)
* magic rom: handle C-key on sega gamepad as exit
This commit is contained in:
UzixLS
2021-09-21 19:57:59 +03:00
parent 83081238ed
commit 0e572d9d69
28 changed files with 1183 additions and 645 deletions

View File

@ -1,7 +1,8 @@
package common;
typedef enum { TIMINGS_PENT, TIMINGS_S48, TIMINGS_S128 } timings_t;
typedef enum { TURBO_NONE, TURBO_7, TURBO_14 } turbo_t;
typedef enum { RAM_512, RAM_48, RAM_128 } rammode_t;
typedef enum { MACHINE_S48, MACHINE_S128, MACHINE_S3, MACHINE_PENT } machine_t;
typedef enum { TURBO_NONE, TURBO_4, TURBO_5, TURBO_7, TURBO_14 } turbo_t;
typedef enum { PANNING_MONO, PANNING_ABC, PANNING_ACB } panning_t;
typedef enum { DIVMMC_OFF, DIVMMC_ON, DIVMMC_NOOS } divmmc_t;
endpackage

View File

@ -5,16 +5,17 @@ module cpucontrol(
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 screen_loading,
input machine_t machine,
input turbo_t turbo,
input timings_t timings,
input pause,
input ext_wait_cycle,
input init_done_in,
@ -29,17 +30,19 @@ module cpucontrol(
/* CONTENTION */
wire iorq_contended = bus.iorq && (~bus.a[0] || (~bus.a[1] && ~bus.a[15]));
reg mreq_delayed, iorq_delayed;
always @(posedge clkcpu)
mreq_delayed <= bus.mreq;
always @(posedge clkcpu)
iorq_delayed <= bus.iorq;
wire contention_mem_addr = bus.a[14] & (~bus.a[15] | (bus.a[15] & rampage128[0]));
iorq_delayed <= iorq_contended;
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 && bus.iorq;
wire contention0 = screen_loading && (hc[2] || hc[3]) && (contention_mem || contention_io);
wire contention = clkcpu && contention0 && turbo == TURBO_NONE && timings != TIMINGS_PENT;
assign snow = (timings != TIMINGS_PENT) && bus.a[14] && ~bus.a[15] && bus.rfsh;
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 */
@ -47,35 +50,47 @@ reg [2:0] turbo_wait;
wire turbo_wait_trig0 = bus.rd || bus.wr;
reg turbo_wait_trig1;
always @(posedge clk28) begin
turbo_wait_trig1 <= turbo_wait_trig0;
turbo_wait[0] <= turbo == TURBO_14 && turbo_wait_trig0 && !turbo_wait_trig1;
turbo_wait[1] <= turbo_wait[0] && (bus.iorq || ext_wait_cycle);
turbo_wait[2] <= turbo_wait[1];
turbo_wait_trig1 <= turbo_wait_trig0;
end
reg clkcpu_prev;
assign clkcpu_ck = clkcpu && ! clkcpu_prev;
assign clkwait = pause || contention || (|turbo_wait);
always @(negedge clk28) begin
assign clkcpu_ck = clkcpu && !clkcpu_prev;
assign clkwait = contention || (|turbo_wait);
always @(posedge clk28) begin
clkcpu_prev <= clkcpu;
clkcpu <= clkwait? clkcpu : (turbo == TURBO_14)? clk14 : (turbo == TURBO_7)? clk7 : clk35;
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 = 247;
localparam INT_H_S48 = 442;
localparam INT_V_S128 = 247;
localparam INT_H_S128 = 450;
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 = 316;
localparam INT_H_PENT = 322;
wire int_begin =
(timings == TIMINGS_PENT)?
vc == INT_V_PENT && hc == INT_H_PENT :
(timings == TIMINGS_S128)?
(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 :
// 48K
vc == INT_V_S48 && hc == INT_H_S48 ;
// 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
@ -98,9 +113,25 @@ always @(posedge clk28 or negedge rst_n) begin
n_rstcpu <= 0;
else if (!init_done_in)
n_rstcpu <= 0;
else if (vc[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

@ -20,25 +20,26 @@ module divmmc(
input magic_mode,
input magic_map,
output reg [3:0] div_page,
output div_map,
output div_ram,
output div_ramwr_mask,
output div_wait
output reg [3:0] page,
output map,
output reg automap,
output ram,
output ramwr_mask,
output cpuwait
);
reg div_automap, div_automap_next;
reg automap_next;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
div_automap_next <= 0;
div_automap <= 0;
automap_next <= 0;
automap <= 0;
end
else if (bus.m1 && bus.memreq && magic_map == 0) begin
else if (bus.m1 && bus.memreq && !magic_map) begin
if (!en_hooks || !en || rammap) begin
div_automap_next <= 0;
automap_next <= 0;
end
else if (bus.a_reg[15:3] == 13'h3FF) begin // exit vectors 1FF8-1FFF
div_automap_next <= 0;
automap_next <= 0;
end
else if (
bus.a_reg == 16'h0000 || // power-on/reset/rst0/software restart
@ -48,37 +49,37 @@ always @(posedge clk28 or negedge rst_n) begin
bus.a_reg == 16'h04C6 || // tape save routine
bus.a_reg == 16'h0562 // tape load and verify routine
) begin
div_automap_next <= 1'b1;
automap_next <= 1'b1;
end
else if (bus.a_reg[15:8] == 8'h3D) begin // tr-dos mapping area
div_automap_next <= 1'b1;
div_automap <= 1'b1;
automap_next <= 1'b1;
automap <= 1'b1;
end
end
else if (!bus.m1) begin
div_automap <= div_automap_next;
automap <= automap_next;
end
end
reg spi_rd;
reg div_conmem, div_mapram;
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;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
spi_rd <= 0;
div_page <= 0;
div_mapram <= 0;
div_conmem <= 0;
page <= 0;
mapram <= 0;
conmem <= 0;
sd_cs <= 1'b1;
end
else begin
spi_rd <= port_eb_cs && bus.rd;
if (port_e3_cs && bus.wr) begin
div_page <= bus.d_reg[3:0];
div_mapram <= bus.d_reg[6] | div_mapram;
div_conmem <= bus.d_reg[7];
page <= bus.d_reg[3:0];
mapram <= bus.d_reg[6] | mapram;
conmem <= bus.d_reg[7];
end
if (port_e7_cs && bus.wr) begin
sd_cs <= bus.d_reg[0];
@ -88,7 +89,7 @@ end
reg [3:0] spi_cnt;
wire spi_cnt_en = ~spi_cnt[3] | spi_cnt[2] | spi_cnt[1] | spi_cnt[0];
assign div_wait = ~spi_cnt[3];
assign cpuwait = ~spi_cnt[3];
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
spi_cnt <= 0;
@ -125,12 +126,15 @@ always @(posedge clk28) begin
end
assign div_map = div_automap | div_conmem;
assign div_ram = (div_conmem == 1 && bus.a[13] == 1) ||
(div_automap == 1 && bus.a[13] == 1) ||
(div_conmem == 0 && div_automap == 1 && div_mapram == 1);
assign div_ramwr_mask = bus.a[15] == 0 && bus.a[14] == 0 &&
(bus.a[13] == 0 || div_page == 4'b0011) && div_conmem == 0 && div_automap == 1 && div_mapram == 1;
assign map = automap | conmem;
assign ram =
(automap && bus.a[13]) ||
(conmem && bus.a[13]) ||
(!conmem && automap && mapram);
assign ramwr_mask =
!bus.a[15] && !bus.a[14] &&
(!bus.a[13] || page == 4'b0011) &&
!conmem && automap && mapram;
assign d_out_active = spi_rd;
assign d_out = spi_reg;

View File

@ -4,26 +4,28 @@ module magic(
input clk28,
cpu_bus bus,
output [7:0] d_out,
output d_out_active,
input n_int,
input n_int_next,
output reg n_nmi,
input magic_button,
input pause_button,
input sd_cd,
input div_automap,
output reg magic_mode,
output reg magic_map,
output reg magic_reboot,
output reg magic_beeper,
output timings_t timings,
output machine_t machine,
output turbo_t turbo,
output rammode_t ram_mode,
output panning_t panning,
output reg joy_sinclair,
output reg rom_plus3,
output reg rom_alt48,
output reg mix_acb,
output reg mix_mono,
output reg divmmc_en,
output divmmc_t divmmc_en,
output reg ulaplus_en,
output reg covox_en,
output reg sd_en
@ -40,7 +42,7 @@ always @(posedge clk28 or negedge rst_n) begin
magic_unmap_next <= 0;
end
else begin
if (magic_button == 1'b1 && n_int == 1'b1 && n_int_next == 1'b0) begin
if ((magic_button || pause_button) && n_int == 1'b1 && n_int_next == 1'b0) begin
if (!magic_mode)
n_nmi <= 1'b0;
magic_mode <= 1'b1;
@ -68,20 +70,16 @@ end
/* MAGIC CONFIG */
wire config_cs = magic_map && bus.ioreq && bus.a_reg[7:0] == 8'hff;
wire config_cs = magic_map && bus.ioreq && bus.a_reg[7:0] == 8'hFF;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
magic_reboot <= 0;
magic_beeper <= 0;
timings <= TIMINGS_PENT;
machine <= MACHINE_PENT;
turbo <= TURBO_NONE;
mix_acb <= 0;
mix_mono <= 0;
ram_mode <= RAM_512;
rom_plus3 <= 1'b1;
rom_alt48 <= 0;
panning <= PANNING_ABC;
joy_sinclair <= 0;
divmmc_en <= 1'b1;
divmmc_en <= DIVMMC_NOOS;
ulaplus_en <= 1'b1;
covox_en <= 1'b1;
sd_en <= 1'b1;
@ -89,18 +87,29 @@ always @(posedge clk28 or negedge rst_n) begin
else if (config_cs && bus.wr) case (bus.a_reg[15:8])
8'h00: magic_reboot <= bus.d_reg[0];
8'h01: magic_beeper <= bus.d_reg[0];
8'h02: timings <= timings_t'(bus.d_reg[1:0]);
8'h03: turbo <= turbo_t'(bus.d_reg[1:0]);
8'h04: {mix_mono, mix_acb} <= bus.d_reg[1:0];
8'h05: rom_plus3 <= bus.d_reg[0];
8'h06: rom_alt48 <= bus.d_reg[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: ram_mode <= rammode_t'(bus.d_reg[1:0]);
8'h09: divmmc_en <= bus.d_reg[0];
8'h09: divmmc_en <= divmmc_t'(bus.d_reg[1:0]);
8'h0a: ulaplus_en <= bus.d_reg[0];
8'h0b: {sd_en, covox_en} <= bus.d_reg[1:0];
endcase
end
reg config_rd;
wire [7:0] config_data = {4'b0000, div_automap, sd_cd, 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'hFF;
end
/* BUS CONTROLLER */
assign d_out_active = config_rd;
assign d_out = config_data;
endmodule

120
fpga/rtl/memcontrol.sv Normal file
View File

@ -0,0 +1,120 @@
import common::*;
module memcontrol(
input rst_n,
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
);
/* MEMORY CONTROLLER */
reg romreq, ramreq, ramreq_wr;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
romreq = 1'b0;
ramreq = 1'b0;
ramreq_wr = 1'b0;
end
else begin
romreq = bus.mreq && !bus.rfsh && bus.a[14] == 0 && bus.a[15] == 0 &&
(magic_map || (!div_ram && div_map) || (!div_ram && !port_dffd[4] && !port_1ffd[0]));
ramreq = bus.mreq && !bus.rfsh && !romreq;
ramreq_wr = ramreq && bus.wr && div_ramwr_mask == 0;
end
end
assign n_vrd = ((((ramreq || romreq) && 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;
/* VA[18:13] map
* 00xxxx 128Kb 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 [18:13] ram_a;
always @(posedge clk28) begin
ram_a <=
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[14] & ~bus.a[15] & bus.a[13]? {2'b01, div_page} :
div_map & ~bus.a[14] & ~bus.a[15]? {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]} :
(port_1ffd == 3'b111)? {2'b11, ~(bus.a[15] & bus.a[14]), (bus.a[15] | bus.a[14]), bus.a[14]} :
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
reg [16:14] rom_a;
always @(posedge clk28) begin
rom_a <=
magic_map? 3'd2 :
div_map? 3'd3 :
(machine == MACHINE_S3 && port_1ffd[2] == 1'b0 && rompage128 == 1'b0)? 3'd4 :
(machine == MACHINE_S3 && port_1ffd[2] == 1'b0 && rompage128 == 1'b1)? 3'd5 :
(machine == MACHINE_S3 && port_1ffd[2] == 1'b1 && rompage128 == 1'b0)? 3'd6 :
(rompage128 == 1'b1)? 3'd1 :
3'd0;
end
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} :
romreq? {2'b00, rom_a[16:14], bus.a[13], {13{1'bz}}} :
{ram_a[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 :
8'hFF;
endmodule

View File

@ -2,9 +2,6 @@ import common::*;
module ports(
input rst_n,
input clk28,
input en_128k,
input en_plus3,
input en_profi,
input en_kempston,
input en_sinclair,
@ -12,13 +9,12 @@ module ports(
output [7:0] d_out,
output d_out_active,
input timings_t timings,
input clkcpu_ck,
input screen_loading,
input [7:0] attr_next,
input machine_t machine,
input port_ff_active,
input [7:0] port_ff_data,
input [4:0] kd,
input [7:0] kempston_data,
input magic_button,
input magic_map,
input tape_in,
output reg tape_out,
@ -27,21 +23,21 @@ module ports(
output reg screenpage,
output reg rompage128,
output reg [2:0] rampage128,
output reg [3:0] rampage_ext,
output reg [2:0] rampage_ext,
output reg [2:0] port_1ffd,
output reg port_dffd_d3,
output reg port_dffd_d4
output reg [4:0] port_dffd
);
/* PORT #FF */
wire [7:0] port_ff_data = attr_next;
reg port_ff_rd;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
port_ff_rd <= 0;
else
port_ff_rd <= bus.rd && bus.ioreq && (timings != TIMINGS_PENT || bus.a_reg[7:0] == 8'hFF) && screen_loading;
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);
end
@ -56,14 +52,14 @@ always @(posedge clk28 or negedge rst_n) begin
end
reg [4:0] kd0;
wire [7:0] port_fe_data = {~magic_button, tape_in, 1'b1, kd0};
always @(posedge clk28 or negedge rst_n) begin
wire [7:0] port_fe_data = {1'b1, tape_in, 1'b1, kd0};
always @(negedge clk28 or negedge rst_n) begin
if (!rst_n) begin
beeper <= 0;
tape_out <= 0;
border <= 0;
end
else if (port_fe_cs && bus.wr && clkcpu_ck) begin // clkcpu_ck to synchronize border
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];
@ -86,7 +82,9 @@ end
/* PORT #7FFD */
wire port_7ffd_cs = en_128k && bus.ioreq && bus.a_reg[1] == 0 && bus.a_reg[15] == 0 && (bus.a_reg[14] == 1'b1 || !en_plus3);
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)) &&
(machine != MACHINE_S48 || magic_map);
reg lock_7ffd;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
@ -95,7 +93,7 @@ always @(posedge clk28 or negedge rst_n) begin
rompage128 <= 0;
lock_7ffd <= 0;
end
else if (port_7ffd_cs && bus.wr && (lock_7ffd == 0 || port_dffd_d4 == 1'b1)) begin
else if (port_7ffd_cs && bus.wr && (lock_7ffd == 0 || port_dffd[4] == 1'b1)) begin
rampage128 <= bus.d_reg[2:0];
screenpage <= bus.d_reg[3];
rompage128 <= bus.d_reg[4];
@ -105,23 +103,21 @@ end
/* PORT #DFFD */
wire port_dffd_cs = en_profi && bus.ioreq && bus.a_reg == 16'hDFFD;
wire port_dffd_cs = bus.ioreq && bus.a_reg == 16'hDFFD && (machine == MACHINE_PENT || magic_map);
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
rampage_ext <= 0;
port_dffd_d3 <= 0;
port_dffd_d4 <= 0;
port_dffd <= 0;
end
else if (port_dffd_cs && bus.wr) begin
rampage_ext <= bus.d_reg[2:0];
port_dffd_d3 <= bus.d_reg[3];
port_dffd_d4 <= bus.d_reg[4];
port_dffd <= bus.d_reg[4:0];
end
end
/* PORT #1FFD */
wire port_1ffd_cs = en_plus3 && bus.ioreq && bus.a_reg == 16'h1FFD;
wire port_1ffd_cs = bus.ioreq && bus.a_reg == 16'h1FFD && (machine == MACHINE_S3 || magic_map);
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
port_1ffd <= 0;

View File

@ -136,8 +136,7 @@ always @(posedge clk or negedge rst_n) begin
`PS2_PGDN: key2_pgdn <= is_press;
`PS2_F5: key_magic <= is_press;
`PS2_F11: key_pause <= 1'b0;
`PS2_F12: key_pause <= 1'b1;
`PS2_F12: key_pause <= is_press;
`PS2_DELETE: key2_del <= is_press;
`PS2_KP_8: joy_up <= is_press;

View File

@ -4,12 +4,12 @@ module screen(
input rst_n,
input clk28,
input timings_t timings,
input machine_t machine,
input [2:0] border,
output reg [2:0] r,
output reg [2:0] g,
output reg [2:0] b,
output reg [1:0] b,
output reg vsync,
output reg hsync,
output reg csync,
@ -20,9 +20,11 @@ module screen(
output [14:0] addr,
input [7:0] fetch_data,
output loading,
output contention,
output blink,
output reg [7:0] attr_next,
output reg even_line,
output port_ff_active,
output [7:0] port_ff_data,
input up_en,
output [5:0] up_ink_addr,
@ -43,24 +45,24 @@ module screen(
/* SCREEN CONTROLLER */
localparam H_AREA = 256;
localparam V_AREA = 192;
localparam SCREEN_DELAY = 8;
localparam SCREEN_DELAY = 13;
localparam H_LBORDER_S48 = 48 - SCREEN_DELAY;
localparam H_RBORDER_S48 = 48 + SCREEN_DELAY;
localparam H_BLANK1_S48 = 17;
localparam H_LBORDER_S48 = 54 - SCREEN_DELAY;
localparam H_RBORDER_S48 = 53 + SCREEN_DELAY;
localparam H_BLANK1_S48 = 12;
localparam H_SYNC_S48 = 33;
localparam H_BLANK2_S48 = 46;
localparam H_BLANK2_S48 = 40;
localparam H_TOTAL_S48 = H_AREA + H_RBORDER_S48 + H_BLANK1_S48 + H_SYNC_S48 + H_BLANK2_S48 + H_LBORDER_S48;
localparam V_BBORDER_S48 = 56;
localparam V_SYNC_S48 = 8;
localparam V_TBORDER_S48 = 56;
localparam V_TOTAL_S48 = V_AREA + V_BBORDER_S48 + V_SYNC_S48 + V_TBORDER_S48;
localparam H_LBORDER_S128 = 48 - SCREEN_DELAY;
localparam H_RBORDER_S128 = 48 + SCREEN_DELAY;
localparam H_BLANK1_S128 = 25;
localparam H_LBORDER_S128 = 58 - SCREEN_DELAY;
localparam H_RBORDER_S128 = 57 + SCREEN_DELAY;
localparam H_BLANK1_S128 = 12;
localparam H_SYNC_S128 = 33;
localparam H_BLANK2_S128 = 46;
localparam H_BLANK2_S128 = 40;
localparam H_TOTAL_S128 = H_AREA + H_RBORDER_S128 + H_BLANK1_S128 + H_SYNC_S128 + H_BLANK2_S128 + H_LBORDER_S128;
localparam V_BBORDER_S128 = 55;
localparam V_SYNC_S128 = 8;
@ -78,12 +80,13 @@ 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 [`CLOG2(`MAX(V_TOTAL_S128, V_TOTAL_PENT))-1:0] vc;
reg [`CLOG2(`MAX(H_TOTAL_S128, H_TOTAL_PENT))+1:0] hc0;
wire [`CLOG2(`MAX(H_TOTAL_S128, H_TOTAL_PENT))-1:0] hc = hc0[$bits(hc0)-1:2];
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];
@ -92,49 +95,49 @@ assign ck7 = hc0[0] & hc0[1];
assign ck35 = hc0[0] & hc0[1] & hc0[2];
wire hc0_reset =
(timings == TIMINGS_PENT)?
hc0 == (H_TOTAL_PENT<<2) - 1'b1 :
(timings == TIMINGS_S128)?
(machine == MACHINE_S48)?
hc0 == (H_TOTAL_S48<<2) - 1'b1 :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
hc0 == (H_TOTAL_S128<<2) - 1'b1 :
// 48K
hc0 == (H_TOTAL_S48<<2) - 1'b1 ;
// Pentagon
hc0 == (H_TOTAL_PENT<<2) - 1'b1 ;
wire vc_reset =
(timings == TIMINGS_PENT)?
vc == V_TOTAL_PENT - 1'b1 :
(timings == TIMINGS_S128)?
(machine == MACHINE_S48)?
vc == V_TOTAL_S48 - 1'b1:
(machine == MACHINE_S128 || machine == MACHINE_S3)?
vc == V_TOTAL_S128 - 1'b1 :
// 48K
vc == V_TOTAL_S48 - 1'b1;
// Pentagon
vc == V_TOTAL_PENT - 1'b1 ;
wire hsync0 =
(timings == TIMINGS_PENT)?
(hc >= (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT)) &&
(hc < (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT + H_SYNC_PENT)) :
(timings == TIMINGS_S128)?
(machine == MACHINE_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)) :
// 48K
(hc >= (H_AREA + H_RBORDER_S48 + H_BLANK1_S48)) &&
(hc < (H_AREA + H_RBORDER_S48 + H_BLANK1_S48 + H_SYNC_S48)) ;
// Pentagon
(hc >= (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT)) &&
(hc < (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT + H_SYNC_PENT)) ;
wire vsync0 =
(timings == TIMINGS_PENT)?
(vc >= (V_AREA + V_BBORDER_PENT)) && (vc < (V_AREA + V_BBORDER_PENT + V_SYNC_PENT)) :
(timings == TIMINGS_S128)?
(machine == MACHINE_S48)?
(vc >= (V_AREA + V_BBORDER_S48)) && (vc < (V_AREA + V_BBORDER_S48 + V_SYNC_S48)) :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
(vc >= (V_AREA + V_BBORDER_S128)) && (vc < (V_AREA + V_BBORDER_S128 + V_SYNC_S128)) :
// 48K
(vc >= (V_AREA + V_BBORDER_S48)) && (vc < (V_AREA + V_BBORDER_S48 + V_SYNC_S48)) ;
// Pentagon
(vc >= (V_AREA + V_BBORDER_PENT)) && (vc < (V_AREA + V_BBORDER_PENT + V_SYNC_PENT)) ;
wire blank =
(timings == TIMINGS_PENT)?
((vc >= (V_AREA + V_BBORDER_PENT)) && (vc < (V_AREA + V_BBORDER_PENT + V_SYNC_PENT))) ||
((hc >= (H_AREA + H_RBORDER_PENT)) &&
(hc < (H_AREA + H_RBORDER_PENT + H_BLANK1_PENT + H_SYNC_PENT + H_BLANK2_PENT))) :
(timings == TIMINGS_S128)?
(machine == MACHINE_S48)?
((vc >= (V_AREA + V_BBORDER_S48)) && (vc < (V_AREA + V_BBORDER_S48 + V_SYNC_S48))) ||
((hc >= (H_AREA + H_RBORDER_S48)) &&
(hc < (H_AREA + H_RBORDER_S48 + H_BLANK1_S48 + H_SYNC_S48 + H_BLANK2_S48))) :
(machine == MACHINE_S128 || machine == MACHINE_S3)?
((vc >= (V_AREA + V_BBORDER_S128)) && (vc < (V_AREA + V_BBORDER_S128 + V_SYNC_S128))) ||
((hc >= (H_AREA + H_RBORDER_S128)) &&
(hc < (H_AREA + H_RBORDER_S128 + H_BLANK1_S128 + H_SYNC_S128 + H_BLANK2_S128))) :
// 48K
((vc >= (V_AREA + V_BBORDER_S48)) && (vc < (V_AREA + V_BBORDER_S48 + V_SYNC_S48))) ||
((hc >= (H_AREA + H_RBORDER_S48)) &&
(hc < (H_AREA + H_RBORDER_S48 + H_BLANK1_S48 + H_SYNC_S48 + H_BLANK2_S48))) ;
// Pentagon
((vc >= (V_AREA + V_BBORDER_PENT)) && (vc < (V_AREA + V_BBORDER_PENT + V_SYNC_PENT))) ||
((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
@ -166,30 +169,61 @@ always @(posedge clk28 or negedge rst_n) begin
blink_cnt <= blink_cnt + 1'b1;
end
reg hsync0_delayed;
always @(posedge clk28)
hsync0_delayed <= hsync0;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
even_line <= 0;
else if (hsync0 && !hsync0_delayed)
even_line <= ~even_line;
end
wire [7:0] attr_border = {2'b00, border[2:0], 3'b000};
reg [7:0] bitmap, attr, bitmap_next;
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'b10001;
reg [7:0] vaddr;
reg [7:3] haddr;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
vaddr <= 0;
haddr <= 0;
end
else if (next_addr) begin
vaddr <= vc[7:0];
haddr <= hc[7:3];
end
end
reg loading;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n)
loading <= 0;
else
loading <= (vc < V_AREA) && (hc0 > 15) && (hc0 < (H_AREA<<2) + 17);
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 fetch_step;
wire fetch_bitmap = fetch && fetch_step == 1'd1;
wire fetch_attr = fetch && fetch_step == 1'd0;
wire fetch_bitmap = fetch && fetch_step == 2'd0;
wire fetch_attr = fetch && fetch_step == 2'd1;
assign fetch_next = loading && fetch_allow;
assign addr = fetch_bitmap?
{ 2'b10, vc[7:6], vc[2:0], vc[5:3], hc[7:3] } :
{ 5'b10110, vc[7:3], hc[7:3] };
reg [7:0] up_ink0, up_paper0;
{ 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 = { attr_next[7:6], 1'b0, attr_next[2:0] };
assign up_paper_addr = { attr_next[7:6], 1'b1, attr_next[5:3] };
assign loading = (vc < V_AREA) && (hc < H_AREA || hc0_reset);
wire screen_show = (vc < V_AREA) && (hc0 >= (SCREEN_DELAY<<2) - 2) && (hc0 < ((H_AREA + SCREEN_DELAY)<<2) - 2);
wire screen_update = vc < V_AREA && hc <= H_AREA && hc != 0 && hc0[4:0] == 5'b11110;
wire border_update = !screen_show && ((timings == TIMINGS_PENT && ck7) || hc0[4:0] == 5'b11110);
wire bitmap_shift = hc0[1:0] == 2'b10;
assign fetch_next = loading && fetch_allow;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
fetch <= 0;
@ -198,12 +232,14 @@ always @(posedge clk28 or negedge rst_n) begin
bitmap <= 0;
attr_next <= 0;
bitmap_next <= 0;
up_ink0 <= 0;
up_paper0 <= 0;
end
else begin
if (ck14) begin
if (fetch)
fetch_step <= fetch_step + 1'b1;
fetch <= fetch_next;
fetch <= fetch_allow;
if (fetch_attr)
attr_next <= fetch_data;
@ -211,12 +247,14 @@ always @(posedge clk28 or negedge rst_n) begin
attr_next <= attr_border;
if (fetch_bitmap)
bitmap_next <= fetch_data;
else if (!loading)
bitmap_next <= 0;
end
if (border_update)
attr <= attr_border;
else if (screen_update)
if (screen_show && screen_update)
attr <= attr_next;
else if (!screen_show && border_update)
attr <= attr_border;
if (screen_update)
bitmap <= bitmap_next;
@ -225,12 +263,24 @@ always @(posedge clk28 or negedge rst_n) begin
if (screen_update)
up_ink0 <= up_ink;
if (screen_update || (!screen_show && !loading))
if (screen_update)
up_paper0 <= up_paper;
end
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_data =
port_ff_attr? attr_next :
port_ff_bitmap? bitmap_next :
8'hFF;
assign contention = (vc < V_AREA) && (hc < H_AREA) && (hc[2] || hc[3]);
/* RGBS generation */
wire pixel = bitmap[7];
always @(posedge clk28) begin
@ -239,14 +289,16 @@ always @(posedge clk28) begin
else if (up_en) begin
g = pixel? up_ink0[7:5] : up_paper0[7:5];
r = pixel? up_ink0[4:2] : up_paper0[4:2];
b[2:1] = pixel? up_ink0[1:0] : up_paper0[1:0];
b[0] = |b[2:1];
b = pixel? up_ink0[1:0] : up_paper0[1:0];
end
else begin
{g[2], r[2], b[2]} = (pixel ^ (attr[7] & blink))? attr[2:0] : attr[5:3];
{g[1], r[1], b[1]} = {g[2] & attr[6], r[2] & attr[6], b[2] & attr[6]};
{g[0], r[0], b[0]} = {g[2], r[2], b[2]};
{g[2], r[2], b[1]} = (pixel ^ (attr[7] & blink))? attr[2:0] : attr[5:3];
{g[1], r[1], b[0]} = {g[2] & attr[6], r[2] & attr[6], b[1] & attr[6]};
{g[0], r[0]} = {g[2], r[2]};
end
end
always @(posedge clk28) begin
csync = ~(vsync0 ^ hsync0);
vsync = ~vsync0;
hsync = ~hsync0;

View File

@ -48,11 +48,9 @@ pll pll0(.inclk0(clk_in), .c0(clk40), .c1(clk20), .locked(rst_n));
/* SHARED DEFINITIONS */
timings_t timings;
machine_t machine;
turbo_t turbo;
rammode_t ram_mode;
reg pause = 0;
wire ps2_key_pause, ps2_key_reset;
wire ps2_key_reset, ps2_key_pause;
wire [2:0] border;
wire magic_reboot, magic_beeper;
wire up_active;
@ -102,30 +100,25 @@ always @(posedge clk28) begin
usrrst_n <= (!rst_n || ps2_key_reset || magic_reboot)? 1'b0 : 1'b1;
end
/* PAUSE */
always @(posedge clk28) begin
if (n_int == 1'b0 && bus.rfsh)
pause <= ps2_key_pause;
end
/* SCREEN CONTROLLER */
wire blink;
wire [2:0] screen_border = {border[2] ^ ~sd_cs, border[1] ^ magic_beeper, border[0] ^ (pause & blink)};
wire [2:0] r, g, b;
wire [2:0] screen_border = {border[2] ^ ~sd_cs, border[1] ^ magic_beeper, border[0]};
wire [2:0] r, g;
wire [1:0] b;
wire hsync;
wire screen_contention, port_ff_active;
wire [14:0] screen_addr;
wire [5:0] up_ink_addr, up_paper_addr;
wire [7:0] up_ink, up_paper;
wire screen_loading;
wire [14:0] screen_addr;
wire [7:0] attr_next;
wire [8:0] vc, hc;
wire [7:0] port_ff_data;
wire clk14, clk7, clk35, ck14, ck7, ck35;
screen screen0(
.rst_n(rst_n),
.rst_n(usrrst_n),
.clk28(clk28),
.timings(timings),
.machine(machine),
.border(screen_border),
.r(r),
@ -141,16 +134,17 @@ screen screen0(
.fetch_next(screen_fetch_next),
.fetch_data(bus.d),
.loading(screen_loading),
.blink(blink),
.attr_next(attr_next),
.up_en(up_active),
.up_ink_addr(up_ink_addr),
.up_paper_addr(up_paper_addr),
.up_ink(up_ink),
.up_paper(up_paper),
.contention(screen_contention),
.blink(blink),
.port_ff_active(port_ff_active),
.port_ff_data(port_ff_data),
.vc_out(vc),
.hc_out(hc),
.clk14(clk14),
@ -210,16 +204,17 @@ cpucontrol cpucontrol0(
.clk14(clk14),
.clk7(clk7),
.clk35(clk35),
.ck14(ck14),
.ck7(ck7),
.bus(bus),
.vc(vc),
.hc(hc),
.rampage128(rampage128),
.screen_loading(screen_loading),
.machine(machine),
.screen_contention(screen_contention),
.turbo(turbo),
.timings(timings),
.pause(pause),
.ext_wait_cycle(div_wait || up_active),
.init_done_in(init_done),
@ -234,32 +229,39 @@ cpucontrol cpucontrol0(
/* MAGIC */
wire div_automap;
wire [7:0] magic_dout;
wire magic_dout_active;
wire magic_mode, magic_map;
wire divmmc_en, joy_sinclair, rom_plus3, rom_alt48, mix_acb, mix_mono, up_en, covox_en, sd_en;
wire joy_sinclair, up_en, covox_en, sd_en;
panning_t panning;
divmmc_t divmmc_en;
magic magic0(
.rst_n(usrrst_n),
.rst_n(n_rstcpu),
.clk28(clk28),
.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),
.sd_cd(sd_cd),
.div_automap(div_automap),
.magic_mode(magic_mode),
.magic_map(magic_map),
.magic_reboot(magic_reboot),
.magic_beeper(magic_beeper),
.timings(timings),
.machine(machine),
.turbo(turbo),
.ram_mode(ram_mode),
.joy_sinclair(joy_sinclair),
.rom_plus3(rom_plus3),
.rom_alt48(rom_alt48),
.mix_acb(mix_acb),
.mix_mono(mix_mono),
.panning(panning),
.divmmc_en(divmmc_en),
.ulaplus_en(up_en),
.covox_en(covox_en),
@ -273,31 +275,26 @@ wire ports_dout_active;
wire beeper, tape_out;
wire screenpage;
wire rompage128;
wire [3:0] rampage_ext;
wire [2:0] rampage_ext;
wire [2:0] port_1ffd;
wire port_dffd_d3;
wire port_dffd_d4;
wire [4:0] port_dffd;
ports ports0 (
.rst_n(usrrst_n),
.rst_n(n_rstcpu),
.clk28(clk28),
.bus(bus),
.d_out(ports_dout),
.d_out_active(ports_dout_active),
.en_128k(ram_mode == RAM_512 || ram_mode == RAM_128),
.en_plus3(rom_plus3),
.en_profi(ram_mode == RAM_512),
.en_kempston(!joy_sinclair),
.en_sinclair(joy_sinclair),
.timings(timings),
.clkcpu_ck(clkcpu_ck),
.screen_loading(screen_loading),
.attr_next(attr_next),
.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_button(ps2_key_magic),
.magic_map(magic_map),
.tape_in(sd_miso_tape_in),
.tape_out(tape_out),
@ -308,8 +305,7 @@ ports ports0 (
.rampage128(rampage128),
.rampage_ext(rampage_ext),
.port_1ffd(port_1ffd),
.port_dffd_d3(port_dffd_d3),
.port_dffd_d4(port_dffd_d4)
.port_dffd(port_dffd)
);
@ -318,7 +314,7 @@ 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(usrrst_n),
.rst_n(n_rstcpu),
.clk28(clk28),
.ck35(ck35),
.en(1'b1),
@ -328,8 +324,6 @@ turbosound turbosound0(
.d_out(turbosound_dout),
.d_out_active(turbosound_dout_active),
.pause(pause),
.ay_a0(ay_a0),
.ay_b0(ay_b0),
.ay_c0(ay_c0),
@ -355,10 +349,9 @@ soundrive soundrive0(
.ch_r1(soundrive_r1)
);
/* SOUND MIXER */
mixer mixer0(
.rst_n(rst_n),
.rst_n(usrrst_n),
.clk28(clk28),
.beeper(beeper ^ magic_beeper),
@ -375,8 +368,8 @@ mixer mixer0(
.sd_r0(soundrive_r0),
.sd_r1(soundrive_r1),
.ay_acb(mix_acb),
.mono(mix_mono),
.ay_acb(panning == PANNING_ABC),
.mono(panning == PANNING_MONO),
.dac_l(snd_l),
.dac_r(snd_r)
@ -389,12 +382,12 @@ wire [7:0] div_dout;
wire [3:0] div_page;
wire sd_mosi0;
divmmc divmmc0(
.rst_n(usrrst_n),
.rst_n(n_rstcpu),
.clk28(clk28),
.ck14(ck14),
.ck7(ck7),
.en(divmmc_en),
.en_hooks(~sd_cd),
.en(divmmc_en == DIVMMC_ON || divmmc_en == DIVMMC_NOOS),
.en_hooks(divmmc_en == DIVMMC_ON),
.bus(bus),
.d_out(div_dout),
@ -405,15 +398,16 @@ divmmc divmmc0(
.sd_sck(sd_sck),
.sd_cs(sd_cs),
.rammap(port_dffd_d4 | port_1ffd[0]),
.rammap(port_dffd[4] | port_1ffd[0]),
.magic_mode(magic_mode),
.magic_map(magic_map),
.div_page(div_page),
.div_map(div_map),
.div_ram(div_ram),
.div_ramwr_mask(div_ramwr_mask),
.div_wait(div_wait)
.page(div_page),
.map(div_map),
.automap(div_automap),
.ram(div_ram),
.ramwr_mask(div_ramwr_mask),
.cpuwait(div_wait)
);
assign sd_mosi = (~sd_cd)? sd_mosi0 : tape_out;
@ -422,7 +416,7 @@ assign sd_mosi = (~sd_cd)? sd_mosi0 : tape_out;
wire up_dout_active;
wire [7:0] up_dout;
ulaplus ulaplus0(
.rst_n(usrrst_n),
.rst_n(n_rstcpu),
.clk28(clk28),
.en(up_en),
@ -484,77 +478,46 @@ asmi asmi0(
/* MEMORY CONTROLLER */
reg romreq, ramreq, ramreq_wr;
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
romreq = 1'b0;
ramreq = 1'b0;
ramreq_wr = 1'b0;
end
else begin
romreq = bus.mreq && !bus.rfsh && bus.a[14] == 0 && bus.a[15] == 0 &&
(magic_map || (!div_ram && div_map) || (!div_ram && !port_dffd_d4 && !port_1ffd[0]));
ramreq = bus.mreq && !bus.rfsh && !romreq;
ramreq_wr = ramreq && bus.wr && div_ramwr_mask == 0;
end
end
memcontrol memcontrol0(
.rst_n(rst_n),
.clk28(clk28),
.bus(bus),
.va(va),
.vd(vd),
.n_vrd(n_vrd),
.n_vwr(n_vwr),
assign n_vrd = ((((ramreq || romreq) && 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;
.machine(machine),
.screenpage(screenpage),
.screen_fetch(screen_fetch),
.snow(snow),
.screen_addr(screen_addr),
.magic_map(magic_map),
.rampage128(rampage128),
.rompage128(rompage128),
.port_1ffd(port_1ffd),
.port_dffd(port_dffd),
.rampage_ext(rampage_ext),
.divmmc_en(divmmc_en != DIVMMC_OFF),
.div_ram(div_ram),
.div_map(div_map),
.div_ramwr_mask(div_ramwr_mask),
.div_page(div_page),
/* VA[18:13] map
* 00xxxx 128Kb 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 [18:13] ram_a;
always @(posedge clk28) begin
ram_a <=
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[14] & ~bus.a[15] & bus.a[13]? {2'b01, div_page} :
div_map & ~bus.a[14] & ~bus.a[15]? {2'b01, 4'b0011} :
port_dffd_d3 & bus.a[15]? {2'b11, bus.a[14], bus.a[15], bus.a[14], bus.a[13]} :
port_dffd_d3 & 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]} :
(port_1ffd == 3'b111)? {2'b11, ~(bus.a[15] & bus.a[14]), (bus.a[15] | bus.a[14]), bus.a[14]} :
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
reg [16:14] rom_a;
always @(posedge clk28) begin
rom_a <=
magic_map? 3'd2 :
div_map? 3'd3 :
(rom_plus3 && port_1ffd[2] == 1'b0 && rompage128 == 1'b0)? 3'd4 :
(rom_plus3 && port_1ffd[2] == 1'b0 && rompage128 == 1'b1)? 3'd5 :
(rom_plus3 && port_1ffd[2] == 1'b1 && rompage128 == 1'b0)? 3'd6 :
(rompage128 == 1'b1 && rom_alt48 == 1'b1)? 3'd7 :
(rompage128 == 1'b1)? 3'd1 :
3'd0;
end
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} :
romreq? {2'b00, rom_a[16:14], bus.a[13], {13{1'bz}}} :
{ram_a[18:13], {13{1'bz}}};
assign vd[7:0] =
~n_vrd? {8{1'bz}} :
rom2ram_ram_wren? rom2ram_dataout :
up_dout_active? up_dout :
div_dout_active? div_dout :
turbosound_dout_active? turbosound_dout :
ports_dout_active? ports_dout :
~n_wr? {8{1'bz}} :
8'hFF;
.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

View File

@ -166,6 +166,7 @@ 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 VERILOG_FILE ../rtl/chroma_gen.v
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/turbosound.sv
set_global_assignment -name VHDL_FILE ../rtl/ym2149.vhd

View File

@ -5,6 +5,7 @@ SRC_T80=./t80/t80n_pack.vhd ./t80/t80n.vhd ./t80/t80n_alu.vhd ./t80/t80n_mcode.v
all: testbench_zx_ula
testbench_zx_ula: IVFLAGS+=-I./az80/ -I./t80/ -I../rtl/
testbench_zx_ula: VLOGFLAGS+=+define+TESTBENCH
testbench_zx_ula: testbench_zx_ula.v ../rtl/common.sv $(wildcard stubs/*.v ../rtl/*.vhd ../rtl/*.v ../rtl/*.sv)
testbench_zx_ula: ${SRC_T80}
testbench_zx_ula: rom.mem

View File

@ -1,26 +1,19 @@
DEVICE ZXSPECTRUM48
ORG #0000
ORG #8000 // mapped #0000
Start:
nop
jp Main
jp #1000
ORG #0038
ORG #8038
Int1:
jp #1ff8
ORG #00FF
DB #38
reti
ORG #0066
ORG #8066
Nmi:
jp #1ffa
push af
ld a, #08
out (#ff), a
pop af
retn
ORG #1000
ORG #9000
Main:
im 2
ei
@ -46,15 +39,8 @@ Main:
jp #1fff
Loop:
halt
jp Loop
jr Loop
ORG #1FF8 // DivROM exit vector
reti
ORG #1FFA // DivROM exit vector
retn
ORG #1FFF // DivROM exit vector
nop
jp #3D00
ORG #C000 // mapped #0000
DivROM_Start:

View File

@ -1,4 +1,4 @@
`timescale 100ps/10ps
`timescale 1ns/100ps
module testbench_zx_ula();
reg rst_n;
@ -6,7 +6,8 @@ reg clk28;
/* CPU */
wire rstcpu_n;
wire clkcpu;
wire n_rstcpu;
wire [15:0] a_cpu, a_cpu_cpu;
wire [7:0] d_cpu_o, d_cpu_i;
wire n_rd, n_rd_cpu;
@ -19,7 +20,7 @@ wire n_int;
wire n_nmi;
T80na cpu1(
.RESET_n(rstcpu_n),
.RESET_n(n_rstcpu),
.CLK_n(clkcpu),
.WAIT_n(1'b1),
.INT_n(n_int),
@ -72,7 +73,7 @@ wire sd_mosi_miso;
zx_ula zx_ula1(
.clk_in(clk28),
.clkcpu(clkcpu),
.n_rstcpu(rstcpu_n),
.n_rstcpu(n_rstcpu),
.a(a_cpu[15:13]),
.vd(vd),
.va(va),
@ -138,51 +139,63 @@ assign d_cpu_i = vd;
// assign a_cpu = a_cpu_cpu;
/* CPU SIGNALS (Z84C0020 timings) */
assign #400 n_rd = n_rd_cpu; //TdCf(RDf)
assign #400 n_wr = n_wr_cpu; //TdCf(WRf)
assign #400 n_iorq = n_iorq_cpu; //TdCr(IORQf)
assign #400 n_mreq = n_mreq_cpu; //TdCf(MREQf)
assign #450 n_m1 = n_m1_cpu; //TdCr(M1f)
assign #600 n_rfsh = n_rfsh_cpu; //TdCr(RFSHf)
assign #570 a_cpu = a_cpu_cpu; //TdCr(A)
assign #40 n_rd = n_rd_cpu; //TdCf(RDf)
assign #40 n_wr = n_wr_cpu; //TdCf(WRf)
assign #40 n_iorq = n_iorq_cpu; //TdCr(IORQf)
assign #40 n_mreq = n_mreq_cpu; //TdCf(MREQf)
assign #45 n_m1 = n_m1_cpu; //TdCr(M1f)
assign #60 n_rfsh = n_rfsh_cpu; //TdCr(RFSHf)
assign #57 a_cpu = a_cpu_cpu; //TdCr(A)
/* CPU SIGNALS (Z84C0008 timings) */
// assign #700 n_rd = n_rd_cpu; //TdCf(RDf)
// assign #600 n_wr = n_wr_cpu; //TdCf(WRf)
// assign #550 n_iorq = n_iorq_cpu; //TdCr(IORQf)
// assign #600 n_mreq = n_mreq_cpu; //TdCf(MREQf)
// assign #700 n_m1 = n_m1_cpu; //TdCr(M1f)
// assign #950 n_rfsh = n_rfsh_cpu; //TdCr(RFSHf)
// assign #800 a_cpu = a_cpu_cpu; //TdCr(A)
//assign #70 n_rd = n_rd_cpu; //TdCf(RDf)
//assign #60 n_wr = n_wr_cpu; //TdCf(WRf)
//assign #55 n_iorq = n_iorq_cpu; //TdCr(IORQf)
//assign #60 n_mreq = n_mreq_cpu; //TdCf(MREQf)
//assign #70 n_m1 = n_m1_cpu; //TdCr(M1f)
//assign #95 n_rfsh = n_rfsh_cpu; //TdCr(RFSHf)
//assign #80 a_cpu = a_cpu_cpu; //TdCr(A)
/* CPU SIGNALS (Z84C0004 timings) */
// assign #850 n_rd = n_rd_cpu; //TdCf(RDf)
// assign #800 n_wr = n_wr_cpu; //TdCf(WRf)
// assign #750 n_iorq = n_iorq_cpu; //TdCr(IORQf)
// assign #850 n_mreq = n_mreq_cpu; //TdCf(MREQf)
// assign #1000 n_m1 = n_m1_cpu; //TdCr(M1f)
// assign #1300 n_rfsh = n_rfsh_cpu; //TdCr(RFSHf)
// assign #1100 a_cpu = a_cpu_cpu; //TdCr(A)
// assign #85 n_rd = n_rd_cpu; //TdCf(RDf)
// assign #80 n_wr = n_wr_cpu; //TdCf(WRf)
// assign #75 n_iorq = n_iorq_cpu; //TdCr(IORQf)
// assign #85 n_mreq = n_mreq_cpu; //TdCf(MREQf)
// assign #100 n_m1 = n_m1_cpu; //TdCr(M1f)
// assign #130 n_rfsh = n_rfsh_cpu; //TdCr(RFSHf)
// assign #110 a_cpu = a_cpu_cpu; //TdCr(A)
/* SIMULATION SIGNALS */
initial begin
n_magic = 1;
#50000
// n_magic = 0;
#50000
n_magic = 1;
end
/* CLOCKS & RESET */
initial begin
rst_n = 0;
#3000 rst_n = 1;
#300 rst_n = 1;
end
always begin
clk28 = 0;
#178 clk28 = 1;
#179;
#17.8 clk28 = 1;
#17.9;
end
/* TESTBENCH CONTROL */
initial begin
$dumpfile("testbench_zx_ula.vcd");
$dumpvars();
#5000000 $finish;
// #200000000 $finish;
$dumpvars;
#500_000 $finish;
// #21_000_000 $finish;
// #41_000_000 $finish;
end

View File

@ -1,12 +1,23 @@
all:
cat 128-0.rom \
128-1.rom \
../rom_src/main.bin \
ESXMMC.BIN ESXMMC.BIN \
dvmen3e0.rom \
dvmen3e1.rom \
dvmen3e2.rom \
opense.rom \
>sizif.bin
objcopy --input-target=binary --output-target=ihex sizif.bin sizif.hex
rm sizif.bin
# Each bank = 16Kb
bank00=128-0.rom # 0x00000
bank01=128-1.rom # 0x04000
bank02=../rom_src/main.bin # 0x08000
bank03=ESXMMC.BIN ESXMMC.BIN # 0x0C000
bank04=dvmen3e0.rom # 0x10000
bank05=dvmen3e1.rom # 0x14000
bank06=dvmen3e2.rom # 0x18000
bank07=zero8k.bin zero8k.bin # 0x1C000
sizif.rom: ${bank00} ${bank01} ${bank02} ${bank03} ${bank04} ${bank05} ${bank06} ${bank07}
%.rom:
cat $+ > $@
%.hex: %.rom
objcopy --input-target=binary --output-target=ihex $< $@
.DEFAULT_GOAL := all
all: sizif.hex
clean:
rm -f sizif.rom sizif.hex

Binary file not shown.

BIN
rom/zero8k.bin Normal file

Binary file not shown.

View File

@ -1,6 +1,7 @@
export PATH:=/cygdrive/c/Hwdev/sjasmplus/:/cygdrive/c/Dev/srec/:${PATH}
SJOPTS='-DSIZIFXXS'
REV=D
SJOPTS=-DSIZIFXXS
.PHONY: all clean .FORCE
.FORCE:

View File

@ -1,35 +1,45 @@
POWERON_DELAY EQU 40 ; *20ms, for ps/2 keyboard initialization
MENU_ENTER_DELAY EQU 40 ; 400ms
MENU_LEAVE_DELAY EQU 2 ; 20ms
MENU_HOLDCHECK_DELAY EQU 7
MENU_WIDTH EQU 20
MENU_HEIGHT EQU MENU_ITEMS+2
MENU_X EQU (32-MENU_WIDTH)/2
MENU_Y EQU (24-MENU_HEIGHT)/2
MENU_HEADER_ATTR EQU #47
MENU_BODY_ATTR EQU #78
MENU_SELECT_ATTR EQU #68
INPUT_REPEAT EQU 2
INPUT_REPEAT_FIRST EQU 11
INPUT_BEEP_DELAY EQU 255
MENU_WIDTH EQU 20
MENU_X EQU (32-MENU_WIDTH)/2
MENU_HEADER_ATTR EQU #47
MENU_BODY_ATTR EQU #78
MENU_SELECT_ATTR EQU #68
PAUSE_WIDTH EQU 7
PAUSE_HEIGHT EQU 3 ; see pause.asm to really change
PAUSE_X EQU (32-PAUSE_WIDTH)/2
PAUSE_Y EQU (24-PAUSE_HEIGHT)/2
PAUSE_BODY_ATTR EQU #00
PAUSE_TEXT_ATTR EQU #C7
STRUCT CFG_T
_reserv0 DB 0
_reserv1 DB 0
timings DB 0
machine DB 3
clock DB 0
panning DB 0
plus3 DB 0
panning DB 1
custom_rom DB 0
rom48 DB 0
joystick DB 0
ram DB 0
divmmc DB 1
_reserv2 DB 0
divmmc DB 2
ulaplus DB 1
dac DB 3
ENDS
STRUCT CFGEXT_T
tsfm DB 1
saa DB 1
gs DB 1
ENDS
CFG_DEFAULT CFG_T
CFGEXT_DEFAULT CFGEXT_T

View File

@ -125,7 +125,7 @@ print_char:
print_string:
ld a, (hl) ; A = *string
or a ; if (A == 0) - exit
jr z, .return ; ...
ret z ; ...
push bc
push hl
call print_char
@ -134,7 +134,6 @@ print_string:
inc hl ; string++
inc c ; column++
jr print_string
.return:
ret
@ -151,7 +150,7 @@ print_string:
print_string_rev:
ld a, (hl) ; A = *string
or a ; if (A == 0) - exit
jr z, .return ; ...
ret z ; ...
push bc
push hl
call print_char
@ -160,7 +159,6 @@ print_string_rev:
dec hl ; string--
dec c ; column--
jr print_string_rev
.return:
ret
@ -280,22 +278,23 @@ draw_menu:
push hl ; IX = menu first item addr
pop ix ; ...
.line_loop:
ld l, (ix+0) ; HL = menu_t.textaddr
ld h, (ix+1) ; ...
ld l, (ix+MENUENTRY_T.text_addr+0) ; HL = menuentry_t.textaddr
ld h, (ix+MENUENTRY_T.text_addr+1) ; ...
ld a, h ; if (HL == 0) - exit
or l ; ...
jr z, .return ; ...
push bc
ret z ; ...
push de
push bc
push ix
call print_string ; print menu item text
pop ix
pop de
pop bc
pop de
dec sp ; DE will be restored in .skip_val
dec sp ; ...
.print_val:
push de ; will be restored in .skip_val
ld l, (ix+2) ; HL = menu_t.value_cb_addr
ld h, (ix+3) ; ...
ld l, (ix+MENUENTRY_T.value_cb_addr+0) ; HL = menuentry_t.value_cb_addr
ld h, (ix+MENUENTRY_T.value_cb_addr+1) ; ...
ld a, h ; if (HL == 0) - skip value print
or l ; ...
jr z, .skip_val ; ...
@ -313,7 +312,7 @@ draw_menu:
ld a, b ; row += 8
add a, 8 ; ...
ld b, a ; ...
ld de, MENU_T ; IX = IX + sizeof(menu_t)
ld de, MENUENTRY_T ; IX = IX + sizeof(menuentry_t)
add ix, de ; ...
pop de ; restore E - columns
jr .line_loop
@ -332,17 +331,16 @@ draw_menu:
; OUT - B - garbage
; OUT - E - garbage
; OUT - HL - garbage
draw_menu_item_line:
draw_attribute_line:
call coords_to_attribute_address ; HL = attribute address
.loop:
ld a, e ; if (columns == 0) - exit
or a ; ...
jr z, .return ; ...
ret z ; ...
ld (hl), d ; write attribute
inc hl ; column++
dec e ; columns--
jr .loop
.return:
ret

View File

@ -721,13 +721,13 @@ font_latin_small_letter_g:
DG --###---
font_latin_small_letter_h:
DG --------
DG -#------
DG -#------
DG -####---
DG -#---#--
DG -#---#--
DG -#---#--
DG -#---#--
DG --------
font_latin_small_letter_i:

View File

@ -14,7 +14,7 @@ input_read:
in a, (#1f) ; ...
bit 7, a ; detect presence by 7th bit
jr nz, .enter ; ...
and #1f ; mask useless bits
and #3f ; mask useless bits
ld b, a ; ...
.enter:
ld a, #bf ; read keys
@ -85,9 +85,16 @@ input_read:
ret
.sinclair_09876_6:
bit 4, a ; handle 6 (LEFT) key
jr nz, .return ; ...
jr nz, .sinclair_ssmnb ; ...
set 1, b ; ...
ret
.sinclair_ssmnb:
ld a, #7f ; read keys
in a, (#fe) ; ...
bit 2, a ; handle M (EXIT) key (in Sinclair mode sega C button is mapped to M)
jr nz, .return ; ...
set 5, b ; ...
ret
.space_break:
ld a, #7f ; read keys
in a, (#fe) ; ...
@ -128,7 +135,7 @@ input_read:
; OUT - BC - garbage
input_beep:
or a
jr z, .return
ret z
IFDEF TEST_BUILD
ld a, #10 ; blink border
out (#fe), a ; ...
@ -142,7 +149,6 @@ input_beep:
ld a, 1 ; blink border back
ld bc, #01ff ; ...
out (c), a ; ...
.return:
ret

View File

@ -4,11 +4,15 @@
app_begin:
; Startup handler
ORG #0000
ex de, hl ; EB opcode used by CPLD to determine magic ROM presence
ex de, hl ; ...
jp startup_handler
DB 0,"Sizif Magic ROM",0
; NMI handler
ORG #0066
ex de, hl ; EB opcode used by CPLD to determine magic ROM presence
ex de, hl ; ...
jp nmi_handler
; INT IM1 handler
@ -35,8 +39,23 @@ startup_handler:
ld ix, #5800 ; draw 4 rygb boxes on left top corner to indicate boot
ld (ix+0), #D2 ; r
ld (ix+1), #F6 ; y
call init_config
call check_initialized
jr z, .warm_boot
im 1 ; wait for ps/2 keyboard ready
ld b, POWERON_DELAY ; ...
.loop ; ...
ei ; ...
halt ; ...
djnz .loop ; ...
call init_default_config
call detect_sd_card
call detect_ext_board
call check_custom_rom
.warm_boot:
call load_config
call init_cpld
call save_initialized
call mute_saa1099 ; saa1099 does not have reset pin
ld (ix+2), #E4 ; g
ld (ix+3), #C9 ; b
ld hl, 0
@ -55,18 +74,25 @@ nmi_handler:
ld (var_magic_enter_cnt), a
ld (var_magic_leave_cnt), a
.loop:
call check_magic_delay
call check_magic_hold ; A == 1 if we are entering menu, A == 2 if we are leaving to...
call check_entering_pause ; A[1] == 1 if pause button is pressed
bit 1, a ; ...
jp nz, enter_pause ; ...
call delay_10ms ;
call check_entering_menu ; A == 1 if we are entering menu, A == 2 if we are leaving to...
bit 0, a ; ...default nmi handler, A == 0 otherwise
jp nz, main ; ...
jp nz, enter_menu ; ...
bit 1, a ; ...
jr z, .loop ; ...
.leave:
xor a ; disable border
ld bc, #01ff ; ...
out (c), a ; ...
ld hl, #0066 ; jump to default nmi handler
jp exit_with_jp ; ...
ld bc, #ffff ; if divmmc paged - just do retn
in a, (c) ; ...
bit 3, a ; ...
jr nz, exit_with_ret ; ...
ld hl, #0066 ; otherwise jump to default nmi handler
jr exit_with_jp ; ...
; IN - HL - jump address
@ -90,40 +116,43 @@ exit_with_ret:
jp Exit_vector-1
init_config:
ld hl, cfg_initialized ; if (cfg_initialized == "magic word") {restore cfg} else {default cfg}
check_initialized:
ld hl, cfg_initialized ; if (cfg_initialized == "magic word") Z = 0, else Z = 1
ld a, #B1 ; ...
cpi ; ... hl++
jr nz, .init_default ; ...
ret nz ; ...
ld a, #5B ; ...
cpi ; ... hl++
jr nz, .init_default ; ...
ret nz ; ...
ld a, #00 ; ...
cpi ; ... hl++
jr nz, .init_default ; ...
ret nz ; ...
ld a, #B5 ; ...
cpi ; ... hl++
jr nz, .init_default ; ...
jr .restore ; ...
.init_default:
ld bc, CFG_T ; cfg_saved = cfg_default
ld de, cfg_saved ; ...
ld hl, CFG_DEFAULT ; ...
ldir ; ...
.restore:
ld bc, CFG_T ; cfg = cfg_saved
ld de, cfg ; ...
ld hl, cfg_saved ; ...
ldir ; ...
.save_magic:
ret
save_initialized:
ld hl, #5BB1 ; cfg_initialized = "magic word"
ld (cfg_initialized+0), hl ; ...
ld hl, #B500 ; ...
ld (cfg_initialized+2), hl ; ...
ret
init_default_config:
ld bc, CFG_T+CFGEXT_T ; cfg_saved = cfg_default
ld de, cfg_saved ; ...
ld hl, CFG_DEFAULT ; ...
ldir ; ...
load_config:
ld bc, CFG_T+CFGEXT_T ; cfg = cfg_saved
ld de, cfg ; ...
ld hl, cfg_saved ; ...
ldir ; ...
ret ; ...
save_config:
ld bc, CFG_T ; cfg_saved = cfg
ld bc, CFG_T+CFGEXT_T ; cfg_saved = cfg
ld de, cfg_saved ; ...
ld hl, cfg ; ...
ldir ; ...
@ -131,22 +160,28 @@ save_config:
init_cpld:
.check_ram48k:
ld a, (cfg.ram) ; if ram == 48K - run basic48
cp 1 ; ...
jr nz, .check_plus3_disabled ; ...
.check_alt48rom:
ld a, (cfg.rom48) ; if alternative 48k rom enabled - disable 128 menu
or a ; ... this is required because 128 menu isn't compatible
jr z, .check_7ffd_disabled ; ... with currently used Looking Glass 48K rom
ld a, (cfg.machine) ; ... however +3e works with looking glass flawlessly
cp 2 ; ...
jr z, .check_7ffd_disabled ; ...
ld a, #10 ; ...
ld bc, #7ffd ; ...
out (c), a ; ...
ld a, #4 ; ...
ld bc, #1ffd ; ...
.check_7ffd_disabled:
ld a, (cfg.machine) ; if machine == 48 - set 7ffd rom to basic48
or a ; ... this is required for case when machine will be
jr nz, .check_1ffd_disabled ; ... changed later by magic menu - this prevents
ld a, #10 ; ... hang if user changes machine while basic48 active
ld bc, #7ffd ; ...
out (c), a ; ...
jr .do_load
.check_plus3_disabled:
ld a, (cfg.plus3) ; if plus3 disabled - set 1ffd rom to basic48
or a ; ... this is required for case when plus3 will be
jr nz, .do_load ; ... activated later by magic menu - this prevents
ld a, #4 ; ... hang if user activating plus3 while basic48 active
.check_1ffd_disabled:
ld a, (cfg.machine) ; if machine != +3 - set 1ffd rom to basic48
cp 2 ; ... this is required for case when +3 will be
jr z, .do_load ; ... activated later by magic menu - this prevents
ld a, #4 ; ... hang if user activate +3 while basic48 active
ld bc, #1ffd ; ...
out (c), a ; ...
.do_load:
@ -154,16 +189,120 @@ init_cpld:
ld c, #ff ;
ld hl, cfg+CFG_T-1 ; HL = &cfg[registers count-1]
otdr ; do { b--; out(bc, *hl); hl--; } while(b)
.do_load_ext: ; same for extension board
ld d, CFGEXT_T ; ...
ld b, #e1 ; ...
ld c, #ff ; ...
ld hl, cfgext ; ...
.do_load_ext_loop: ; ...
ld a, (hl) ; ...
out (c), a ; ...
inc hl ; ...
inc b ; ...
dec d ; ...
jr nz, .do_load_ext_loop ; ...
ret
detect_sd_card:
ld a, #ff ; read sd_cd state in bit 2 of #FFFF port
in a, (#ff) ; ...
bit 2, a ; check sd_cd == 0 (card is insert)
jr z, .is_insert ; yes?
.no_card:
xor a ; divmmc = OFF
ld (cfg_saved.divmmc), a ; ...
ret
.is_insert:
ld a, 1 ; divmmc = ON
ld (cfg_saved.divmmc), a ; ...
ret
; OUT - A = 1 if ext board present, 0 otherwise
; OUT - F - garbage
; OUT - BC - garbage
detect_ext_board:
ld b, #e0 ; read port #e0ff
ld c, #ff ; ...
in a, (c) ; ...
ld b, a ; if (result & 0xF0 != 0) - return
and #f0 ; ...
jr z, .detected ; ...
.not_detected:
xor a
ld (var_ext_presence), a
ret
.detected
ld a, 1
ld (var_ext_presence), a
xor a
bit 0, b ; check TSFM jumper
jr z, .cfg_tsfm
ld a, 1
.cfg_tsfm:
ld (cfgext_saved.tsfm), a
xor a
bit 1, b ; check SAA jumper
jr z, .cfg_saa
ld a, 1
.cfg_saa:
ld (cfgext_saved.saa), a
xor a
bit 2, b ; check GS jumper
jr z, .cfg_gs
ld a, 1
.cfg_gs:
ld (cfgext_saved.gs), a
ret
; Check if user holds 1/2/3/4 key on poweron. If true - boot with custom rom
check_custom_rom:
ld a, #f7 ; read 1-5 keys
in a, (#fe) ; ...
bit 0, a ; check key 1 pressed
jr z, .key1 ; ...
bit 1, a ; check key 2 pressed
jr z, .key2 ; ...
bit 2, a ; check key 3 pressed
jr z, .key3 ; ...
bit 3, a ; check key 4 pressed
jr z, .key4 ; ...
ret
.key1:
ld a, #80 ; rom #0
jr .reconfig
.key2:
ld a, #81 ; rom #1
jr .reconfig
.key3:
ld a, #82 ; rom #2
jr .reconfig
.key4:
ld a, #83 ; rom #3
.reconfig:
ld (cfg_saved.custom_rom), a ; set custom rom
xor a
ld (cfg_saved.divmmc), a ; disable divmmc
ld (cfg_saved.ulaplus), a ; disable ula+
ret
; OUT - A bit 1 if we are entering pause, 0 otherwise
check_entering_pause:
ld a, #ff ; read pause key state in bit 1 of #FFFF port
in a, (#ff) ; ...
ret
; OUT - A = 1 if we are entering menu, A = 2 if we are leaving menu, A = 0 otherwise
; OUT - F - garbage
check_magic_hold:
ld a, #ff ; read magic key state in bit 7 of #FE port
in a, (#fe) ; ...
bit 7, a ; check key is hold
jr z, .is_hold ; yes?
check_entering_menu:
ld a, #ff ; read magic key state in bit 0 of #FFFF port
in a, (#ff) ; ...
bit 0, a ; check key is hold
jr nz, .is_hold ; yes?
.not_hold:
ld a, (var_magic_leave_cnt) ; leave_counter++
inc a ; ...
@ -187,15 +326,21 @@ check_magic_hold:
; OUT - AF - garbage
; OUT - BC - garbage
check_magic_delay:
ld c, MENU_HOLDCHECK_DELAY
delay_10ms:
ld c, 7
ld a, (cfg.clock)
or a
jr z, .loop
ld c, MENU_HOLDCHECK_DELAY*2
ld c, 9
dec a
jr z, .loop
ld c, MENU_HOLDCHECK_DELAY*4
ld c, 11
dec a
jr z, .loop
ld c, 7*2
dec a
jr z, .loop
ld c, 7*4
.loop:
ld a, c
.loop_outer:
@ -223,14 +368,27 @@ get_im2_handler:
ret
save:
.mute_saa1099:
mute_saa1099:
ld bc, #ffff ; select saa register
ld a, #1c ; ...
out (c), a ; ...
ld b, #fe ; mute
xor a ; ...
out (c), a ; ...
ret
save:
.mute_gs:
ld a, (var_ext_presence) ; if (no_ext_pcb || gs_is_disabled) - skip gs
or a ; ...this is required to be compatible with DivIDE
jr z, .mute_saa1099 ; ...which uses same port #bb
ld a, (cfgext.gs) ; ...
or a ; ...
jr z, .mute_saa1099 ; ...
ld a, #fa ; send command Out zero_to_zero
out (#bb), a ; ...
.mute_saa1099:
call mute_saa1099
.save_ay:
ld hl, var_save_ay ; select first AY chip in TurboSound
ld a, #ff ; ...
@ -292,6 +450,15 @@ restore:
ld hl, var_save_ay ; select first AY chip in TurboSound
ld a, #ff ; ...
call .restore_ay_sub
.restore_gs:
ld a, (var_ext_presence) ; if (no_ext_pcb || gs_is_disabled) - skip gs
or a ; ...this is required to be compatible with DivIDE
jr z, .restore_ret ; ...which uses same port #bb
ld a, (cfgext.gs) ; ...
or a ; ...
jr z, .restore_ret ; ...
ld a, #60 ; send command Get Song Position
out (#bb), a ; ...
.restore_ret:
ret
@ -313,6 +480,16 @@ restore:
ret
enter_pause:
ld a, 1
ld (var_pause_flag), a
jr main
enter_menu:
xor a
ld (var_pause_flag), a
jr main
; Main program
main:
push de
@ -330,23 +507,45 @@ main:
ld (var_input_key), a
ld (var_input_key_last), a
ld (var_input_key_hold_timer), a
ld (var_pause_is_released), a
ld (var_menu_current_item), a
ld (var_menu_animate_cnt), a
call save
call menu_init
ld a, (var_pause_flag)
or a
jr z, .menu_init
.loop:
.pause_init:
call pause_init
.pause_loop:
ei
halt
call pause_process
ld a, (var_exit_flag)
or a
jr z, .pause_loop
jr .wait_for_keys_release
.menu_init:
call check_initialized
jr z, .menu_init1
call init_default_config
call detect_ext_board
call load_config
call save_initialized
.menu_init1:
call menu_init
.menu_loop:
ei
halt
call input_process ; B = 32 if exit key pressed
bit 5, b
jr nz, .wait_for_keys_release
call menu_process
ld a, (var_exit_flag)
or a
jr z, .loop
jr z, .menu_loop
.wait_for_keys_release:
ei
@ -355,6 +554,10 @@ main:
xor a
or b
jr nz, .wait_for_keys_release
ld a, #ff ; read magic/pause keys state
in a, (#ff) ; ...
and #03 ; ...
jr nz, .wait_for_keys_release
.leave:
call save_config
@ -389,6 +592,7 @@ main:
include config.asm
include draw.asm
include input.asm
include pause.asm
include menu.asm
include menu_structure.asm
include font.asm
@ -406,23 +610,7 @@ Readout_vector EQU #F008
ORG #D500
var_save_screen: .6912 DB 0
ORG #F020
var_save_ay: .32 DB 0
var_save_ulaplus: DB 0
var_sp_reg: DW 0
var_int_vector: DW 0
var_magic_enter_cnt: DB 0
var_magic_leave_cnt: DB 0
var_exit_flag: DB 0
var_exit_reboot: DB 0
var_input_key: DB 0
var_input_key_last: DB 0
var_input_key_hold_timer: DB 0
var_menu_current_item: DB 0
var_menu_animate_cnt: DB 0
cfg CFG_T
cfg_saved CFG_T
cfg_initialized: DB #B1, #5B, #00, #B5
include variables.asm
ORG #FFBE
Stack_top:

View File

@ -31,8 +31,9 @@ app_begin:
call menu_process
ld a, #01
out #fe, a
jr .loop
ld a, (var_exit_flag)
or a
jr z, .loop
save_variables:
ret
@ -42,24 +43,14 @@ includes:
include config.asm
include draw.asm
include input.asm
include pause.asm
include menu.asm
include menu_structure.asm
include font.asm
include strings.asm
variables:
var_exit_flag: DB 0
var_exit_reboot: DB 0
var_input_key: DB 0
var_input_key_last: DB 0
var_input_key_hold_timer: DB 0
var_menu_current_item: DB 0
var_menu_animate_cnt: DB 0
cfg CFG_T
cfg_saved CFG_T
cfg_initialized: DB #B1, #5B, #00, #B5
include variables.asm
DISPLAY "Application size: ",/D,$-app_begin
CSPECTMAP "main_test.map"

View File

@ -1,16 +1,29 @@
menu_init:
ld b, MENU_Y
ld bc, MENU_T ; if (ext board present) var_menu = menuext; else var_menu = menu;
ld de, var_menu ; ...
ld hl, menu ; ...
ld a, (var_ext_presence) ; ...
or a ; ...
jr z, .set_menu ; ...
ld hl, menuext ; ...
.set_menu: ; ...
ldir ; ...
ld ix, var_menu
ld b, (ix+MENU_T.y_row)
ld c, MENU_X
ld d, MENU_HEIGHT
ld d, (ix+MENU_T.height)
ld e, MENU_WIDTH
call draw_box
ld ix, var_menu
ld hl, str_sizif
ld b, MENU_Y*8
ld b, (ix+MENU_T.y_pixel)
ld c, MENU_X
call print_string
ld b, MENU_Y*8
ld ix, var_menu
ld b, (ix+MENU_T.y_pixel)
ld c, MENU_X+MENU_WIDTH-6
ld e, 0
call draw_logo
@ -49,7 +62,8 @@ menu_animate_logo:
ld a, 4 ; ...
sub e ; ...
ld e, a ; ...
ld b, MENU_Y*8 ; draw logo
ld ix, var_menu ;
ld b, (ix+MENU_T.y_pixel) ; draw logo
ld c, MENU_X+MENU_WIDTH-6 ; ...
call draw_logo ; ...
.return:
@ -60,7 +74,9 @@ menu_animate_logo:
; OUT - BC - garbage
; OUT - DE - garbage
; OUT - HL - garbage
; OUT - IX - garbage
menu_handle_updown:
ld ix, var_menu
call input_key_get ; A = current_pressed_key
.down: ;
bit 2, a ; down?
@ -68,11 +84,10 @@ menu_handle_updown:
ld a, (var_menu_current_item) ;
ld d, MENU_BODY_ATTR ; fill selected item with background color
call menu_draw_selected_item ; ...
cp a, MENU_ITEMS-1 ; if (current_item == max) current_item = 0
jr nz, .down_increment ; ...
ld a, 255 ; ...
.down_increment ; ...
inc a ; current_item++
cp a, (ix+MENU_T.items) ; if (current_item == max) current_item = 0
jr nz, .return_save ; ...
ld a, 0 ; ...
jr .return_save ;
.up: ;
bit 3, a ; up?
@ -82,7 +97,7 @@ menu_handle_updown:
call menu_draw_selected_item ; ...
or a ; if (current_item == 0) current_item = max
jr nz, .up_decrement ; ...
ld a, MENU_ITEMS ; ...
ld a, (ix+MENU_T.items)
.up_decrement ; ...
dec a ; current_item--
.return_save: ;
@ -104,17 +119,20 @@ menu_handle_action_left_right:
ld d, a
and #13 ; action/left/right?
jr z, .return
ld a, d
ld ix, var_menu ; IX = &menu
ld c, (ix+MENU_T.addr+0) ; IX = &menu_entry
ld b, (ix+MENU_T.addr+1) ; ...
ld ixl, c ; ...
ld ixh, b ; ...
ld a, (var_menu_current_item) ; A = selected item index
sla a ; A*8 (one menu entry - 8 bytes)
sla a ; ...
sla a ; ...
ld ix, menu ; IX = &menu
ld c, a ; IX = menu[index]
ld c, a ; IX = &menu_entry[index].callback
ld b, 0 ; ...
add ix, bc ; ...
ld l, (ix+4) ; HL = menu[index].callback
ld h, (ix+5) ; ...
ld l, (ix+MENUENTRY_T.callback+0) ; HL = menu_entry[index].callback
ld h, (ix+MENUENTRY_T.callback+1) ; ...
ld a, h ; if (HL == 0) - exit
or l ; ...
jr z, .return ; ...
@ -132,23 +150,30 @@ menu_handle_action_left_right:
; OUT - BC - garbage
; OUT - E - garbage
; OUT - HL - garbage
; OUT - IX - garbage
menu_draw_selected_item:
push af
ld b, MENU_Y+1
ld ix, var_menu
ld b, (ix+MENU_T.y_row)
inc b
add b
ld b, a
ld c, MENU_X
ld e, MENU_WIDTH
call draw_menu_item_line
call draw_attribute_line
pop af
ret
menu_draw_menu:
ld b, MENU_Y*8+8
ld ix, var_menu
ld a, (ix+MENU_T.y_pixel)
add a, 8
ld b, a
ld c, MENU_X+1
ld e, MENU_WIDTH
ld hl, menu
ld l, (ix+MENU_T.addr+0)
ld h, (ix+MENU_T.addr+1)
call draw_menu
ret

View File

@ -1,34 +1,63 @@
STRUCT MENU_T
addr DW
items DB
height DB
y_row DB
y_pixel DB
ENDS
STRUCT MENUENTRY_T
text_addr DW
value_cb_addr DW
callback DW
reserved DW
ENDS
menu:
MENU_T str_timings menu_timings_value_cb menu_timins_cb
MENU_T str_cpu menu_clock_value_cb menu_clock_cb
MENU_T str_panning menu_panning_value_cb menu_panning_cb
MENU_T str_dac menu_dac_value_cb menu_dac_cb
MENU_T str_joystick menu_joystick_value_cb menu_joystick_cb
MENU_T str_ram menu_ram_value_cb menu_ram_cb
MENU_T str_rom48 menu_rom48_value_cb menu_rom48_cb
MENU_T str_plus3 menu_plus3_value_cb menu_plus3_cb
MENU_T str_divmmc menu_divmmc_value_cb menu_divmmc_cb
MENU_T str_ulaplus menu_ulaplus_value_cb menu_ulaplus_cb
MENU_T str_exit menu_exit_value_cb menu_exit_cb
MENU_T 0
MENU_ITEMS EQU ($-menu)/MENU_T-1
MACRO MENUDESCR label_addr, items
MENU_T (label_addr) (items) (items+2) ((24-(items+2))/2) (((24-(items+2))/2)*8)
ENDM
.menu:
MENUENTRY_T str_machine menu_machine_value_cb menu_machine_cb
MENUENTRY_T str_cpu menu_clock_value_cb menu_clock_cb
MENUENTRY_T str_panning menu_panning_value_cb menu_panning_cb
MENUENTRY_T str_joystick menu_joystick_value_cb menu_joystick_cb
IFNDEF SIZIFXXS
MENUENTRY_T str_rom48 menu_rom48_value_cb menu_rom48_cb
ENDIF
MENUENTRY_T str_divmmc menu_divmmc_value_cb menu_divmmc_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_exit menu_exit_value_cb menu_exit_cb
MENUENTRY_T 0
!menu: MENUDESCR .menu, ($-.menu)/MENUENTRY_T-1
.menuext:
MENUENTRY_T str_machine menu_machine_value_cb menu_machine_cb
MENUENTRY_T str_cpu menu_clock_value_cb menu_clock_cb
MENUENTRY_T str_panning menu_panning_value_cb menu_panning_cb
MENUENTRY_T str_joystick menu_joystick_value_cb menu_joystick_cb
MENUENTRY_T str_rom48 menu_rom48_value_cb menu_rom48_cb
MENUENTRY_T str_divmmc menu_divmmc_value_cb menu_divmmc_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_tsfm menu_tsfm_value_cb menu_tsfm_cb
MENUENTRY_T str_saa menu_saa_value_cb menu_saa_cb
MENUENTRY_T str_gs menu_gs_value_cb menu_gs_cb
MENUENTRY_T str_exit menu_exit_value_cb menu_exit_cb
MENUENTRY_T 0
!menuext: MENUDESCR .menuext, ($-.menuext)/MENUENTRY_T-1
menu_timings_value_cb:
menu_machine_value_cb:
ld ix, .values_table
ld a, (cfg.timings)
ld a, (cfg.machine)
jp menu_value_get
.values_table:
DW str_timings_pentagon_end-2
DW str_timings_48_end-2
DW str_timings_128_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
@ -36,17 +65,32 @@ menu_clock_value_cb:
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
menu_panning_value_cb:
ld ix, .values_table
ld a, (var_ext_presence) ; if (ext_board && tsfm) - use ABC instead of ACB panning
or a ; ...
jr z, .no_tsfm ; ...
ld a, (cfgext.tsfm) ; ...
or a ; ...
jr z, .no_tsfm ; ...
ld a, (cfg.panning)
cp a, 2 ; if (panning == acb) panning = abc
jr c, .get ; ...
dec a ; ...
.get
jp menu_value_get
.no_tsfm:
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
menu_joystick_value_cb:
ld ix, .values_table
@ -56,41 +100,14 @@ menu_joystick_value_cb:
DW str_joystick_kempston_end-2
DW str_joystick_sinclair_end-2
menu_ram_value_cb:
ld ix, .values_table
ld a, (cfg.ram)
or a
jr nz, .less_than_512K
ld a, (cfg.divmmc) ; 256K with divmmc
or a ; ...
jr z, .is_512K ; ...
ld a, 3 ; ...
jp menu_value_get
.is_512K:
xor a
.less_than_512K:
jp menu_value_get
.values_table:
DW str_ram_512_end-2
DW str_ram_48_end-2
DW str_ram_128_end-2
DW str_ram_256_end-2
menu_rom48_value_cb:
ld ix, .values_table
ld a, (cfg.rom48)
jp menu_value_get
.values_table:
DW str_rom48_default_end-2
DW str_rom48_alt_end-2
menu_plus3_value_cb:
ld ix, .values_table
ld a, (cfg.plus3)
jp menu_value_get
.values_table:
DW str_off_end-2
DW str_on_end-2
DW str_rom48_lg_end-2
DW str_rom48_opense_end-2
menu_divmmc_value_cb:
ld ix, .values_table
@ -99,6 +116,7 @@ menu_divmmc_value_cb:
.values_table:
DW str_off_end-2
DW str_on_end-2
DW str_divmmc_noos_end-2
menu_ulaplus_value_cb:
ld ix, .values_table
@ -118,6 +136,31 @@ menu_dac_value_cb:
DW str_dac_sd_end-2
DW str_dac_covoxsd_end-2
menu_tsfm_value_cb:
ld ix, .values_table
ld a, (cfgext.tsfm)
jp menu_value_get
.values_table:
DW str_off_end-2
DW str_on_end-2
menu_saa_value_cb:
ld ix, .values_table
ld a, (cfgext.saa)
jp menu_value_get
.values_table:
DW str_off_end-2
DW str_on_end-2
menu_gs_value_cb:
ld ix, .values_table
ld a, (cfgext.gs)
jp menu_value_get
.values_table:
DW str_off_end-2
DW str_on_end-2
menu_exit_value_cb:
ld ix, .values_table
ld a, (var_exit_reboot)
@ -136,18 +179,18 @@ menu_value_get:
ret
menu_timins_cb:
ld a, (cfg.timings)
ld c, 2
menu_machine_cb:
ld a, (cfg.machine)
ld c, 3
call menu_handle_press
ld (cfg.timings), a
ld (cfg.machine), a
ld bc, #02ff
out (c), a
ret
menu_clock_cb:
ld a, (cfg.clock)
ld c, 2
ld c, 4
call menu_handle_press
ld (cfg.clock), a
ld bc, #03ff
@ -155,8 +198,19 @@ menu_clock_cb:
ret
menu_panning_cb:
ld a, (var_ext_presence) ; if (ext_board && tsfm) - do not allow to set ACB panning
or a ; ...
jr z, .no_tsfm ; ...
ld a, (cfgext.tsfm) ; ...
or a ; ...
jr z, .no_tsfm ; ...
ld a, (cfg.panning) ; ...
ld c, 1 ; ...
jr .load
.no_tsfm:
ld a, (cfg.panning)
ld c, 2
.load:
call menu_handle_press
ld (cfg.panning), a
ld bc, #04ff
@ -172,36 +226,22 @@ menu_joystick_cb:
out (c), a
ret
menu_ram_cb:
ld a, (cfg.ram)
ld c, 2
call menu_handle_press
ld (cfg.ram), a
ld bc, #08ff
out (c), a
ret
menu_rom48_cb:
ld a, (cfg.rom48)
IFDEF REV_C
ld c, 1
ELSE
ld c, 2
ENDIF
call menu_handle_press
ld (cfg.rom48), a
ld bc, #06ff
out (c), a
ret
menu_plus3_cb:
ld a, (cfg.plus3)
ld c, 1
call menu_handle_press
ld (cfg.plus3), a
ld bc, #05ff
out (c), a
ret
menu_divmmc_cb:
ld a, (cfg.divmmc)
ld c, 1
ld c, 2
call menu_handle_press
ld (cfg.divmmc), a
ld bc, #09ff
@ -226,6 +266,33 @@ menu_dac_cb:
out (c), a
ret
menu_tsfm_cb:
ld a, (cfgext.tsfm)
ld c, 1
call menu_handle_press
ld (cfgext.tsfm), a
ld bc, #e1ff
out (c), a
ret
menu_saa_cb:
ld a, (cfgext.saa)
ld c, 1
call menu_handle_press
ld (cfgext.saa), a
ld bc, #e2ff
out (c), a
ret
menu_gs_cb:
ld a, (cfgext.gs)
ld c, 1
call menu_handle_press
ld (cfgext.gs), a
ld bc, #e3ff
out (c), a
ret
menu_exit_cb:
bit 4, d ; action?
jr nz, .exit
@ -253,8 +320,8 @@ menu_handle_press:
jr nz, .decrement
ret
.increment:
cp c ; if (value == max) value = 0
jr z, .increment_roll ; ...
cp c ; if (value >= max) value = 0
jr nc, .increment_roll ; ...
inc a ; else value++
ret
.increment_roll:

33
rom_src/pause.asm Normal file
View File

@ -0,0 +1,33 @@
pause_init:
ld d, PAUSE_BODY_ATTR
ld c, PAUSE_X
ld b, PAUSE_Y
ld e, PAUSE_WIDTH
call draw_attribute_line
ld b, PAUSE_Y+2
ld e, PAUSE_WIDTH
call draw_attribute_line
ld d, PAUSE_TEXT_ATTR
ld b, PAUSE_Y+1
ld e, PAUSE_WIDTH
call draw_attribute_line
ld b, (PAUSE_Y+1)<<3
ld hl, str_pause
call print_string
ret
pause_process:
ld a, #ff ; read pause key state in bit 1 of #FFFF port
in a, (#ff) ; ...
bit 1, a ; check key is hold
jr nz, .is_hold ; yes?
ld a, 1
ld (var_pause_is_released), a
ret
.is_hold:
ld a, (var_pause_is_released) ; if key wasnt released - do nothing
or a ; ...
ret z ; ...
ld a, 1 ; otherwise - var_exit_flag = 1
ld (var_exit_flag), a ; ...
ret

View File

@ -10,6 +10,9 @@ str_sizif: DB "SIZIF-512",0
str_sizif_end:
ENDIF
str_pause DB " PAUSE ",0
str_pause_end:
str_exit: DB "Exit",0
str_exit_end:
@ -25,17 +28,20 @@ str_on_end:
str_off: DB " OFF",0
str_off_end:
str_timings: DB "Timings",0
str_timings_end:
str_machine: DB "Machine",0
str_machine_end:
str_timings_pentagon: DB "Pentagon",0
str_timings_pentagon_end:
str_machine_48: DB " 48",0
str_machine_48_end:
str_timings_128: DB " 128",0
str_timings_128_end:
str_machine_128: DB " 128",0
str_machine_128_end:
str_timings_48: DB " 48",0
str_timings_48_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:
@ -43,6 +49,12 @@ 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:
@ -76,29 +88,17 @@ str_rom48_end:
str_rom48_default: DB "Default",0
str_rom48_default_end:
str_rom48_alt: DB " Alt",0
str_rom48_alt_end:
str_rom48_lg: DB " LG",0
str_rom48_lg_end:
str_plus3: DB "+3",0
str_plus3_end:
str_rom48_opense: DB " OpenSE",0
str_rom48_opense_end:
str_divmmc: DB "DivMMC",0
str_divmmc_end:
str_ram: DB "RAM",0
str_ram_end:
str_ram_48: DB " 48K",0
str_ram_48_end:
str_ram_128: DB "128K",0
str_ram_128_end:
str_ram_256: DB "256K",0
str_ram_256_end:
str_ram_512: DB "512K",0
str_ram_512_end:
str_divmmc_noos: DB "NO OS",0
str_divmmc_noos_end:
str_ulaplus: DB "ULA+",0
str_ulaplus_end
@ -109,8 +109,17 @@ str_dac_end
str_dac_covox: DB " Covox",0
str_dac_covox_end
str_dac_sd: DB "SounDrive",0
str_dac_sd: DB " SD",0
str_dac_sd_end
str_dac_covoxsd: DB " Covox+SD",0
str_dac_covoxsd: DB "Covox+SD",0
str_dac_covoxsd_end
str_tsfm: DB "TSFM+MIDI",0
str_tsfm_end
str_saa: DB "SAA1099",0
str_saa_end
str_gs: DB "GS",0
str_gs_end

23
rom_src/variables.asm Normal file
View File

@ -0,0 +1,23 @@
var_save_ay: .32 DB 0
var_save_ulaplus: DB 0
var_sp_reg: DW 0
var_int_vector: DW 0
var_magic_enter_cnt: DB 0
var_magic_leave_cnt: DB 0
var_exit_flag: DB 0
var_exit_reboot: DB 0
var_input_key: DB 0
var_input_key_last: DB 0
var_input_key_hold_timer: DB 0
var_pause_flag: DB 0
var_pause_is_released: DB 0
var_menu_current_item: DB 0
var_menu_animate_cnt: DB 0
var_menu: MENU_T
var_ext_presence: DB 1
cfg CFG_T
cfgext CFGEXT_T
cfg_saved CFG_T
cfgext_saved CFGEXT_T
cfg_initialized: DB #B1, #5B, #00, #B5