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

17 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
239aa2a25b update jic files 2022-11-17 19:42:55 +03:00
7c6fdb683f add 14MHz mode 2022-11-01 21:01:29 +03:00
993c336507 improve compatibility with slower sram chips 2022-10-31 21:49:02 +03:00
1189d41266 change ps/2 keyboard mapping
* pause has been moved from F12 to F1
* reboot has been assigned to F10 and F12 (but still present on
Ctrl-Alt-Del / Ctrl-Alt-Backspace)
2022-10-30 20:56:54 +03:00
cf2671b9ad fix ps/2 sticking keys 2022-10-30 20:55:26 +03:00
35 changed files with 1026 additions and 806 deletions

View File

@ -1,5 +1,5 @@
OUTDIR=out_new
REV=B
REV=zero_A
.PHONY: all build_rev clean pipeline pipeline_sof
@ -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

@ -10,7 +10,7 @@ Smallest FPGA-based ZX Spectrum clone with real Z80.
* PS/2 keyboard
* Pentagon, Spectrum 128, Spectrum 48 and Spectrum +3e modes
* Altera EP1C3T100 FPGA
* Real Z80 with 3.5MHz, 4.4MHz, 5.2MHz, 7MHz modes
* Real Z80 with 3.5MHz, 4.4MHz, 5.2MHz, 7MHz (no-wait turbo) and 14MHz (turbo with wait-states) modes
* 512K RAM
* TurboSound with switchable stereo ABC/ACB/mono output
* Integrated DivMMC and Z-Controller, 1x microSD socket
@ -34,8 +34,10 @@ If you press Magic button for a short time, the standard NMI handler 'll be call
### PS/2 keyboard buttons
| Button | Function |
| - | - |
| F5 | Magic menu button |
| F12 | Pause |
| F1 | Pause |
| F5 | Magic button |
| F10 | Reboot |
| F12 | Reboot |
| Ctrl+Alt+Del | Reboot |
| Ctrl+Alt+Backspace | Reboot |
| Numpad 8, 2/5, 4, 6 | Joystick's up-down-left-right |
@ -48,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,17 +6,17 @@ endpackage
interface cpu_bus();
wire [15:0] a;
wire [7:0] d;
wire iorq;
wire mreq;
wire m1;
wire rfsh;
wire rd;
wire wr;
reg [15:0] a_raw;
reg [15:0] a;
reg [7:0] d;
reg iorq;
reg mreq;
reg m1;
reg rfsh;
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,137 +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 ext_wait_cycle,
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 [2:0] turbo_wait;
wire turbo_wait_trig0 = bus.rd || bus.wr;
reg turbo_wait_trig1;
always @(posedge clk28) begin
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 = contention || (|turbo_wait);
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;
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
else if (bus.m1) begin
rom_m1_access0 <= bus.a_raw[15:14] == 2'b00;
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

