aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@trantor.hos.anvin.org>2010-09-18 23:01:51 -0700
committerH. Peter Anvin <hpa@trantor.hos.anvin.org>2010-09-18 23:01:51 -0700
commitcfae781bf19c4a5e2faa88d25f1bd56cba82f2ab (patch)
tree255d52e84e39e0678e7f56b27aa1eb312f0bd1dd
parenta378cfc8700a22c4be05a44b4e110241760318e9 (diff)
downloadabc80-cfae781bf19c4a5e2faa88d25f1bd56cba82f2ab.tar.gz
abc80-cfae781bf19c4a5e2faa88d25f1bd56cba82f2ab.tar.xz
abc80-cfae781bf19c4a5e2faa88d25f1bd56cba82f2ab.zip
Make the "high-resolution" graphics unit work (sort of...)
Make the high-resolution graphics unit actually work... at least with 80-character text display. It still doesn't seem to work for a 40-character test display.
-rw-r--r--abc80.v85
-rwxr-xr-xdata/fgcol.pl9
-rwxr-xr-xdata/mmuinit.pl4
-rw-r--r--display.v67
-rw-r--r--mega/fgcolrom.v18
5 files changed, 149 insertions, 34 deletions
diff --git a/abc80.v b/abc80.v
index 0497c8e..9edbef5 100644
--- a/abc80.v
+++ b/abc80.v
@@ -250,6 +250,52 @@ module abc80 (
);
// ------------------------------------------------------------------------
+ // FG graphics controller - data counters
+ //
+ // These counters are here so they run in the cpu_clk clock domain
+ // -- necessary to multiplex with the SRAM.
+ // ------------------------------------------------------------------------
+
+ reg [5:0] fgxaddr; // Byte address horizontally
+ reg [8:0] fgyaddr; // Byte address vertically (bit 0 ignored)
+ reg [7:0] fgdata;
+ wire fgxrst;
+ reg [1:0] fgxrst_q;
+ wire fgyrst;
+ reg [1:0] fgyrst_q;
+ wire fgack;
+ reg [1:0] fgack_q;
+ reg [7:0] fgctl;
+ reg [4:0] fgpage; // Which 16K page in SRAM
+
+ always @(posedge cpu_clk)
+ fgack_q <= { fgack_q[0], fgack };
+
+ always @(posedge cpu_clk)
+ fgxrst_q <= { fgxrst_q[0], fgxrst };
+
+ always @(posedge cpu_clk)
+ fgyrst_q <= { fgyrst_q[0], fgyrst };
+
+ always @(posedge cpu_clk)
+ begin
+ if (fgxrst_q[0] & ~fgxrst_q[1])
+ fgxaddr <= ~6'h00; // The first ACK will advance this to 0
+ else if (fgack_q[0] & ~fgack_q[1])
+ fgxaddr <= fgxaddr + 1;
+
+ if (fgyrst_q[0] & ~fgyrst_q[1])
+ fgyaddr <= 8'h00;
+ else if (fgxrst_q[0] & ~fgxrst_q[1])
+ fgyaddr <= fgyaddr + 1;
+ end // always @(posedge cpu_clk)
+
+ // fgyaddr[0] ignored due to double-scanning
+ wire [18:0] sram_fgaddr = { fgpage, fgyaddr[8:1], fgxaddr };
+
+ wire sram_fgreq = fgack_q[0] & ~fgack_q[1];
+
+ // ------------------------------------------------------------------------
// Video controller
// ------------------------------------------------------------------------
@@ -299,7 +345,13 @@ module abc80 (
.gd ( chargen_d[5:0] ),
.rgb ( rgb ),
.vsync ( vga_vs ),
- .hsync ( vga_hs )
+ .hsync ( vga_hs ),
+
+ .fg_ctl ( fgctl ),
+ .fg_data ( fgdata ),
+ .fg_ack ( fgack ),
+ .fg_xrst ( fgxrst ),
+ .fg_yrst ( fgyrst )
);
assign vga_r = {4{rgb[2]}};
@@ -321,12 +373,12 @@ module abc80 (
wire sram_we_w;
reg sram_we_q1;
reg sram_we_q2;
+ reg sram_fgrd;
// Are we actually accessed by the CPU?
wire sram_cpu = msel[0] & cpu_clk_en;
- assign sram_ce_n = ~sram_cpu;
- assign sram_oe_w = sram_cpu & ~cpu_rd_n;
+ assign sram_oe_w = (sram_cpu & ~cpu_rd_n) | sram_fgrd;
assign sram_we_w = sram_cpu & ~cpu_wr_n;
always @(negedge rst_n or posedge fast_clk)
@@ -345,13 +397,14 @@ module abc80 (
// The address to drive onto the bus. This is a placeholder for
// multiplexing with the Fine Graphics unit.
- wire [18:0] sram_addr = sram_cpu ? mmu_a[18:0] : 19'h7ffff;
+ wire [18:0] sram_addr = sram_cpu ? mmu_a[18:0] : sram_fgaddr;
// Driving output pins.
assign sram_a = sram_addr[18:1];
assign sram_be_n = sram_addr[0] ? ~2'b10 : ~2'b01;
+ assign sram_ce_n = ~(sram_cpu | sram_fgrd);
assign sram_oe_n = ~sram_oe_w;
assign sram_we_n = ~(sram_we_w & ~sram_we_q2);
@@ -360,6 +413,15 @@ module abc80 (
// SRAM Input side MUX
assign sram_do = sram_addr[0] ? sram_dq[15:8] : sram_dq[7:0];
+ always @(posedge cpu_clk)
+ if (sram_fgreq)
+ sram_fgrd <= 1'b1;
+ else if (sram_fgrd & ~sram_cpu)
+ begin
+ sram_fgrd <= 1'b0;
+ fgdata <= sram_do;
+ end
+
// ------------------------------------------------------------------------
// External flash ROM
// Note: the flash ROM is a 70 ns part. With MMU delays, we have about
@@ -806,7 +868,10 @@ module abc80 (
prog_s7_0 <= 0;
prog_s7_1 <= 0;
- intio_do <= ~8'b0;
+ intio_do <= ~8'b0;
+
+ fgctl <= 8'h00;
+ fgpage <= 5'h04;
end
else
begin
@@ -834,6 +899,10 @@ module abc80 (
prog_s7_0 <= cpu_do[7:0];
5'b10111:
prog_s7_1 <= cpu_do[7:0];
+ 5'b11110:
+ fgctl <= cpu_do[7:0];
+ 5'b11111:
+ fgpage <= cpu_do[4:0];
endcase // casex cpu_a[5:0] )
end // if ( intio_sel & ~cpu_wr_n )
else if ( ~abc_out_n[7] )
@@ -864,6 +933,12 @@ module abc80 (
intio_do <= prog_s7_0;
5'b10111:
intio_do <= prog_s7_1;
+ 5'b11110:
+ intio_do <= fgctl;
+ 5'b11111:
+ intio_do <= { 3'b0, fgpage };
+ default:
+ intio_do <= 8'hFF;
endcase // casex ( cpu_a[5:0] )
end // if ( intio_sel & ~cpu_rd_n )
end
diff --git a/data/fgcol.pl b/data/fgcol.pl
index 4d8df63..2b96114 100755
--- a/data/fgcol.pl
+++ b/data/fgcol.pl
@@ -20,11 +20,12 @@
'YCYC', 'YYCC', 'YWYW', 'YYWW', 'BMBM', 'BBMM', 'BCBC', 'BBCC',
'BWBW', 'BBWW', 'MCMC', 'MMCC', 'MWMW', 'MMWW', 'CWCW', 'CCWW' );
-%colenc = ('K' => 0, 'B' => 1, 'G' => 2, 'C' => 3,
- 'R' => 4, 'M' => 5, 'Y' => 6, 'W' => 7);
+# Note: bit 3 means opaque
+%colenc = ('K' => 0, 'B' => 9, 'G' => 10, 'C' => 11,
+ 'R' => 12, 'M' => 13, 'Y' => 14, 'W' => 15);
print "DEPTH = 512;\n";
-print "WIDTH = 3;\n";
+print "WIDTH = 4;\n";
print "ADDRESS_RADIX = HEX;\n";
print "DATA_RADIX = HEX;\n";
print "CONTENT\n";
@@ -35,7 +36,7 @@ for ($i = 0; $i < 128; $i++) {
for ($x = 0; $x < 4; $x++) {
$c = substr($coltbl[$i], $x, 1);
$c = $colenc{$c};
- printf "%02X : %01X\n", $a++, $c;
+ printf "%02X : %01X;\n", $a++, $c;
}
}
print "END;\n";
diff --git a/data/mmuinit.pl b/data/mmuinit.pl
index 2b3eaa9..389c89f 100755
--- a/data/mmuinit.pl
+++ b/data/mmuinit.pl
@@ -34,7 +34,7 @@ sub do_ram() {
if ( $testram ) {
# Tiny amount of RAM (4K)
for ( ; $i < 0xF0 ; $i++ ) {
- printf("%03X : %04X;\n", $a++, 0xFFFF);
+ printf("%03X : %04X;\n", $a++, 0x70FF);
}
for ( $i = 0xF0 ; $i < 0x100 ; $i++ ) {
printf("%03X : %04X;\n", $a++, 0x0000|$i);
@@ -61,7 +61,7 @@ for ( $i = 0x00 ; $i < 0x40 ; $i++ ) { # BASIC
printf("%03X : %04X;\n", $a++, 0x9000|$i);
}
for ( $i = 0x40 ; $i < 0x60 ; $i++ ) { # Free for expansion
- printf("%03X : %04X;\n", $a++, 0x7FFF);
+ printf("%03X : %04X;\n", $a++, 0x70FF);
}
for ( $i = 0x60 ; $i < 0x74 ; $i++ ) { # DOS, IEC options
printf("%03X : %04X;\n", $a++, 0x1000|$i);
diff --git a/display.v b/display.v
index 55aa914..2b7e8f3 100644
--- a/display.v
+++ b/display.v
@@ -13,8 +13,14 @@ module display (
input [5:0] gd,
output reg [2:0] rgb,
- output reg vsync,
- output reg hsync
+ output vsync,
+ output hsync,
+
+ input [7:0] fg_ctl,
+ input [7:0] fg_data,
+ output fg_ack,
+ output fg_xrst,
+ output fg_yrst
);
// We use the standard VGA 640x480 monitor timings mode, htime = 31.77
@@ -65,7 +71,10 @@ module display (
parameter hsync_minus = 1'b1; // -hsync
parameter vsync_minus = 1'b1; // -vsync
-
+
+ reg hsync_q; // Horizontal sync active
+ reg vsync_q; // Vertical sync active
+
reg [9:0] x; // Horizontal pixel count
reg [9:0] y; // Vertical pixel count
reg [6:0] xchr; // Character column (0..99)
@@ -84,6 +93,9 @@ module display (
reg [5:0] pixrow; // One character worth of pixels
reg prefetch; // True for the prefetch character position
+ // Fine Graphics control
+ reg [7:0] fgpixels; // One byte of fg pixels
+
// For the current text line
reg [2:0] curfg; // Foreground RGB
reg [2:0] curbg; // Background RGB
@@ -165,6 +177,9 @@ module display (
assign xvideo = ( x < x_blank );
assign yvideo = ( y < y_blank );
+ assign hsync = hsync_q ^ hsync_minus;
+ assign vsync = vsync_q ^ vsync_minus;
+
// Flashing
wire flash_on = scan_counter[4];
@@ -173,24 +188,48 @@ module display (
// "reverse" is asserted with invert everything *on top of that*...
wire invert = (inverse & (flash_on|noblink))^reverse;
+ //
+ // Fine graphics
+ //
+ assign fg_ack = xvideo & yvideo & (x[2:0] == 3'b000);
+ assign fg_xrst = yvideo & hsync_q;
+ assign fg_yrst = vsync_q;
+
+ wire [3:0] fg_argb;
+
+ always @(posedge clk)
+ if (x[2:0] == 3'b100)
+ fgpixels <= fg_data;
+ else if (~x[0])
+ fgpixels <= { fgpixels[5:0], 2'bxx };
+
+ fgcolrom fgcolrom (
+ .address ( { fg_ctl[6:0], fgpixels[7:6] } ),
+ .clock ( clk ),
+ .q ( fg_argb )
+ );
+
// Synchronous logic
always @(posedge clk)
begin
- if ( xvideo & yvideo & ~prefetch )
- if ( testpattern )
- // Pixel test pattern for LCD monitor calibration
- rgb <= {3{x[0] ^ y[0]}};
- else if ( pixrow[5] & ~(do_flsh & ~flash_on) & ~(do_hide & ~reveal) )
- rgb <= fg ^ {3{invert}};
- else
- rgb <= bg ^ {3{invert}};
+ if ( ~xvideo | ~yvideo | prefetch )
+ rgb <= 3'b000; // Blank
+ else if ( testpattern )
+ // Pixel test pattern for LCD monitor calibration
+ rgb <= {3{x[0] ^ y[0]}};
+ else if ( ~fg_ctl[7] & pixrow[5]
+ & ~(do_flsh & ~flash_on)
+ & ~(do_hide & ~reveal) )
+ rgb <= fg ^ {3{invert}};
+ else if (fg_ctl[7] | fg_argb[3])
+ rgb <= fg_argb[2:0];
else
- rgb <= 3'b0; // Blank
+ rgb <= bg ^ {3{invert}};
// Sync pulses
- vsync <= ( y >= y_sync && y < y_front ) ^ vsync_minus;
- hsync <= ( x >= x_sync && x < x_front ) ^ hsync_minus;
+ vsync_q <= ( y >= y_sync && y < y_front );
+ hsync_q <= ( x >= x_sync && x < x_front );
// Rotating shift register; may be overridden by the below
// The rotation is so that if we're in GHOL mode we already
diff --git a/mega/fgcolrom.v b/mega/fgcolrom.v
index d89270b..6e05d07 100644
--- a/mega/fgcolrom.v
+++ b/mega/fgcolrom.v
@@ -43,7 +43,7 @@ module fgcolrom (
input [8:0] address;
input clock;
- output [2:0] q;
+ output [3:0] q;
`ifndef ALTERA_RESERVED_QIS
// synopsys translate_off
`endif
@@ -52,8 +52,8 @@ module fgcolrom (
// synopsys translate_on
`endif
- wire [2:0] sub_wire0;
- wire [2:0] q = sub_wire0[2:0];
+ wire [3:0] sub_wire0;
+ wire [3:0] q = sub_wire0[3:0];
altsyncram altsyncram_component (
.clock0 (clock),
@@ -71,7 +71,7 @@ module fgcolrom (
.clocken1 (1'b1),
.clocken2 (1'b1),
.clocken3 (1'b1),
- .data_a ({3{1'b1}}),
+ .data_a ({4{1'b1}}),
.data_b (1'b1),
.eccstatus (),
.q_b (),
@@ -91,7 +91,7 @@ module fgcolrom (
altsyncram_component.outdata_aclr_a = "NONE",
altsyncram_component.outdata_reg_a = "UNREGISTERED",
altsyncram_component.widthad_a = 9,
- altsyncram_component.width_a = 3,
+ altsyncram_component.width_a = 4,
altsyncram_component.width_byteena_a = 1;
@@ -126,7 +126,7 @@ endmodule
// Retrieval info: PRIVATE: SingleClock NUMERIC "1"
// Retrieval info: PRIVATE: UseDQRAM NUMERIC "0"
// Retrieval info: PRIVATE: WidthAddr NUMERIC "9"
-// Retrieval info: PRIVATE: WidthData NUMERIC "3"
+// Retrieval info: PRIVATE: WidthData NUMERIC "4"
// Retrieval info: PRIVATE: rden NUMERIC "0"
// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS"
// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS"
@@ -139,13 +139,13 @@ endmodule
// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE"
// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "UNREGISTERED"
// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "9"
-// Retrieval info: CONSTANT: WIDTH_A NUMERIC "3"
+// Retrieval info: CONSTANT: WIDTH_A NUMERIC "4"
// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1"
// Retrieval info: USED_PORT: address 0 0 9 0 INPUT NODEFVAL address[8..0]
// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC clock
-// Retrieval info: USED_PORT: q 0 0 3 0 OUTPUT NODEFVAL q[2..0]
+// Retrieval info: USED_PORT: q 0 0 4 0 OUTPUT NODEFVAL q[3..0]
// Retrieval info: CONNECT: @address_a 0 0 9 0 address 0 0 9 0
-// Retrieval info: CONNECT: q 0 0 3 0 @q_a 0 0 3 0
+// Retrieval info: CONNECT: q 0 0 4 0 @q_a 0 0 4 0
// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0
// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
// Retrieval info: GEN_FILE: TYPE_NORMAL fgcolrom.v TRUE