Код:
module speccy2007_vid (
input wire CLK, // 14MHz input clock
input wire nCPU_Reset, // CPU reset
input wire RD,
input wire WR,
input wire IOREQ,
input wire MREQ,
input wire M1,
input wire A14,
input wire A15,
input wire AVR_NOINT,
input wire AVR_PROM,
input wire AVR_WAIT,
input wire TAPE_IN,
input wire [7:0] mD,
output wire nADR_GATE_EN,
output wire ROM_CS,
output wire ROM_A14,
output wire ROM_A15,
output wire AY_CLK,
output reg AY_BC1,
output reg AY_BDIR,
output reg CLK_CPU = 1, // CPU clock 3.5 MHz
output reg WR_BUF = 0,
output wire nRD_BUF_EN,
output reg nWR_GATE_EN = 1,
output reg INT = 1,
output reg mRD = 1,
output reg mWR = 1,
output reg RAM_A14 = 0,
output reg RAM_A15 = 0,
output reg RAM_A16 = 0,
output reg SYNC = 1,
output reg Red = 0,
output reg Green = 0,
output reg Blue = 1,
output reg Bright = 0,
output wire AVR_INT,
output wire AVR_TRDOS,
output wire SPEAKER,
inout wire [13:0] mA
);
reg pixel_clock = 0; // 7MHz pixel clock
reg [4:0] flash_cnt = 5'b00000; // flash counter
reg [2:0] ChrC_Cnt = 3'b000; // Character column counter
reg [5:0] Hor_Cnt = 6'b000000;// Horizontal counter
reg [2:0] ChrR_Cnt = 3'b000; // Character row counter
reg [5:0] Ver_Cnt = 6'b000000;// Vertical counter
reg [7:0] attr; // attributes register
reg [7:0] pixels; // pixel data from data bus
reg [7:0] attr_buf; // attributes buffer register
reg [7:0] pixels_buf; // pixel data buffer register
reg [3:0] border_attr = 3'b000; // border attributes
reg [5:0] port_7ffd; // port 7FFD data
reg AVR_PORT = 0;
reg VBUS_REQ = 1;
reg VBUS_ACK = 1;
reg VBUS_MODE = 1;
reg VBUS_RDY = 1;
reg VidRD = 0;
reg paper_r;
reg blank_r;
reg paper;
reg hsync;
reg vsync1;
reg vsync2;
reg pport_wait = 0;
wire VRAM_ACC;
reg TRDOS_TGL = 0;
reg TRDOS_FLG = 0;
reg PROM_TGL = 0;
reg PROM_FLG = 0;
reg [2:0] RAM_PAGE = 3'b000;
reg [1:0] ROM_PAGE = 2'b00;
reg SOUND_OUT = 0;
reg AY_PORT = 0;
wire RAM;
wire ROMADR = A14 | A15;
assign SPEAKER = SOUND_OUT ^ TAPE_IN;
assign ROM_CS = MREQ | ROMADR | TRDOS_TGL | PROM_TGL;
assign RAM = MREQ | ~ROMADR;
assign ROM_A14 = ROM_PAGE[0];
assign ROM_A15 = ROM_PAGE[1];
assign nADR_GATE_EN = VBUS_MODE;
assign nRD_BUF_EN = RAM | RD;
assign AY_CLK = ChrC_Cnt[1];
assign AVR_INT = ~AVR_PORT;
assign AVR_TRDOS = TRDOS_FLG;
always @(*)
begin
casex({TRDOS_FLG,PROM_FLG,port_7ffd[4]})
'b1xx: ROM_PAGE <= 'b11;
'b01x: ROM_PAGE <= 'b10;
'b001: ROM_PAGE <= 'b01;
'b000: ROM_PAGE <= 'b00;
endcase
case({A14,A15})
'b00 : RAM_PAGE <= 'b000;
'b10 : RAM_PAGE <= 'b101;
'b01 : RAM_PAGE <= 'b010;
'b11 : RAM_PAGE <= port_7ffd[2:0];
endcase
RAM_A14 <= VBUS_MODE == 0 ? RAM_PAGE[0] : 1'b1;
RAM_A15 <= VBUS_MODE == 0 ? RAM_PAGE[1] : port_7ffd[3];
RAM_A16 <= VBUS_MODE == 0 ? RAM_PAGE[2] : 1'b1;
VBUS_REQ <= ( MREQ == 0 || IOREQ == 0 ) && ( WR == 0 || RD == 0 ) ? 1'b0 : 1'b1;
VBUS_RDY <= pixel_clock & ChrC_Cnt[0];
nWR_GATE_EN <= VBUS_MODE == 0 && ((RAM == 0 || (IOREQ == 0 && M1 == 1)) && WR == 0) ? 1'b0 : 1'b1;
mRD <= (VBUS_MODE == 1 && VBUS_RDY == 0) || (VBUS_MODE == 0 && RD == 0 && MREQ == 0) ? 1'b0 : 1'b1;
mWR <= VBUS_MODE == 0 && RAM == 0 && WR == 0 && ChrC_Cnt[0] == 0 ? 1'b0 : 1'b1;
pport_wait <= AVR_WAIT == !AVR_PORT || TRDOS_TGL == 1 ? 1'b1 : 1'b0;
PROM_TGL <= VBUS_MODE == 0 && M1 == 0 && RD == 0 && MREQ == 0 && PROM_FLG == !AVR_PROM ? 1'b1 : 1'b0;
WR_BUF <= VBUS_MODE == 0 && ChrC_Cnt[0] == 0 ? 1'b1 : 1'b0;
if( WR & RD )
AY_PORT <= 1'b0;
else if( VBUS_MODE == 0 && mA[1:0] == 2'b01 && mA[13] == 1 && A15 == 1 && M1 == 1 && IOREQ == 0 )
AY_PORT <= 1'b1;
else if( VBUS_MODE == 0 )
AY_PORT <= 1'b0;
AY_BC1 <= AY_PORT == 1 && A14 == 1 ? 1'b1 : 1'b0;
AY_BDIR <= AY_PORT == 1 && WR == 0 ? 1'b1 : 1'b0;
end
// just moved here to fit
always @(negedge CLK)
begin
TRDOS_TGL <= VBUS_MODE == 0 && M1 == 0 && RD == 0 && MREQ == 0 && (
( TRDOS_FLG == 0 && port_7ffd[4] == 1 && {A15,A14,mA[13:8]} == 'h3D) // enter TR-DOS condition
|| ( TRDOS_FLG == 0 && AVR_PROM == 0 && port_7ffd[4] == 1 && {A15,A14,mA[13:0]} == 'h66 )
|| ( TRDOS_FLG == 1 && (A15 == 1 || A14 == 1 || PROM_FLG == 1) ) // return from TR-DOS
) ? 1'b1 : 1'b0;
paper <= Hor_Cnt[5] == 0 && Ver_Cnt[5] == 0 && ( Ver_Cnt[4] == 0 || Ver_Cnt[3] == 0 ) ? 1'b0 : 1'b1;
hsync <= Hor_Cnt[5:2] == 4'b1010 ? 1'b0 : 1'b1;
vsync1 <= Hor_Cnt[5:1] == 5'b00110 || Hor_Cnt[5:1] == 5'b10100 ? 1'b0 : 1'b1;
vsync2 <= Hor_Cnt[5:2] == 4'b0010 || Hor_Cnt[5:2] == 4'b1001 ? 1'b1 : 1'b0;
end
// generate 7MHz pixelclock
always @(posedge CLK)
pixel_clock <= ~pixel_clock;
// CPU Clock & counters
always @(posedge pixel_clock)
begin
// generate Z80 CLOCK 3.5 MHz
if( ChrC_Cnt[0] == 0 )
begin
if( pport_wait == 0 )
CLK_CPU <= 0;
end
else
CLK_CPU <= 1;
// screen counters
if( ChrC_Cnt == 7 )
begin
if( Hor_Cnt == 55 )
Hor_Cnt <= 0;
else
Hor_Cnt <= Hor_Cnt + 1'b1;
if( Hor_Cnt == 39 )
begin
if( ChrR_Cnt == 7 )
begin
if( Ver_Cnt == 39 )
begin
Ver_Cnt <= 0;
flash_cnt <= flash_cnt + 1'b1;
end
else
Ver_Cnt <= Ver_Cnt + 1'b1;
end
ChrR_Cnt <= ChrR_Cnt + 1'b1;
end
if( Ver_Cnt != 31 )
SYNC <= hsync;
else if( ChrR_Cnt == 3 || ChrR_Cnt == 4 || ( ChrR_Cnt == 5 && ( Hor_Cnt >= 40 || Hor_Cnt < 12 ) ) )
SYNC <= vsync2;
else
SYNC <= vsync1;
end
if( ChrC_Cnt == 6 && Hor_Cnt[2:0] == 'b111 )
begin
if( Ver_Cnt == 29 && ChrR_Cnt == 7 && Hor_Cnt[5:3] == 'b100 )
INT <= 0;
else
INT <= 1;
end
ChrC_Cnt <= ChrC_Cnt + 1'b1;
end
// prepare pixel attributes
always @(posedge pixel_clock)
begin
if( paper_r == 0 )
begin
// show current pixel
if( pixels_buf[7] ^ ( attr_buf[7] & flash_cnt[4] ) )
begin // pixels output
Blue <= attr_buf[0];
Red <= attr_buf[1];
Green <= attr_buf[2];
end
else
begin // attributes output
Blue <= attr_buf[3];
Red <= attr_buf[4];
Green <= attr_buf[5];
end
end
else
begin
if(blank_r == 0 )
begin // blank output
Blue <= 1'bZ;
Red <= 1'bZ;
Green <= 1'bZ;
end
else
begin // border output
Blue <= border_attr[0];
Red <= border_attr[1];
Green <= border_attr[2];
end
end
if( paper_r == 0 && attr_buf[6] == 1 )
Bright <= 1;
else
Bright <= 0;
end
// fetch attributes
always @(negedge pixel_clock)
if( ChrC_Cnt[0] == 1 )
begin
if( VBUS_MODE == 1 )
begin
if( VidRD == 0 )
pixels <= mD;
else
attr <= mD;
end
if( VBUS_REQ == 0 && VBUS_ACK == 1 )
VBUS_MODE <= 0;
else
begin
VBUS_MODE <= 1;
VidRD <= ~VidRD;
end
VBUS_ACK <= VBUS_REQ;
end
// put data to buffers or shift pixel
always @(posedge pixel_clock)
if( ChrC_Cnt == 7 )
begin
attr_buf <= attr;
pixels_buf <= pixels;
if( ((Hor_Cnt[5:0] > 38) && (Hor_Cnt[5:0] < 48)) || Ver_Cnt[5:1] == 15 )
blank_r <= 0;
else
blank_r <= 1;
paper_r <= paper;
end
else
pixels_buf <= pixels_buf << 1;
// Read PORTs
always @(posedge CLK or negedge nCPU_Reset)
if( !nCPU_Reset)
begin
port_7ffd <= 6'b000000;
SOUND_OUT <= 0;
end
else if( pixel_clock == 1 && ChrC_Cnt[0] == 0 && VBUS_MODE == 0 && IOREQ == 0 && M1 == 1)
begin //read ports
// port FD
if( WR == 0 && mA[1] == 0 && A15 == 0 && port_7ffd[5] == 0 )
port_7ffd <= mD[5:0];
// port FE
if( WR == 0 && mA[7:0] == 'b11111110 )
begin
border_attr <= mD[2:0];
SOUND_OUT <= mD[4];
end
end
// Write PORTs
always @(posedge pixel_clock)
begin
if( TRDOS_TGL == 1 )
TRDOS_FLG <= ~TRDOS_FLG;
if( PROM_TGL == 1 )
PROM_FLG <= ~PROM_FLG;
if( IOREQ == 0 )
begin //write ports using AVR
if( VBUS_MODE == 0 && ChrC_Cnt[0] == 0 )
begin
// port FE
if( RD == 0 && mA[7:0] == 'hFE && AVR_NOINT == 1 )
AVR_PORT <= 1;
// port 1F
else if( ( RD == 0 || WR == 0 ) && mA[7:0] == 'h1F )
AVR_PORT <= 1;
// other ports not affected
else
AVR_PORT <= 0;
end
end
else
AVR_PORT <= 0;
end
// Memory address generation
assign mA = VBUS_MODE == 0 ? 14'bZZZZZZZZZZZZZZ :
VidRD == 0 ? {1'b0,Ver_Cnt[4:3],ChrR_Cnt,Ver_Cnt[2:0],Hor_Cnt[4:0]} :
{4'b0110,Ver_Cnt[4:0],Hor_Cnt[4:0]};
endmodule