@ -47,6 +47,7 @@ reg key2_l_ctrl, key2_r_ctrl, key2_up, key2_down, key2_left, key2_right, key2_es
reg key2_minus, key2_equals, key2_back_slash, key2_tab, key2_l_bracket, key2_r_bracket, key2_semicolon, key2_quote;
reg key2_comma, key2_period, key2_slash, key2_caps, key2_pgup, key2_pgdn;
reg key2_alt, key2_del;
reg key_reset0;
reg is_press;
reg is_ext;
@ -135,8 +136,10 @@ always @(posedge clk or negedge rst_n) begin
`PS2_PGUP: key2_pgup <= is_press;
`PS2_PGDN: key2_pgdn <= is_press;
`PS2_F1: key_pause <= is_press;
`PS2_F5: key_magic <= is_press;
`PS2_F12: key_pause <= is_press;
`PS2_F10: key_reset0 <= is_press;
`PS2_F12: key_reset0 <= is_press;
`PS2_DELETE: key2_del <= is_press;
`PS2_KP_8: joy_up <= is_press;
@ -163,7 +166,7 @@ always @(posedge clk or negedge rst_n) begin
if (!rst_n)
key_reset <= 0;
else
key_reset <= (key2_l_ctrl || key2_r_ctrl) && key2_alt && (key2_del || key2_backspace);
key_reset <= ((key2_l_ctrl || key2_r_ctrl) && key2_alt && (key2_del || key2_backspace)) || key_reset0;
end

View File

@ -16,28 +16,21 @@ module ps2_rxtx#(
localparam CLKWAIT_US = 1;
localparam TOUT_US = 200;
localparam CLKWAIT_TICKS = int'(CLKWAIT_US*CLK_FREQ/1e6) + 1'b1;
localparam TOUT_US = 150; // must be greater than CLKWAIT_US
localparam TOUT_TICKS = int'(TOUT_US*CLK_FREQ/1e6) + 1'b1;
localparam TIMER_WIDTH = $clog2(TOUT_TICKS);
reg [TIMER_WIDTH-1:0] timer;
reg [$clog2(TOUT_TICKS)-1:0] timer;
reg ps2_freeze; // debounce
reg ps2_dat;
reg [1:0] ps2_clk;
wire ps2_clk_fall = ps2_freeze? 1'b0 : (ps2_clk[0] == 0 && ps2_clk[1] == 1'b1);
wire ps2_clk_fall = ps2_clk[0] == 0 && ps2_clk[1] == 1'b1;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ps2_freeze <= 0;
ps2_dat <= 1'b1;
ps2_clk <= 2'b11;
end
else begin
if (timer == CLKWAIT_TICKS)
ps2_freeze <= 1'b0;
else if (ps2_clk_fall)
ps2_freeze <= 1'b1;
ps2_dat <= ps2_dat_in;
ps2_clk <= {ps2_clk[0], ps2_clk_in};
end
@ -59,21 +52,23 @@ always @(posedge clk or negedge rst_n) begin
dataout_valid <= 0;
dataout_error <= 0;
if (ps2_clk_fall) begin
if (bit_cnt == 4'd10) begin
bit_cnt <= 0;
if (rxbits[0] == 0 && ~rxbits[9] == ^rxbits[8:1] && ps2_dat == 1'b1)
dataout_valid <= 1'b1;
else
dataout_error <= 1'b1;
end
else begin
bit_cnt <= bit_cnt + 1'b1;
rxbits <= {ps2_dat, rxbits[9:1]};
end
timer <= 1'b1;
end
else if (timer != 0) begin
if (timer == TOUT_TICKS) begin
if (timer == CLKWAIT_TICKS && !ps2_clk) begin
if (bit_cnt == 4'd10) begin
if (rxbits[0] == 0 && ~rxbits[9] == ^rxbits[8:1] && ps2_dat == 1'b1)
dataout_valid <= 1'b1;
else
dataout_error <= 1'b1;
bit_cnt <= 0;
end
else begin
rxbits <= {ps2_dat, rxbits[9:1]};
bit_cnt <= bit_cnt + 1'b1;
end
end
else if (timer == TOUT_TICKS) begin
dataout_error <= bit_cnt != 0;
bit_cnt <= 0;
end

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,44 +58,32 @@ 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 div_wait;
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 <= bus.a;
bus.d_reg <= bus.d;
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
always @(negedge clk28) begin
bus.a_raw <= {a[15:13], va[12:0]};
bus.iorq <= ~n_iorq;
bus.mreq <= ~n_mreq;
bus.m1 <= ~n_m1;
bus.rfsh <= ~n_rfsh;
bus.rd <= ~n_rd;
bus.wr <= ~n_wr;
end
always @(posedge clk28) begin
bus.a <= mem_bus_valid? {a[15:13], va[12:0]} : bus.a;
bus.d <= mem_bus_valid? vd : bus.d;
bus.ioreq <= (mem_bus_valid | bus.ioreq) & ~n_iorq & n_m1;
bus.memreq <= (mem_bus_valid | bus.memreq) & ~n_mreq & n_rfsh;
bus.memreq_rise <= mem_bus_valid & ~bus.memreq & ~n_mreq & n_rfsh;
end
assign bus.a = {a[15:13], va[12:0]};
assign bus.d = vd;
assign bus.iorq = ~n_iorq;
assign bus.mreq = ~n_mreq;
assign bus.m1 = ~n_m1;
assign bus.rfsh = ~n_rfsh;
assign bus.rd = ~n_rd;
assign bus.wr = ~n_wr;
assign bus.ioreq = bus_ioreq & ~n_iorq;
assign bus.memreq = bus_memreq & ~n_mreq;
/* RESET */
@ -105,24 +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),
.border(screen_border),
.border({border[2] ^ sd_indication, border[1] ^ magic_beeper, border[0]}),
.r(r),
.g(g),
@ -131,20 +118,19 @@ screen screen0(
.vsync(vsync),
.hsync(hsync),
.fetch_allow((!bus.iorq && !bus.mreq) || bus.rfsh || clkwait),
.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),
@ -182,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),
@ -196,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),
@ -210,35 +196,38 @@ cpucontrol cpucontrol0(
.vc(vc),
.hc(hc),
.rampage128(rampage128),
.ram_page128(ram_page128),
.machine(machine),
.screen_contention(screen_contention),
.turbo(turbo),
.ext_wait_cycle(div_wait),
.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),
@ -250,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),
@ -266,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)
);
@ -274,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 (
@ -301,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)
);
@ -337,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),
@ -359,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),
@ -380,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;
@ -404,17 +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),
.cpuwait(div_wait)
.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,11 +35,12 @@ 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];
write_req <= {write_req[0], port_ff3b_cs && bus.wr && addr_reg[7:6] == 2'b00};
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;
if (!en)
@ -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

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

@ -1,6 +1,5 @@
`include "util.vh"
import common::*;
module screen(
module video(
input rst_n,
input clk28,
@ -14,23 +13,22 @@ module screen(
output reg hsync,
output reg csync,
input fetch_allow,
output reg fetch,
output fetch_next,
output reg [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,
@ -42,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;
@ -80,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 :
@ -110,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)) :
@ -139,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;
@ -159,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;
@ -180,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;
@ -199,64 +205,57 @@ always @(posedge clk28 or negedge rst_n) begin
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 [7:0] up_ink, up_paper;
reg fetch_step;
wire fetch_bitmap = fetch && fetch_step == 1'd0;
wire fetch_attr = fetch && fetch_step == 1'd1;
assign fetch_next = loading && fetch_allow;
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] };
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
addr <= 0;
fetch <= 0;
fetch_step <= 0;
attr <= 0;
bitmap <= 0;
read_step <= 0;
read_step_cur <= 0;
attr_next <= 0;
bitmap_next <= 0;
up_ink0 <= 0;
up_paper0 <= 0;
end
else begin
if (ck14) begin
addr <= ((fetch && fetch_step == 1'd1) || (!fetch && fetch_step == 1'b0))?
{ 2'b10, vaddr[7:6], vaddr[2:0], vaddr[5:3], haddr[7:3] } :
{ 5'b10110, vaddr[7:3], haddr[7:3] };
if (next_addr)
read_step <= 0;
else if (read_req_ack)
read_step <= read_step + 1'd1;
if (fetch)
fetch_step <= fetch_step + 1'b1;
fetch <= fetch_next;
if (read_req_ack)
read_step_cur <= read_step;
if (fetch_attr)
attr_next <= fetch_data;
else if (!loading)
attr_next <= attr_border;
if (fetch_bitmap)
bitmap_next <= fetch_data;
else if (!loading)
bitmap_next <= 0;
end
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
always @(posedge clk28 or negedge rst_n) begin
if (!rst_n) begin
attr <= 0;
bitmap <= 0;
up_ink <= 0;
up_paper <= 0;
end
else begin
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;
@ -264,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
@ -274,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 :
@ -283,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,17 +1,20 @@
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
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
# 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
# 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 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

@ -58,7 +58,7 @@ set_global_assignment -name FMAX_REQUIREMENT "4 MHz" -section_id clk4
set_instance_assignment -name CLOCK_SETTINGS clk8 -to "lpm_counter:wgcnt_rtl_1|dffs[1]"
set_instance_assignment -name CLOCK_SETTINGS clk4 -to "lpm_counter:wgcnt_rtl_1|dffs[2]"
set_global_assignment -name OPTIMIZE_HOLD_TIMING OFF
set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS"
set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output/
set_global_assignment -name FMAX_REQUIREMENT "7.156 MHz" -section_id clk7
@ -67,7 +67,7 @@ set_global_assignment -name DUTY_CYCLE 40 -section_id clk7
set_global_assignment -name SAVE_DISK_SPACE OFF
set_global_assignment -name SMART_RECOMPILE ON
set_global_assignment -name POWER_USE_PVA OFF
set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING OFF
set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON
set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS OFF
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 100
@ -165,19 +165,18 @@ set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to vd[5]
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to vd[6]
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to vd[7]
set_global_assignment -name VERILOG_MACRO "REV_A=<None>"
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
set_global_assignment -name SYSTEMVERILOG_FILE ../rtl/ym2149.sv
set_global_assignment -name VERILOG_FILE ../rtl/vencode_sin_cos.v
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
@ -188,4 +187,16 @@ set_global_assignment -name SDC_FILE clocks.sdc
set_global_assignment -name CDF_FILE output/zx_ula.cdf
set_global_assignment -name QIP_FILE ip/pll.qip
set_global_assignment -name QIP_FILE ip/rom2ram.qip
set_global_assignment -name QIP_FILE ip/asmi.qip
set_global_assignment -name QIP_FILE ip/asmi.qip
set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON
set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON
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

@ -58,7 +58,7 @@ set_global_assignment -name FMAX_REQUIREMENT "4 MHz" -section_id clk4
set_instance_assignment -name CLOCK_SETTINGS clk8 -to "lpm_counter:wgcnt_rtl_1|dffs[1]"
set_instance_assignment -name CLOCK_SETTINGS clk4 -to "lpm_counter:wgcnt_rtl_1|dffs[2]"
set_global_assignment -name OPTIMIZE_HOLD_TIMING OFF
set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS"
set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output/
set_global_assignment -name FMAX_REQUIREMENT "7.156 MHz" -section_id clk7
@ -67,7 +67,7 @@ set_global_assignment -name DUTY_CYCLE 40 -section_id clk7
set_global_assignment -name SAVE_DISK_SPACE OFF
set_global_assignment -name SMART_RECOMPILE ON
set_global_assignment -name POWER_USE_PVA OFF
set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING OFF
set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON
set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS OFF
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 100
@ -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
@ -187,5 +187,16 @@ set_global_assignment -name CDF_FILE output/zx_ula.cdf
set_global_assignment -name QIP_FILE ip/pll.qip
set_global_assignment -name QIP_FILE ip/rom2ram.qip
set_global_assignment -name QIP_FILE ip/asmi.qip
set_global_assignment -name VERILOG_MACRO "REV_B=<None>"
set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON
set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON
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
set_global_assignment -name VERILOG_MACRO "REV_B=<None>"

View File

@ -58,7 +58,7 @@ set_global_assignment -name FMAX_REQUIREMENT "4 MHz" -section_id clk4
set_instance_assignment -name CLOCK_SETTINGS clk8 -to "lpm_counter:wgcnt_rtl_1|dffs[1]"
set_instance_assignment -name CLOCK_SETTINGS clk4 -to "lpm_counter:wgcnt_rtl_1|dffs[2]"
set_global_assignment -name OPTIMIZE_HOLD_TIMING OFF
set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS"
set_global_assignment -name FITTER_EFFORT "STANDARD FIT"
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output/
set_global_assignment -name FMAX_REQUIREMENT "7.156 MHz" -section_id clk7
@ -67,7 +67,7 @@ set_global_assignment -name DUTY_CYCLE 40 -section_id clk7
set_global_assignment -name SAVE_DISK_SPACE OFF
set_global_assignment -name SMART_RECOMPILE ON
set_global_assignment -name POWER_USE_PVA OFF
set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING OFF
set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON
set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS OFF
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 100
@ -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
@ -189,10 +189,15 @@ set_global_assignment -name QIP_FILE ip/rom2ram.qip
set_global_assignment -name QIP_FILE ip/asmi.qip
set_global_assignment -name VERILOG_MACRO "REV_ZERO_A=<None>"
set_instance_assignment -name CURRENT_STRENGTH_NEW "MINIMUM CURRENT" -to clkcpu
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA OFF
set_global_assignment -name PHYSICAL_SYNTHESIS_EFFORT NORMAL
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON
set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON
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.A.jic vendored

Binary file not shown.

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

Binary file not shown.

BIN
out/fpga.rev.B.jic vendored

Binary file not shown.

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

Binary file not shown.

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
@ -76,7 +77,7 @@ nmi_handler:
call check_entering_pause ; A[1] == 1 if pause button is pressed
bit 1, a ; ...
jp nz, .enter_pause ; ...
call delay_10ms ;
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, .enter_menu ; ...
@ -89,14 +90,14 @@ nmi_handler:
ld bc, #00ff ; ...
in a, (c) ; if divmmc paged - just do retn
bit 3, a ; ...
jr nz, exit_with_ret ; ...
jr nz, exit_with_ret ; ...
ld hl, #0066 ; otherwise jump to default nmi handler
jr exit_with_jp ; ...
.enter_pause:
ld hl, nmi_pause
ld (var_main_fun), hl
jr .enter
jr .enter
.enter_menu:
ld hl, nmi_menu
ld (var_main_fun), hl
@ -130,7 +131,7 @@ nmi_handler:
out (c), a ; ...
.leave_without_reboot:
pop af ; A = I
push af ;
push af ;
call get_im2_handler ; HL = default im2 handler address
ld (var_int_vector), hl
xor a ; disable border
@ -208,7 +209,7 @@ load_config:
save_config:
ld bc, CFG_T ; cfg_saved = cfg
ld de, cfg_saved ; ...
ld hl, cfg ; ...
ld hl, cfg ; ...
ldir ; ...
ret
@ -230,7 +231,7 @@ init_cpld:
out (c), a ; ...
.do_load:
ld b, CFG_T ; B = registers count
ld c, #ff ;
ld c, #ff ;
ld hl, cfg+CFG_T-1 ; HL = &cfg[registers count-1]
otdr ; do { b--; out(bc, *hl); hl--; } while(b)
ret
@ -259,7 +260,7 @@ check_entering_pause:
; OUT - A = 1 if we are entering menu, A = 2 if we are leaving menu, A = 0 otherwise
; OUT - F - garbage
check_entering_menu:
check_entering_menu:
xor a ; read magic key state in bit 0 of #00FF port
in a, (#ff) ; ...
bit 0, a ; check key is hold
@ -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
@ -514,7 +524,7 @@ var_ram_func:
; Magic vectors
ORG #F000
Exit_vector:
Exit_vector:
ORG #F008
Readout_vector:

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
@ -138,7 +162,7 @@ menu_machine_cb:
menu_clock_cb:
ld a, (cfg.clock)
ld c, 3
ld c, 4
call menu_handle_press
ld (cfg.clock), a
ld bc, #03ff
@ -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
@ -232,4 +284,3 @@ menu_handle_press:
.decrement_roll:
ld a, c ; value = max
ret

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..."