Pause and Credits based on jtframe by @jotego

I have modified jtframe to adapt it to the characteristics of the core, with 64 characters instead of 32.
This commit is contained in:
Aitor Gómez
2022-12-07 08:19:40 +01:00
parent b6a49879ce
commit 3f0e29f4dd
13 changed files with 18446 additions and 14 deletions

57
PCXT.sv
View File

@@ -319,6 +319,7 @@ module emu
wire VGA_VBlank_border;
wire std_hsyncwidth;
wire pause_core;
always @(posedge CLK_VIDEO)
begin
@@ -1122,7 +1123,8 @@ module emu
.enable_a000h (a000h),
.wait_count_clk_en (~clk_cpu & clk_cpu_ff_2),
.ram_read_wait_cycle (ram_read_wait_cycle),
.ram_write_wait_cycle (ram_write_wait_cycle)
.ram_write_wait_cycle (ram_write_wait_cycle),
.pause_core (pause_core)
);
wire [15:0] SDRAM_DQ_IN;
@@ -1142,7 +1144,7 @@ module emu
.CLK(clk_cpu),
.RESET(reset_cpu),
.READY(processor_ready),
.READY(processor_ready && ~pause_core),
.NMI(1'b0),
.INTR(interrupt_to_cpu),
@@ -1263,8 +1265,8 @@ module emu
cmp_r <= compr(out_r);
end
assign AUDIO_L = status[37:36] ? cmp_l : out_l;
assign AUDIO_R = status[37:36] ? cmp_r : out_r;
assign AUDIO_L = pause_core ? 1'b0 : status[37:36] ? cmp_l : out_l;
assign AUDIO_R = pause_core ? 1'b0 : status[37:36] ? cmp_r : out_r;
assign AUDIO_S = 1;
assign AUDIO_MIX = status[39:38];
@@ -1489,6 +1491,12 @@ module emu
assign CE_PIXEL = ce_pixel;
*/
wire LHBL = border_video_ff ? HBlank_fixed : HBlank_VGA;
wire LVBL = border_video_ff ? std_hsyncwidth ? VGA_VBlank_border : ~VSync : VBlank;
wire pre2x_LHBL, pre2x_LVBL;
wire [7:0] pre2x_r, pre2x_g, pre2x_b;
video_mixer #(.GAMMA(1)) video_mixer_cga
(
@@ -1500,12 +1508,12 @@ module emu
.freeze_sync(),
.R(raux_cga),
.G(gaux_cga),
.B(baux_cga),
.R(pre2x_r),
.G(pre2x_g),
.B(pre2x_b),
.HBlank(border_video_ff ? HBlank_fixed : HBlank_VGA),
.VBlank(border_video_ff ? std_hsyncwidth ? VGA_VBlank_border : ~VSync : VBlank),
.HBlank(pre2x_LHBL),
.VBlank(pre2x_LVBL),
.HSync(HSync),
.VSync(VSync),
@@ -1641,6 +1649,37 @@ module emu
// .mosi (vsdMosi ),
// .miso (vsdMiso )
// );
jtframe_credits #(
.PAGES (4),
.COLW (8),
.BLKPOL (1)
) u_credits(
.rst ( reset ),
.clk ( clk_chipset ), // alt: CLK_VIDEO_CGA
.pxl_cen ( CE_PIXEL_cga ), // alt: ce_pixel_cga
// input image
.HB ( LHBL ),
.VB ( LVBL ),
.rgb_in ( { raux_cga, gaux_cga, baux_cga } ),
.rotate ( 2'd0 ),
.toggle ( 1'b0 ),
.fast_scroll( 1'b0 ),
.border ( border_video_ff ),
.vram_din ( 8'h0 ),
.vram_dout ( ),
.vram_addr ( 8'h0 ),
.vram_we ( 1'b0 ),
.vram_ctrl ( 3'b0 ),
.enable ( pause_core ),
// output image
.HB_out ( pre2x_LHBL ),
.VB_out ( pre2x_LVBL ),
.rgb_out ( {pre2x_r, pre2x_g, pre2x_b } )
);
endmodule

4
credits/Makefile Normal file
View File

@@ -0,0 +1,4 @@
programs = msg2hex
all: $(programs)

111
credits/msg Normal file
View File

@@ -0,0 +1,111 @@
\R * ( ( )
\R ( ` )\\ ) * ) )\\ ) ( ( /( * )
\R )\\))( ( (()/(` ) /( ( ( (()/( )\\ )\\())` ) /(
\R ((_)()\\ )\\ /(_))( )(_))))\\ )( /(_)|((_)((_)\\ ( )(_))
\W (_()((_|(_|_)) (_(_())/((_|()\\ (_)) )\\_____((_)(_(_())
\W | \\/ |(_) __||_ _(_)) ((_) | _ ((/ __\\ \\/ /|_ _|
\W | |\\/| || \\__ \\ | | / -_)| '_| | _/| (__ > < | |
\W |_| |_||_|___/ |_| \\___||_| |_| \\___/_/\\_\\ |_|
\W & Tandy 1000 by \Gspark2k06
Aitor Gomez Garcia
https://ko-fi.com/spark2k06
\BPOWERED BY
KFPC-XT * kitune-san
https://github.com/kitune-san
MCL86 * Ted Fried
http://www.microcorelabs.com/
GraphicsGremlin * TubeTime
https://tubetime.us/
\BALSO
JTOPL * JT89 * JTCREDITS
Jose Tejada (jotego)
https://www.patreon.com/jotego
MS Mouse PS2 to Serial
Antonio Sanchez (TheSonders)
https://github.com/TheSonders
SAA1099 (Tandy Sound)
Dave Hooper (stripwax)
https://github.com/stripwax
SAA1099 (Tandy Sound)
Miguel Angel Rodriguez Jodar (mcleod-ideafix)
https://github.com/mcleod-ideafix
2 Button Analog Joysticks
Flandango
https://github.com/Flandango
UART 16750
Sebastian Witt
https://opencores.org/users/hasw/profile
Other ao486-based modules
Alexey Melnikov (sorgelig)
https://www.patreon.com/FPGAMiSTer
______________________________________________________________
\BDEVELOPERS \W& \GCO-WORKERS
Aitor Gomez Garcia (spark2k06)
kitune-san
Ted Fried (MicroCoreLabs)
somhi
David Gila Blazquez (Mills)
flynnsbit
Jason Alexander (JasonA)
Newsdee
birdybro
Pedro Gimeno (pgimeno)
Jordi Segura (Jordi)
______________________________________________________________
\BSpecial Thanks
https://www.xtideuniversalbios.org/
https://www.lo-tech.co.uk
https://github.com/640-KB/GLaBIOS
https://github.com/virtualxt/pcxtbios
https://github.com/skiselev/8088_bios
Alejandro Valero Sebastian (Wilco2009)
naeloob
gyurco
______________________________________________________________
\BThanks for supporting this project!!!
Adr1048
TonyEscobar
Kathleen
Jordi Segura (Jordi)
thorr
Caldor
______________________________________________________________
\RReport issues to
https://github.com/MiSTer-devel/PCXT_MiSTer/issues
\BSome Known Issues
* The AREA5150 demo has graphical glitches.
* More than the standard 16 colours of simulated
composite video are not displayed reliably.
* Timing issues mean that the image may not display well on
CRTs and some vertical line shifts to the right of the
image, such as 640x400x4 and sometimes 320x200x16.

105
credits/msg2hex.cc Normal file
View File

@@ -0,0 +1,105 @@
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <ctype.h>
using namespace std;
void parse_line( int *buf, ifstream& fin );
int main( int argc, char *argv[] ) {
if( argc != 2 ) {
cout << "ERROR: expecting .msg filename\n";
return 1;
}
string fname( argv[1] );
ifstream fin( fname );
if( !fin.good() ) {
cout << "ERROR: cannot open file " << fname << '\n';
return 2;
}
// Parse file
int *buf = new int[16*1024]; // Max 16 kB
for(int k=0; k<16*1024; k++ ) buf[k]=0;
int *pline = buf;
int line=0;
try {
while( !fin.eof() ) {
parse_line( pline, fin );
pline += 0x40;
if( pline-buf >= 16*1024 ) {
throw "ERROR: file is too long for 16kB ";
}
line++;
}
// Dump the contents
ofstream fout( "msg.hex" );
for( int k=0; k<16*1024; k++ ) {
fout << hex << buf[k] << '\n';
}
fout.close();
fout.open( "msg.bin" );
for( int k=0; k<16*1024; k++ ) {
int v = buf[k];
for( int bit=0; bit<9; bit++ ) {
if( v&0x100 ) fout << '1'; else fout << '0';
v<<=1;
}
fout << '\n';
}
} catch( const char* error ) {
cout << "ERROR: " << error << "at line " << dec << (line+1) << '\n';
delete []buf;
return 3;
}
delete []buf;
return 0;
}
void parse_line( int *buf, ifstream& fin ) {
string line;
getline( fin, line );
int pal=3;
bool brk=false;
int cnt=0;
for( int i : line ) {
if( brk ) {
if( i=='\\' ) {
brk = false;
}
else {
switch( toupper(i) ) {
case 'R': pal=0; break;
case 'G': pal=1; break;
case 'B': pal=2; break;
case 'W': pal=3; break;
default: {
throw "ERROR: invalid palette code ";
}
}
brk = false;
// cout << pal << '\n';
continue;
}
}
else if( i=='\\' ) {
// cout << "BRK";
brk=true;
continue;
}
// actual chars
if( cnt++ == 64 ) {
throw "line is longer than 64 characters, ";
}
if( i<0x20 || i>0x7f ) {
throw "character code out of range ";
}
int v = i-0x20;
v&=0x7f;
v |= pal<<7;
*buf++ = v;
}
}

View File

@@ -153,7 +153,8 @@ module CHIPSET (
// RAM wait mode
input logic wait_count_clk_en,
input logic [1:0] ram_read_wait_cycle,
input logic [1:0] ram_write_wait_cycle
input logic [1:0] ram_write_wait_cycle,
output logic pause_core
);
logic [19:0] latch_address;
@@ -367,7 +368,8 @@ module CHIPSET (
.fdd_dma_req (fdd_dma_req),
.fdd_dma_ack (~dma_acknowledge_n[2]),
.terminal_count (terminal_count_n),
.xtctl (xtctl)
.xtctl (xtctl),
.pause_core (pause_core)
);
RAM u_RAM

View File

@@ -16,7 +16,8 @@ module KFPS2KB #(
output logic irq,
output logic [7:0] keycode,
input logic clear_keycode
input logic clear_keycode,
output reg pause_core = 1'b0
);
//
// Internal Signals
@@ -246,6 +247,19 @@ module KFPS2KB #(
keycode <= 8'h00;
break_flag <= 1'b1;
end
else if (register == 8'h07) begin
// F12 -> Pause core and credits
irq <= 1'b0;
keycode <= 8'h00;
break_flag <= 1'b0;
pause_core <= break_flag ? ~pause_core : pause_core;
end
else if (pause_core) begin
// The core is paused and the credits are visible
irq <= 1'b0;
keycode <= 8'h00;
break_flag <= 1'b0;
end
else begin
// Make code
irq <= 1'b1;

View File

@@ -121,7 +121,8 @@ module PERIPHERALS #(
input logic fdd_dma_ack,
input logic terminal_count,
// XTCTL DATA
output logic [7:0] xtctl = 8'h00
output logic [7:0] xtctl = 8'h00,
output logic pause_core
);
wire [4:0] clkdiv;
@@ -442,7 +443,8 @@ module PERIPHERALS #(
// I/O
.irq (keybord_irq),
.keycode (keycode),
.clear_keycode (clear_keycode)
.clear_keycode (clear_keycode),
.pause_core (pause_core)
);
// Keybord reset

View File

@@ -8,3 +8,6 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) MSMouse
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ide.v ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) bram.vhd ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) tandy_pcjr_joy.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_credits.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_ram.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtframe_dual_ram.v ]

1024
rtl/common/font0.hex Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,446 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-3-2020 */
// 8x8 tiles
module jtframe_credits #(
parameter PAGES = 1,
COLW = 4, // bits per pixel colour component
parameter [11:0] PAL0 = { 4'hf, 4'h0, 4'h0 }, // Red
parameter [11:0] PAL1 = { 4'h0, 4'hf, 4'h0 }, // Green
parameter [11:0] PAL2 = { 4'h3, 4'h3, 4'hf }, // Blue
parameter [11:0] PAL3 = { 4'hf, 4'hf, 4'hf }, // White
parameter BLKPOL = 1'b1, // Blanking polarity
parameter SPEED = 2 // scroll speed
) (
input rst,
input clk,
// input image
input pxl_cen,
input HB,
input VB,
input [COLW*3-1:0] rgb_in,
// Optional VRAM control
input [8:0] vram_din,
input [9:0] vram_addr,
input vram_we,
output [8:0] vram_dout,
// control
input enable, // shows the screen and resets the scroll counter
input toggle, // disables the screen. Only has an effect if enable is high
input [2:0] vram_ctrl,
input fast_scroll,
input [1:0] rotate,
input border,
// output image
output reg HB_out,
output reg VB_out,
output reg [COLW*3-1:0] rgb_out
);
localparam MSGW = PAGES == 1 ? 11 :
(PAGES == 2 ? 12 :
(PAGES > 2 && PAGES <=4 ? 13 :
(PAGES > 5 && PAGES <=8 ? 14 : 15 ))); // Support for upto 16 pages
localparam VPOSW = MSGW-2;
localparam HPOSW = 10;
localparam _MAXVISIBLE = PAGES*24*8-1; // workaround to avoid a warning
localparam [VPOSW-1:0] MAXVISIBLE = _MAXVISIBLE[VPOSW-1:0];
localparam [HPOSW-1:0] HSTART = 0, HEND = 514;
wire [HPOSW-1:0] hoffset = 64 + (border ? 73 : 0);
reg [HPOSW-1:0] hn;
wire [HPOSW-1:0] hscan;
reg [VPOSW-1:0] scrpos, vdump, vdump1;
reg [8:0] vrender;
wire [8:0] scan_data;
wire [7:0] font_data;
reg [MSGW-1:0] scan_addr;
wire [9:0] font_addr = {scan_data[6:0],
rotate==2'b11 ? (~vdump[2:0]+3'd1) : vdump[2:0] };
wire visible = vrender < MAXVISIBLE;
reg last_toggle, last_enable;
reg show, hide;
wire vram_mode = vram_ctrl[0];
wire vram_nc;
assign hscan = hn - hoffset;
jtframe_dual_ram #(.dw(10), .aw(MSGW),.synfile("msg.bin"),.ascii_bin(1)) u_msg(
.clk0 ( clk ),
.clk1 ( clk ),
// Port 0: optional write access
.data0 ( {1'b1, vram_din } ),
.addr0 ( { {MSGW-10{1'b0}}, vram_addr } ),
.we0 ( vram_we ),
.q0 ( { vram_nc, vram_dout } ),
// Port 1: video dump
.data1 ( 10'd0 ),
.addr1 ( scan_addr ),
.we1 ( 1'b0 ),
.q1 ( scan_data )
);
jtframe_ram #(.aw(10),.synfile("font0.hex")) u_font(
.clk ( clk ),
.cen ( 1'b1 ),
.data ( 8'd0 ),
.addr ( font_addr ),
.we ( 1'b0 ),
.q ( font_data )
);
reg [1:0] pal;
reg [2:0] pxl;
localparam MULTIPAGE = MSGW > 11;
// hb and vb are always active high
wire hb = BLKPOL ? HB : ~HB;
wire vb = BLKPOL ? VB : ~VB;
reg [7:0] pxl_data;
wire tate = rotate[0],
tate_flip = rotate==2'b11;
reg last_hb, last_vb;
reg [3:0] scr_base;
wire hb_edge = hb && !last_hb;
always @(posedge clk) if(pxl_cen) begin
if( tate || hb_edge ) begin
vdump1 <= scrpos + (tate ? hscan : vrender);
vdump <= vdump1;
end
end
wire [VPOSW-1:3] vidx_flip = (~vdump[VPOSW-1:3])+1'd1;
always @(posedge clk) begin
if( rst ) begin
hn <= HSTART;
scrpos <= {VPOSW{1'b0}};
vrender <= 8'd0;
scr_base <= 4'd0;
end else if(pxl_cen) begin
last_hb <= hb;
last_vb <= vb;
if( hb_edge ) begin
vrender <= vrender + 8'd1;
end
hn <= hb ? HSTART : hn+9'd1;
// scrpos: scroll counter
// gets reset each time the pause button is pressed
if( enable && !last_enable ) begin
scrpos <= tate_flip ? MAXVISIBLE : {VPOSW{1'b0}};
end else begin
if ( vb ) begin
vrender <= 0;
if( !last_vb && MULTIPAGE ) begin
// Scroll runs at max speed when the visible pages are over
// otherwise it runs at SPEED
if( scr_base == SPEED || (scrpos > MAXVISIBLE && scrpos < (MAXVISIBLE << 2)) || fast_scroll ) begin
scrpos <= tate_flip ? (scrpos-1'b1) : (scrpos + 1'b1);
scr_base <= 4'd0;
end else scr_base <= scr_base + 4'd1;
end
end
end
if( vram_mode ) scrpos <= 0;
//if( /*tate || hn[2:0]==3'd0 || hb || vb ) begin
scan_addr <= tate ?
{ rotate[1] ? vidx_flip : vdump[VPOSW-1:3], vrender[7:3]^{5{~rotate[1]}} } :
{ vdump[VPOSW-1:3], hscan[8:3] };
//end
// Draw
if( tate ) begin
pxl <= { scan_data[8:7], font_data[ vrender[2:0] ^{3{rotate[1]}} ] };
end else begin
pxl <= { pal, pxl_data[7] };
if( hscan[2:0]==3'd1 ) begin
pal <= scan_data[8:7];
pxl_data <= font_data;
end else begin
pxl_data <= pxl_data << 1;
end
end
end
end
//////////////////////////////////////////////////////////////////////////////
// Object Generator
`ifdef JTFRAME_AVATARS
reg [ 7:0] buf_din;
reg buf_we0, buf_we1;
reg [ 7:0] buf_addr0;
reg [11:0] lut_addr;
wire [ 7:0] lut_data;
reg [12:0] obj_addr;
wire [15:0] obj_data;
wire [ 7:0] pal_addr;
wire [11:0] pal_data;
reg [11:0] obj_pxl;
reg [ 7:0] obj_id, obj_x, obj_y;
reg line = 1'b0;
jtframe_dual_ram #(.dw(8), .aw(9)) u_linebuffer(
.clk0 ( clk ),
.clk1 ( clk ),
// Port 0: new data writes
.data0 ( buf_din ),
.addr0 ( { line, buf_addr0 } ),
.we0 ( buf_we0 ),
.q0 ( ),
// Port 1
.data1 ( ~8'd0 ),
.addr1 ( { ~line, hscan[7:0] } ),
.we1 ( buf_we1 ),
.q1 ( pal_addr )
);
jtframe_ram #(.dw(8), .aw(12),.synfile("lut.hex")) u_lut(
.clk ( clk ),
.cen ( 1'b1 ),
.data ( 8'd0 ),
.addr ( lut_addr ),
.we ( 1'b0 ),
.q ( lut_data )
);
jtframe_ram #(.dw(16), .aw(13),.synfile("avatar.hex")) u_obj(
.clk ( clk ),
.cen ( 1'b1 ),
.data ( 16'd0 ),
.addr ( obj_addr ),
.we ( 1'b0 ),
.q ( obj_data )
);
jtframe_ram #(.dw(12), .aw(4+4),.synfile("avatar_pal.hex")) u_pal(
.clk ( clk ),
.cen ( 1'b1 ),
.data ( 12'd0 ),
.addr ( pal_addr ),
.we ( 1'b0 ),
.q ( pal_data )
);
wire [VPOSW-1:0] vsub = vdump1 - { lut_data, 3'b0 };
reg [3:0] obj_pal;
reg [3:0] x,y,z,w;
reg [4:0] st;
reg first;
reg last_hb2; // this is one is not gated by pxl_cen
always @(posedge clk) begin
last_hb2 <= hb;
if( hb && !last_hb2 ) begin
lut_addr <= 12'd0;
first <= 1'b1;
st <= 0;
line <= ~line;
buf_we0 <= 1'b0;
buf_addr0<= 8'd0;
end else begin
st <= st+1;
case( st )
0: begin
if( lut_addr==12'd0 && !first ) st <= 0;
end
1: begin
lut_addr <= lut_addr + 12'd1;
first <= 1'b0;
end
2: begin
lut_addr <= lut_addr + 12'd1;
obj_id <= lut_data;
end
3: begin
lut_addr <= lut_addr + 12'd1;
obj_x <= lut_data;
end
4: begin
lut_addr <= lut_addr + 12'd1;
obj_y <= lut_data;
obj_addr <= { obj_id[6:0], vsub[3:0], 2'b0 }; // 7+4+2 = 13
if( !({lut_data,3'b0} <= vdump1 && {lut_data,3'b0}+16 > vdump1) ) st <= 0;
if( obj_id==8'hff ) begin // end of LUT
lut_addr <= 12'd0;
st <= 0;
end
end
5: obj_pal <= lut_data;
6: begin
buf_addr0 <= { obj_x-8'd1, 3'b111 };
{z,y,x,w} <= obj_data;
obj_addr[1:0] <= 2'b01;
end
7,8,9,10, 12,13,14,15,
17,18,19,20, 22,23,24,25: begin
buf_addr0 <= buf_addr0 + 1;
// xywz
// wxyz
// zyxw
// zywx
// zwyx
// zwxy
buf_din <= { obj_pal, z[3],y[3],x[3],w[3] };
buf_we0 <= 1'b1;
obj_x <= obj_x + 1;
x <= x << 1;
y <= y << 1;
z <= z << 1;
w <= w << 1;
end
11: begin
{z,y,x,w} <= obj_data;
obj_addr[1:0] <= 2'b10;
end
16: begin
{z,y,x,w} <= obj_data;
obj_addr[1:0] <= 2'b11;
end
21: {z,y,x,w} <= obj_data;
26: begin
buf_we0<= 1'b0;
st <= 0;
end
endcase
end
end
reg rd=1'b0;
reg [ 2:0] st2=3'd0;
reg obj_ok;
always @(posedge clk ) begin
st2 <= st2+1;
case( st2 )
3: begin
obj_pxl <= pal_data;
obj_ok <= pal_addr[3:0] != 4'hf; // visible pixel
buf_we1 <= !hscan[9]; // do not empty the line buffer when
// scanning the left side of the screen
// This applies when JTFRAME_CREDITS_HSTART!=0
end
4: begin
buf_we1 <= 1'b0;
if( pxl_cen ) st2 <= 0; else st2 <= 4;
end
endcase
end
`else
wire [11:0] obj_pxl = ~12'h0;
wire obj_ok = 1'b0;
`endif
/////////////////////////////////////////////////////////////////////////////
// Colour Mixer
// Merge the new image with the old
localparam R1 = COLW*3-1;
localparam R0 = COLW*2;
localparam G1 = COLW*2-1;
localparam G0 = COLW;
localparam B1 = COLW-1;
localparam B0 = 0;
wire [COLW*3-1:0] dim = { 1'b0, rgb_in[R1:R0+1], 1'b0, rgb_in[G1:G0+1], 1'b0, rgb_in[B1:B0+1] };
function [COLW*3-1:0] extend;
input [11:0] rgb4;
extend =
COLW==5 ? {
rgb4[11:8], rgb4[11],
rgb4[7:4], rgb4[7],
rgb4[3:0], rgb4[3]
} : (
COLW==4 ? rgb4 :
{
rgb4[11:8], rgb4[11:8],
rgb4[7:4], rgb4[7:4],
rgb4[3:0], rgb4[3:0]
});
endfunction
always @(posedge clk, posedge rst) begin
if( rst ) begin
show <= 0;
hide <= 0;
last_toggle <= 0;
last_enable <= 0;
end else begin
last_enable <= enable;
last_toggle <= toggle;
if( enable ) begin
if( vram_mode ) begin
show <= 1;
hide <= 0;
end else begin
show <= ~hide;
if( toggle && !last_toggle ) begin
hide <= ~hide;
end
end
end else show <= 0;
end
end
always @(posedge clk) if(pxl_cen) begin
{ HB_out, VB_out } <= { HB, VB };
// if hoffset != 0 and the game is vertical, the full horizontal length
// of the screen is used. Otherwise, the credits will start at hoffset
// and last for 512 pixels
if( !show || ( hoffset!=0 && !tate && (hn<hoffset || hn>=(HEND+hoffset))) )
rgb_out <= rgb_in;
else begin
if( (!pxl[0] && (!obj_ok || vram_mode)) || !visible ) begin
if( vram_ctrl[0] ) begin
rgb_out <= (vdump[7] ? vram_ctrl[2] : vram_ctrl[1]) ? dim : rgb_in;
end else begin
rgb_out <= dim;
end
end else begin
if( pxl[0] || tate ) begin // CHAR, OBJ disabled for TATE
case( pxl[2:1] )
2'd0: rgb_out <= extend(PAL0);
2'd1: rgb_out <= extend(PAL1);
2'd2: rgb_out <= extend(PAL2);
2'd3: rgb_out <= extend(PAL3);
endcase
end else rgb_out <= extend(obj_pxl); // OBJ
end
if( vb || hb ) rgb_out <= 0;
end
end
endmodule

View File

@@ -0,0 +1,217 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2017 */
// Generic dual port RAM with clock enable
// parameters:
// dw => Data bit width, 8 for byte-based memories
// aw => Address bit width, 10 for 1kB
// simfile => binary file to load during simulation
// simhexfile => hexadecimal file to load during simulation
// synfile => hexadecimal file to load for synthesis
/* verilator lint_off MULTIDRIVEN */
module jtframe_dual_ram #(parameter dw=8, aw=10,
simfile="", simhexfile="",
synfile="",
ascii_bin=0, // set to 1 to read the ASCII file as binary
dumpfile="dump.hex"
)(
// Port 0
input clk0,
input [dw-1:0] data0,
input [aw-1:0] addr0,
input we0,
output [dw-1:0] q0,
// Port 1
input clk1,
input [dw-1:0] data1,
input [aw-1:0] addr1,
input we1,
output [dw-1:0] q1
`ifdef JTFRAME_DUAL_RAM_DUMP
,input dump
`endif
);
jtframe_dual_ram_cen #(
.dw ( dw ),
.aw ( aw ),
.simfile ( simfile ),
.simhexfile ( simhexfile),
.synfile ( synfile ),
.ascii_bin ( ascii_bin ),
.dumpfile ( dumpfile )
) u_ram (
.clk0 ( clk0 ),
.cen0 ( 1'b1 ),
.clk1 ( clk1 ),
.cen1 ( 1'b1 ),
// Port 0
.data0 ( data0 ),
.addr0 ( addr0 ),
.we0 ( we0 ),
.q0 ( q0 ),
// Port 1
.data1 ( data1 ),
.addr1 ( addr1 ),
.we1 ( we1 ),
.q1 ( q1 )
`ifdef JTFRAME_DUAL_RAM_DUMP
,.dump ( dump )
`endif
);
endmodule
module jtframe_dual_ram_cen #(parameter dw=8, aw=10,
simfile="", simhexfile="",
synfile="",
ascii_bin=0, // set to 1 to read the ASCII file as binary
dumpfile="dump.hex"
)(
input clk0,
input cen0,
input clk1,
input cen1,
// Port 0
input [dw-1:0] data0,
input [aw-1:0] addr0,
input we0,
output [dw-1:0] q0,
// Port 1
input [dw-1:0] data1,
input [aw-1:0] addr1,
input we1,
output [dw-1:0] q1
`ifdef JTFRAME_DUAL_RAM_DUMP
,input dump
`endif
);
`ifdef SIMULATION
localparam SIMULATION=1;
`else
localparam SIMULATION=0;
`endif
`ifdef POCKET
localparam POCKET=1;
`else
localparam POCKET=0;
`endif
generate
if( !SIMULATION && POCKET && aw<13 && dw<=8 ) begin
jtframe_pocket_dualram u_pocket_ram(
.address_a( addr0 ),
.address_b( addr1 ),
.clock_a ( clk0 ),
.clock_b ( clk1 ),
.data_a ( data0 ),
.data_b ( data1 ),
.enable_a ( cen0 ),
.enable_b ( cen1 ),
.wren_a ( we0 ),
.wren_b ( we1 ),
.q_a ( q0 ),
.q_b ( q1 )
);
end else begin
reg [dw-1:0] qq0, qq1;
(* ramstyle = "no_rw_check" *) reg [dw-1:0] mem[0:(2**aw)-1];
assign { q0, q1 } = { qq0, qq1 };
always @(posedge clk0) if(cen0) begin
qq0 <= mem[addr0];
if(we0) mem[addr0] <= data0;
end
always @(posedge clk1) if(cen1) begin
qq1 <= mem[addr1];
if(we1) mem[addr1] <= data1;
end
/* verilator lint_off WIDTH */
`ifdef SIMULATION
// Content dump for simulation debugging
`ifdef JTFRAME_DUAL_RAM_DUMP
integer fdump=0, dumpcnt;
always @(posedge dump) begin
$display("INFO: contents dumped to %s", dumpfile );
if( fdump==0 )begin
fdump=$fopen(dumpfile,"w");
end
for( dumpcnt=0; dumpcnt<2**aw; dumpcnt=dumpcnt+1 )
$fdisplay(fdump,"%X", mem[dumpcnt]);
end
`endif
integer f, readcnt;
initial begin
for( f=0; f<(2**aw)-1;f=f+1) begin
mem[f] = 0;
end
if( simfile != "" ) begin
f=$fopen(simfile,"rb");
if( f != 0 ) begin
readcnt=$fread( mem, f );
$display("INFO: Read %14s (%4d bytes/%2d%%) for %m",
simfile, readcnt, readcnt*100/(2**aw));
if( readcnt != 2**aw )
$display(" the memory was not filled by the file data");
$fclose(f);
end else begin
$display("WARNING: %m cannot open file: %s", simfile);
end
end
else begin
if( simhexfile != "" ) begin
$readmemh(simhexfile,mem);
$display("INFO: Read %14s (hex) for %m", simhexfile);
end else begin
if( synfile!= "" ) begin
if( ascii_bin==1 )
$readmemb(synfile,mem);
else
$readmemh(synfile,mem);
$display("INFO: Read %14s (hex) for %m", synfile);
end else
for( readcnt=0; readcnt<2**aw; readcnt=readcnt+1 )
mem[readcnt] = {dw{1'b0}};
end
end
end
`else
// file for synthesis:
initial if(synfile!="" ) begin
if( ascii_bin==1 )
$readmemb(synfile,mem);
else
$readmemh(synfile,mem);
end
`endif
end
endgenerate
/* verilator lint_on WIDTH */
endmodule
/* verilator lint_on MULTIDRIVEN */

81
rtl/common/jtframe_ram.v Normal file
View File

@@ -0,0 +1,81 @@
/* This file is part of JTFRAME.
JTFRAME program 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.
JTFRAME program 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 JTFRAME. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2017 */
// Generic RAM with clock enable
// parameters:
// dw => Data bit width, 8 for byte-based memories
// aw => Address bit width, 10 for 1kB
// simfile => binary file to load during simulation
// simhexfile => hexadecimal file to load during simulation
// synfile => hexadecimal file to load for synthesis
// cen_rd => Use clock enable for reading too, by default it is used
// only for writting.
module jtframe_ram #(parameter dw=8, aw=10,
simfile="", simhexfile="",
synfile="", synbinfile="",
cen_rd=0)(
input clk,
input cen /* direct_enable */,
input [dw-1:0] data,
input [aw-1:0] addr,
input we,
output reg [dw-1:0] q
);
(* ramstyle = "no_rw_check" *) reg [dw-1:0] mem[0:(2**aw)-1];
`ifdef SIMULATION
integer f, readcnt;
initial
if( simfile != 0 ) begin
f=$fopen(simfile,"rb");
if( f != 0 ) begin
readcnt=$fread( mem, f );
$display("INFO: Read %14s (%4d bytes) for %m",simfile, readcnt);
$fclose(f);
end else begin
$display("WARNING: %m cannot open file: %s", simfile);
end
end
else begin
if( simhexfile != 0 ) begin
$readmemh(simhexfile,mem);
$display("INFO: Read %14s (hex) for %m", simhexfile);
end else begin
if( synfile != 0 ) begin
$readmemh(synfile,mem);
$display("INFO: Read %14s for %m", synfile);
end else
for( readcnt=0; readcnt<(2**aw)-1; readcnt=readcnt+1 )
mem[readcnt] = {dw{1'b0}};
end
end
`else
// file for synthesis:
initial if(synfile!=0 )$readmemh(synfile,mem);
initial if(synbinfile!=0 )$readmemb(synbinfile,mem);
`endif
always @(posedge clk) begin
if( !cen_rd || cen ) q <= mem[addr];
if( cen && we) mem[addr] <= data;
end
endmodule

16384
rtl/common/msg.bin Normal file

File diff suppressed because it is too large Load Diff