`timescale 1ns / 1ps
`default_nettype none
// This file is part of the ZXUNO Spectrum core.
// Creation date is 16:54:55 2014-02-16 by Miguel Angel Rodriguez Jodar
// (c)2014-2020 ZXUNO association.
// ZXUNO official repository: http://svn.zxuno.com/svn/zxuno
// Username: guest Password: zxuno
// Github repository for this core: https://github.com/mcleod-ideafix/zxuno_spectrum_core
//
// ZXUNO Spectrum core is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ZXUNO Spectrum core is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the ZXUNO Spectrum core. If not, see .
//
// Any distributed copy of this file must keep this notice intact.
module ula_radas (
// Clocks
input wire sysclk,
input wire clk14en,
input wire clk7en,
input wire clk7en_n,
input wire clk35en,
input wire clk35en_n,
output wire CPUContention,
input wire rst_n, // reset para volver al modo normal
// CPU interface
input wire [15:0] a,
input wire mreq_n,
input wire iorq_n,
input wire rd_n,
input wire wr_n,
input wire rfsh_n,
output wire int_n,
input wire [7:0] din,
output reg [7:0] dout,
input wire rasterint_enable,
input wire vretraceint_disable,
input wire [8:0] raster_line,
output wire raster_int_in_progress,
// VRAM interface
output reg [13:0] va, // 16KB videoram
input wire [7:0] vramdata,
// ZX-UNO register interface
input wire [7:0] zxuno_addr,
input wire zxuno_regrd,
input wire zxuno_regwr,
input wire regaddr_changed,
// I/O ports and Timex control
input wire ear,
input wire [4:0] kbd,
output reg mic,
output reg spk,
input wire issue2_keyboard,
input wire [1:0] mode,
input wire ioreqbank,
input wire disable_contention,
input wire access_to_contmem,
output wire doc_ext_option,
input wire enable_timexmmu,
input wire disable_timexscr,
input wire disable_ulaplus,
input wire disable_radas,
input wire csync_option,
// Debug
// input wire button_up,
// input wire button_down,
// output wire [7:0] posint,
// Video
output wire [2:0] r,
output wire [2:0] g,
output wire [2:0] b,
output wire [8:0] hcnt,
output wire [8:0] vcnt,
output wire hsync,
output wire vsync,
output wire csync,
output wire [8:0] end_count_v
);
`include "config.vh"
parameter
BHPIXEL = 0,
EHPIXEL = 255,
BVPIXEL = 0,
EVPIXEL = 191,
BVSYNC = 248;
parameter
ULA48K = 2'b00,
ULA128K = 2'b01,
PENTAGON = 2'b10,
NTSC = 2'b11;
// RGB inputs to sync module
reg [2:0] ri;
reg [2:0] gi;
reg [2:0] bi;
// Counters from sync module
wire [8:0] hc;
wire [8:0] vc;
assign hcnt = hc;
assign vcnt = vc;
// Initial values for Radastanian mode pixel and border palette bank
reg radasborderpalettehalf = 1'b0;
reg [1:0] radaspixelpalettequarter = 2'b00;
// Initial values for synch, syncv for all supported timings
reg [8:0] hinit48k = 9'd112;
reg [8:0] vinit48k = 9'd0;
reg [8:0] hinit128k = 9'd116;
reg [8:0] vinit128k = 9'd0;
reg [8:0] hinitpen = 9'd116;
reg [8:0] vinitpen = 9'd0;
// Initial values for offset and padding in Radastanian mode, used for HW scroller
reg [13:0] radasoffset = 14'h0000;
reg [7:0] radaspadding = 8'h00;
reg ffbitmapofs = 1'b0;
reg [7:0] lastdatatoradasoffset = 8'h00;
// Signal when the vertical counter is in the line that we use to make the INT signal
wire in_int_line;
pal_sync_generator syncs (
.clk(sysclk),
.clken(clk7en),
.mode(mode),
.rasterint_enable(rasterint_enable),
.vretraceint_disable(vretraceint_disable),
.raster_line(raster_line),
.raster_int_in_progress(raster_int_in_progress),
.csync_option(csync_option),
.hinit48k(hinit48k),
.vinit48k(vinit48k),
.hinit128k(hinit128k),
.vinit128k(vinit128k),
.hinitpen(hinitpen),
.vinitpen(vinitpen),
// .button_up(button_up),
// .button_down(button_down),
// .posint(posint),
.ri(ri),
.gi(gi),
.bi(bi),
.hcnt(hc),
.vcnt(vc),
.ro(r),
.go(g),
.bo(b),
.hsync(hsync),
.vsync(vsync),
.csync(csync),
.int_n(int_n),
.end_count_v(end_count_v)
);
///////////////////////////////////////////////
// ULA datapath
///////////////////////////////////////////////
// Control signals generated from the control unit
// or the rest of modules
reg BitmapDataLoad;
reg AttrDataLoad;
reg WriteToPortFE;
reg SerializerLoad;
reg TimexConfigLoad;
reg AttrOutputLoad;
reg PaletteRegLoad;
reg ConfigRegLoad;
reg PaletteLoad;
reg BitmapAddr;
reg AttrAddr;
reg CALoad;
reg VideoEnable;
wire RadasEnabled; // =1 is el modo radastaniano está habilitado
// BitmapData register
reg [7:0] BitmapData = 8'h00;
always @(posedge sysclk) begin
if (BitmapDataLoad && clk7en)
BitmapData <= vramdata;
end
// AttrData register
reg [7:0] AttrData = 8'h00;
always @(posedge sysclk) begin
if (AttrDataLoad && clk7en)
AttrData <= vramdata;
end
// Border register
reg [2:0] Border = 3'b010; // initial border colour is red
always @(posedge sysclk) begin
if (WriteToPortFE)
Border <= din[2:0];
end
// BitmapSerializer register
reg [7:0] BitmapSerializer = 8'h00;
wire SerialOutput = BitmapSerializer[7];
always @(posedge sysclk) begin
if (clk7en == 1'b1) begin
if (SerializerLoad == 1'b1)
BitmapSerializer <= BitmapData;
else
BitmapSerializer <= {BitmapSerializer[6:0],1'b0};
end
end
reg clkhalf14 = 1'b0;
always @(posedge sysclk)
if (clk14en == 1'b1)
clkhalf14 <= ~clkhalf14;
// BitmapSerializerHR register
reg [15:0] BitmapSerializerHR = 8'h00;
wire SerialOutputHR = BitmapSerializerHR[15];
always @(posedge sysclk) begin
if (clk14en == 1'b1) begin
if (SerializerLoad == 1'b1 && clkhalf14 == 1'b1)
BitmapSerializerHR <= {BitmapData,AttrData};
else
BitmapSerializerHR <= {BitmapSerializerHR[14:0],1'b0};
end
end
// Timex config register
reg [7:0] TimexConfigReg = 8'h00;
wire PG = TimexConfigReg[0];
wire HCL = TimexConfigReg[1];
wire HR = TimexConfigReg[2];
assign doc_ext_option = enable_timexmmu & TimexConfigReg[7];
wire [2:0] HRInk = TimexConfigReg[5:3];
`ifdef ULA_TIMEX_SUPPORT
always @(posedge sysclk) begin
if (rst_n == 1'b0)
TimexConfigReg <= 8'h00;
else if (TimexConfigLoad)
TimexConfigReg <= din;
end
`endif
// Combinational logic between AttrData and AttrOutput
reg [7:0] InputToAttrOutput;
always @* begin
InputToAttrOutput = AttrData;
case ({VideoEnable,HR})
2'b00 : InputToAttrOutput = (RadasEnabled)? {radasborderpalettehalf,Border,radasborderpalettehalf,Border} : {2'b00,Border,3'b000};
2'b01,
2'b11 : InputToAttrOutput = {2'b01,~HRInk,HRInk};
2'b10 : InputToAttrOutput = AttrData;
endcase
end
// AttrOutput register
reg [7:0] AttrOutput = 8'h00;
reg [7:0] BorderColorDelayed; // used to delay 0.5T the assignment from border to AttrOutput while in Pentagon mode. De donde he sacado esta información???
wire [2:0] StdPaperColour = AttrOutput[5:3];
wire [2:0] StdInkColour = AttrOutput[2:0];
wire Bright = AttrOutput[6];
wire Flash = AttrOutput[7];
always @(posedge sysclk) begin
if (clk7en) begin
BorderColorDelayed <= {2'b00,Border,3'b000}; // update always BorderColorDelayed
if (mode == PENTAGON && (hc<(BHPIXEL+12) || hc>(EHPIXEL+12) || vcEVPIXEL))
AttrOutput <= BorderColorDelayed; // and in next pixel clock, update AttrOutput if in border and Pentagon mode is on
else if (AttrOutputLoad)
AttrOutput <= InputToAttrOutput;
end
end
// Combinational logic to generate pixel bit
reg Pixel;
always @* begin
if (HR)
Pixel = SerialOutputHR;
else
Pixel = SerialOutput;
end
// Flash!
reg [4:0] FlashCounter = 5'h00;
wire FlashFF = FlashCounter[4];
wire PixelWFlash = Pixel ^ (Flash & FlashFF);
always @(posedge sysclk) begin
if (vc==BVSYNC && hc==0 && clk7en)
FlashCounter <= FlashCounter + 5'd1;
end
// Standard ULA final 4-bit IGRB colour
reg [3:0] StdPixelColour;
always @* begin
if (PixelWFlash)
StdPixelColour = {Bright,StdInkColour};
else
StdPixelColour = {Bright,StdPaperColour};
end
// LUT-based translatator from IGRB to 9-bit GRB
`define none 3'b000
`define half 3'b101
`define full 3'b111
reg [8:0] Std9bitColour;
always @* begin
case (StdPixelColour) // speccy colour to GGGRRRBBB colour. If you want to alter the standard palette,
// this is what you need to touch ;)
0,8: Std9bitColour = {`none,`none,`none};
1: Std9bitColour = {`none,`none,`half};
2: Std9bitColour = {`none,`half,`none};
3: Std9bitColour = {`none,`half,`half};
4: Std9bitColour = {`half,`none,`none};
5: Std9bitColour = {`half,`none,`half};
6: Std9bitColour = {`half,`half,`none};
7: Std9bitColour = {`half,`half,`half};
9: Std9bitColour = {`none,`none,`full};
10: Std9bitColour = {`none,`full,`none};
11: Std9bitColour = {`none,`full,`full};
12: Std9bitColour = {`full,`none,`none};
13: Std9bitColour = {`full,`none,`full};
14: Std9bitColour = {`full,`full,`none};
15: Std9bitColour = {`full,`full,`full};
default: Std9bitColour = {`none,`none,`none};
endcase
end
// PaletteReg register (ULAplus)
reg [6:0] PaletteReg = 7'h00;
always @(posedge sysclk) begin
if (PaletteRegLoad)
PaletteReg <= din[6:0];
end
// ConfigReg register (ULAplus)
reg ConfigReg = 1'b0;
always @(posedge sysclk) begin
if (rst_n == 1'b0)
ConfigReg <= 1'b0;
else if (ConfigRegLoad)
ConfigReg <= din[0];
end
// RadasCtrl register
reg [1:0] RadasCtrl = 2'b00;
always @(posedge sysclk) begin
if (rst_n == 1'b0)
RadasCtrl <= 2'b00;
else if (zxuno_addr == RADASCTRL && zxuno_regwr == 1'b1 && disable_radas == 1'b0)
RadasCtrl <= din[1:0];
end
assign RadasEnabled = &RadasCtrl[1:0];
wire ULAplusEnabled = ConfigReg | RadasEnabled;
// Palette LUT
wire [7:0] PaletteEntryToCPU;
wire [7:0] ULAplusPaperColour;
wire [7:0] ULAplusInkColour;
wire [5:0] AddressA1 = (RadasEnabled)? {radaspixelpalettequarter,InputToAttrOutput[7:4]} :
{InputToAttrOutput[7:6],1'b1,InputToAttrOutput[5:3]};
wire [5:0] AddressA2 = (RadasEnabled)? {radaspixelpalettequarter,InputToAttrOutput[3:0]} :
{InputToAttrOutput[7:6],1'b0,InputToAttrOutput[2:0]};
lut palette (
.clk(sysclk),
.load(PaletteLoad),
.din(din),
.a1(AddressA1),
.a2(AddressA2),
.a3(PaletteReg[5:0]),
.do1(ULAplusPaperColour),
.do2(ULAplusInkColour),
.do3(PaletteEntryToCPU)
);
// AttrPlusOutput register
reg [15:0] AttrPlusOutput = 16'h0000;
always @(posedge sysclk) begin
if (AttrOutputLoad && clk7en)
AttrPlusOutput <= {ULAplusPaperColour,ULAplusInkColour};
end
// ULAplus final 8-bit GGGRRRBB colour
reg [7:0] ULAplusPixelColour;
always @* begin
case ({RadasEnabled,hc[1],Pixel})
3'b000,
3'b010 : ULAplusPixelColour = AttrPlusOutput[15:8];
3'b001,
3'b011 : ULAplusPixelColour = AttrPlusOutput[7:0];
3'b100,
3'b101 : ULAplusPixelColour = AttrPlusOutput[15:8]; // pixel izquierdo del par
3'b110,
3'b111 : ULAplusPixelColour = AttrPlusOutput[7:0]; // pixel derecho del par
default : ULAplusPixelColour = AttrPlusOutput[15:8];
endcase
end
// 332-GRB to 333-GRB (blue turns from B1 B0 into B1 B0 B1 or B0)
wire [8:0] ULAplus9bitColour = {ULAplusPixelColour,ULAplusPixelColour[1] | ULAplusPixelColour[0]};
// Final stage. Final colour is connected to PAL generator
always @* begin
if (ULAplusEnabled) begin
gi = ULAplus9bitColour[8:6];
ri = ULAplus9bitColour[5:3];
bi = ULAplus9bitColour[2:0];
end
else begin
gi = Std9bitColour[8:6];
ri = Std9bitColour[5:3];
bi = Std9bitColour[2:0];
end
end
// Column address register (CA)
reg [4:0] CA = 5'h00;
always @(posedge sysclk) begin
if (CALoad && clk7en)
CA <= hc[7:3];
end
// VRAM Address generation
// ULA snow effect added. Only for 48K ULA.
/*
En el primer par de bytes leidos sólo puede haber corrupción por valor de R en bus. Esto ocurriría en el ciclo 8.
La corrupción desaparece en el ciclo 11 si no se fuerza por la condicion siguiente.
En el segundo par de bytes leidos puede haber corrupción por lo anterior (ciclo 12), o por RAS forzado a bajo (ciclo 11).
*/
reg [6:0] dram_row_for_ula_snow = 7'h00;
reg snow_is_about_to_happen = 1'b0;
reg [6:0] latched_row_from_first_burst = 7'h00;
`ifdef ULA_SNOW_SUPPORT
always @(posedge sysclk) begin
if (clk7en) begin
if ((hc[3:0] == 4'd7 || hc[3:0] == 4'd8 || hc[3:0] == 4'd11) && rfsh_n == 1'b0 && mreq_n == 1'b0 && a[15:14]==2'b01) begin
if (snow_is_about_to_happen == 1'b0)
dram_row_for_ula_snow <= a[6:0]; // value of address if CPU address interferes with ULA DRAM address
snow_is_about_to_happen <= (mode == ULA48K); // emulate the condition of VRAM address corruption, only if in a 48K ULA
end
else if ((hc[3:0] == 4'd10) && rfsh_n == 1'b0 && mreq_n == 1'b0 && a[15:14]==2'b01) begin
dram_row_for_ula_snow <= latched_row_from_first_burst; // value of row address if RAS doesn't get updated between bursts
snow_is_about_to_happen <= (mode == ULA48K); // emulate the condition of RAS being kept low, , only if in a 48K ULA
end
else if (hc[3:0] == 4'd15 || (hc[3:0] == 4'd11 && (rfsh_n == 1'b1 || mreq_n == 1'b1 || a[15:14]!=2'b01)))
snow_is_about_to_happen <= 1'b0;
if (hc[3:0] == 4'd9)
latched_row_from_first_burst <= va[6:0]; // this is the row value that would be latched during the first DRAM read burst.
end
end
`endif
wire [8:0] hcd = hc + 9'hFF8; // hc delayed 8 ticks
always @* begin
if (!RadasEnabled) begin
if (BitmapAddr) begin
va = {PG,vc[7:6],vc[2:0],vc[5:3],CA};
if (snow_is_about_to_happen == 1'b1) // this IF statement will never be true if ULA is not a 48K ULA
va[6:0] = dram_row_for_ula_snow;
end
else if (AttrAddr) begin
if (HCL==1'b0) begin
va = {PG,3'b110,vc[7:3],CA};
if (snow_is_about_to_happen == 1'b1) // this IF statement will never be true if ULA is not a 48K ULA
va[6:0] = dram_row_for_ula_snow;
end
else begin
va = {1'b1,vc[7:6],vc[2:0],vc[5:3],CA};
end
end
else
va = 14'h0000;
end
else begin
va = {PG,vc[7:1],hcd[7:2]} + radasoffset + vc[7:1]*radaspadding;
end
end
///////////////////////////////////////////////
// ULA control unit
///////////////////////////////////////////////
// control data flow from VRAM to RGB output
reg Border_n;
always @* begin
if (vc>=BVPIXEL && vc<=EVPIXEL && hc>=BHPIXEL && hc<=EHPIXEL)
Border_n = 1;
else
Border_n = 0;
end
always @* begin
BitmapDataLoad = 1'b0;
AttrDataLoad = 1'b0;
SerializerLoad = 1'b0;
VideoEnable = 1'b0;
AttrOutputLoad = 1'b0;
BitmapAddr = 1'b0;
AttrAddr = 1'b0;
CALoad = 1'b0;
if (!RadasEnabled) begin // Control para los modos estándar
if (hc>=(BHPIXEL+8) && hc<=(EHPIXEL+8) && vc>=BVPIXEL && vc<=EVPIXEL) begin // VidEN_n is low here: paper area
VideoEnable = 1'b1;
if (hc[2:0]==3'd4) begin
SerializerLoad = 1'b1; // updated every 8 pixel clocks, if we are in paper area
end
end
if (hc[2:0] == 3'd4) begin // hc=4,12,20,28,etc
AttrOutputLoad = 1'b1; // updated every 8 pixel clocks
end
if (hc[2:0]==3'd3) begin
CALoad = 1'b1;
end
if (hc>=BHPIXEL && hc<=EHPIXEL && vc>=BVPIXEL && vc<=EVPIXEL) begin
if (hc[3:0]==4'd8 || hc[3:0]==4'd12) begin
BitmapAddr = 1'b1;
end
if (hc[3:0]==4'd9 || hc[3:0]==4'd13) begin
BitmapAddr = 1'b1;
BitmapDataLoad = 1'b1;
end
if (hc[3:0]==4'd10 || hc[3:0]==4'd14) begin
AttrAddr = 1'b1;
end
if (hc[3:0]==4'd11 || hc[3:0]==4'd15) begin
AttrAddr = 1'b1;
AttrDataLoad = 1'b1;
end
end
end
`ifdef ULA_RADASTAN_SUPPORT
else begin // Control para el modo radastaniano
if (hc[1:0]==2'b11) begin // trasladamos dos píxeles a la salida
AttrOutputLoad = 1'b1;
end
if (hc>=(BHPIXEL+8) && hc<=(EHPIXEL+8) && vc>=BVPIXEL && vc<=EVPIXEL) begin // VidEN_n is low here: paper area
VideoEnable = 1'b1;
if (hc[1:0]==2'b01) begin // sólo durante video activo: se lee la memoria de pantalla
AttrDataLoad = 1'b1;
end
end
end
`endif
end
///////////////////////////////////////////////
// ULA interface with CPU
///////////////////////////////////////////////
// Z80 writes values into registers
// Port 0xFE
always @(posedge sysclk) begin
if (WriteToPortFE) begin
{spk,mic} <= din[4:3];
end
end
// TIMEX and ULAplus ports
always @* begin
TimexConfigLoad = 1'b0;
PaletteRegLoad = 1'b0;
ConfigRegLoad = 1'b0;
PaletteLoad = 1'b0;
WriteToPortFE = 1'b0;
if (iorq_n==1'b0 && wr_n==1'b0) begin
if (a[0]==1'b0 && (!enable_timexmmu || a[7:0]!=TIMEXMMU))
WriteToPortFE = 1'b1;
else if (a[7:0]==TIMEXPORT && !disable_timexscr)
TimexConfigLoad = 1'b1;
else if (a==ULAPLUSADDR && !disable_ulaplus)
PaletteRegLoad = 1'b1;
else if (a==ULAPLUSDATA && !disable_ulaplus) begin
if (PaletteReg[6]==1'b0) // writting a new value into palette LUT
PaletteLoad = 1'b1;
else
ConfigRegLoad = 1'b1; // writting a new value into ULAplus config register
end
end
end
// Sync and radastanian palette adjustment
always @(posedge sysclk) begin
if (rst_n == 1'b0) begin
radasborderpalettehalf <= 1'b0;
radaspixelpalettequarter <= 2'b00;
end
else if (zxuno_regwr == 1'b1) begin
case (zxuno_addr)
HOFFS48K: hinit48k <= {din,1'b0};
VOFFS48K: vinit48k <= {din,1'b0};
HOFFS128K: hinit128k <= {din,1'b0};
VOFFS128K: vinit128k <= {din,1'b0};
HOFFSPEN: hinitpen <= {din,1'b0};
VOFFSPEN: vinitpen <= {din,1'b0};
RADASPALBANK: {radasborderpalettehalf,radaspixelpalettequarter} <= din[2:0];
endcase
end
end
// Control de offsets del modo radastaniano
reg offset_reg_accessed = 1'b0;
always @(posedge sysclk) begin
if (rst_n == 1'b0) begin
ffbitmapofs <= 1'b0;
radasoffset <= 14'h0000;
radaspadding <= 8'h00;
end
else begin
if (regaddr_changed && zxuno_addr == RADASOFFSET)
ffbitmapofs <= 1'b0;
else if (offset_reg_accessed == 1'b0 && zxuno_addr == RADASOFFSET && (zxuno_regrd == 1'b1 || zxuno_regwr == 1'b1)) begin
if (zxuno_regwr == 1'b1 && ffbitmapofs == 1'b0) begin
radasoffset[7:0] <= din;
end
else if (zxuno_regwr == 1'b1 && ffbitmapofs == 1'b1) begin
radasoffset[13:8] <= din[5:0];
end
else if (zxuno_regrd == 1'b1 && ffbitmapofs == 1'b0) begin
lastdatatoradasoffset <= radasoffset[7:0];
end
else if (zxuno_regrd == 1'b1 && ffbitmapofs == 1'b1) begin
lastdatatoradasoffset <= {2'b00,radasoffset[13:8]};
end
ffbitmapofs <= ~ffbitmapofs;
offset_reg_accessed <= 1'b1;
end
else if (zxuno_regwr == 1'b1 && zxuno_addr == RADASPADDING) begin
radaspadding <= din;
end
if (offset_reg_accessed == 1'b1 && zxuno_regwr == 1'b0 && zxuno_regwr == 1'b0)
offset_reg_accessed <= 1'b0;
end
end
reg post_processed_ear; // EAR signal after being altered by the keyboard current issue
always @* begin
if (issue2_keyboard)
post_processed_ear = ear ^ (spk | mic);
else
post_processed_ear = ear ^ spk;
end
// Z80 gets values from registers (or floating bus)
always @* begin
dout = 8'hFF;
if (iorq_n==1'b0 && rd_n==1'b0) begin
if (a[0]==1'b0 && (a[7:0]!=TIMEXMMU || !enable_timexmmu))
dout = {1'b1,post_processed_ear,1'b1,kbd};
else if (a==ULAPLUSADDR && !disable_ulaplus)
dout = {1'b0,PaletteReg};
else if (a==ULAPLUSDATA && PaletteReg[6]==1'b0 && !disable_ulaplus)
dout = PaletteEntryToCPU;
else if (a==ULAPLUSDATA && PaletteReg[6]==1'b1 && !disable_ulaplus)
dout = {7'b0000000,ConfigReg};
else if (a[7:0]==TIMEXPORT && enable_timexmmu && !disable_timexscr)
dout = TimexConfigReg;
else if (zxuno_addr == HOFFS48K && zxuno_regrd == 1'b1)
dout = hinit48k[8:1];
else if (zxuno_addr == VOFFS48K && zxuno_regrd == 1'b1)
dout = vinit48k[8:1];
else if (zxuno_addr == HOFFS128K && zxuno_regrd == 1'b1)
dout = hinit128k[8:1];
else if (zxuno_addr == VOFFS128K && zxuno_regrd == 1'b1)
dout = vinit128k[8:1];
else if (zxuno_addr == HOFFSPEN && zxuno_regrd == 1'b1)
dout = hinitpen[8:1];
else if (zxuno_addr == VOFFSPEN && zxuno_regrd == 1'b1)
dout = vinitpen[8:1];
else if (zxuno_addr == RADASCTRL && zxuno_regrd == 1'b1 && !disable_radas)
dout = {6'b000000,RadasCtrl};
else if (zxuno_addr == RADASOFFSET && zxuno_regrd == 1'b1 && !disable_radas)
dout = lastdatatoradasoffset;
else if (zxuno_addr == RADASPADDING && zxuno_regrd == 1'b1 && !disable_radas)
dout = radaspadding;
else if (zxuno_addr == RADASPALBANK && zxuno_regrd == 1'b1 && !disable_radas)
dout = {5'b00000, radasborderpalettehalf,radaspixelpalettequarter};
else begin
if (BitmapAddr || AttrAddr)
dout = vramdata;
else
dout = 8'hFF;
end
end
end
///////////////////////////////////
// AUXILIARY SIGNALS FOR CONTENTION CONTROL
///////////////////////////////////
wire iorequla = !iorq_n && (a[0]==0);
wire iorequlaplus = !iorq_n && !disable_ulaplus && (a==ULAPLUSADDR || a==ULAPLUSDATA);
wire ioreqall_n = !(iorequlaplus || iorequla || ioreqbank);
///////////////////////////////////
// CPU CLOCK GENERATION (Altwasser method)
///////////////////////////////////
//`define MASTERCPUCLK clk7
// reg ioreqtw3 = 0;
// reg mreqt23 = 0;
// wire N1y2 = ~access_to_contmem | ioreqall_n;
// wire N3 = hc[3:0]>=4'd4;
// wire N4 = ~Border_n | ~ioreqtw3 | ~mreqt23 | ~cpuclk;
// wire N5 = ~(N1y2 | N3 | N4);
// wire N6 = ~(hc[3:0]>=4'd4 | ~Border_n | ~cpuclk | ioreqall_n | ~ioreqtw3);
//
// always @(posedge cpuclk) begin
// ioreqtw3 <= ioreqall_n;
// mreqt23 <= mreq_n;
// end
//
// wire Nor1 = (~access_to_contmem & ioreqall_n) | (hc[3:0]<4'd12) |
// (~Border_n | ~ioreqtw3 | ~cpuclk | ~mreqt23);
// wire Nor2 = (hc[3:0]<4'd4) | ~Border_n | ~cpuclk | ioreqall_n | ~ioreqtw3;
// wire CLKContention = ~Nor1 | ~Nor2;
//
// always @(posedge cpuclk) begin
// if (!CLKContention) begin
// ioreqtw3 <= ioreqall_n;
// mreqt23 <= mreq_n;
// end
// end
//
// assign CPUContention = ~(!CLKContention || RadasEnabled || disable_contention);
///////////////////////////////////
// CPU CLOCK GENERATION (CSmith method)
///////////////////////////////////
reg MayContend_n;
always @(posedge sysclk) begin // esto era negedge clk7 en el esquemático
if (clk7en_n) begin
if (hc[3:0]>4'd3 && Border_n==1'b1)
MayContend_n <= 1'b0;
else
MayContend_n <= 1'b1;
end
end
reg CauseContention_n;
always @* begin
if ((access_to_contmem || !ioreqall_n) && !RadasEnabled && !disable_contention)
CauseContention_n = 1'b0;
else
CauseContention_n = 1'b1;
end
reg CancelContention = 1'b1;
reg CancelContention_cycle_before = 1'b1;
always @(posedge sysclk) begin
if (clk35en && !CPUContention) begin
if (!mreq_n || !ioreqall_n)
CancelContention_cycle_before <= 1'b1;
else
CancelContention_cycle_before <= 1'b0;
end
if (clk35en_n)
CancelContention <= CancelContention_cycle_before;
end
//assign cpuclk = (~(MayContend_n | CauseContention_n | CancelContention)) | hc[0];
assign CPUContention = (~(MayContend_n | CauseContention_n | CancelContention));
endmodule