OpenCores
URL https://opencores.org/ocsvn/rf6809/rf6809/trunk

Subversion Repositories rf6809

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /rf6809
    from Rev 18 to Rev 19
    Reverse comparison

Rev 18 → Rev 19

/trunk/rtl/noc/keyboard/PS2kbd.sv
0,0 → 1,437
`timescale 1ns / 1ps
// ============================================================================
// __
// \\__/ o\ (C) 2005-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// PS2kbd.v - PS2 compatible keyboard interface
//
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file 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 this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// PS2 compatible keyboard / mouse interface
//
// This core provides a raw interface to the a PS2
// keyboard or mouse. The interface is raw in the sense
// that it doesn't do any scan code processing, it
// just supplies it to the system. The core uses a
// WISHBONE compatible bus interface.
// Both transmit and recieve are
// supported. It is possible to build the core without
// the transmitter to reduce the size of the core; however
// then it would not be possible to control the leds on
// the keyboard. (The transmitter is required for a mouse
// interface).
// There is a 5us debounce circuit on the incoming
// clock.
// The transmitter does not have a watchdog timer, so
// it may cause the keyboard to stop responding if there
// was a problem with the transmit. It relys on the system
// to reset the transmitter after 30ms or so of no
// reponse. Resetting the transmitter should allow the
// keyboard to respond again.
// Note: keyboard clock must be at least three times slower
// than the clk_i input to work reliably.
// A typical keyboard clock is <30kHz so this should be ok
// for most systems.
// * There must be pullup resistors on the keyboard clock
// and data lines, and the keyboard clock and data lines
// are assumed to be open collector.
// To read the keyboard, wait for bit 7 of the status
// register to be set, then read the transmit / recieve
// register. Reading the transmit / recieve register clears
// the keyboard reciever, and allows the next character to
// be recieved.
//
// Reg
// 0 keyboard transmit/receive register
// 1 status reg. itk xxxx p
// i = interrupt status
// t = transmit complete
// k = transmit acknowledge receipt (from keyboard)
// p = parity error
// A write to the status register clears the transmitter
// state
//
//
//
// Webpack 9.1i xc3s1000-4ft256
// LUTs / slices / MHz
// block rams
// multiplier
//
// ============================================================================
// A good source of info:
// http://panda.stb_i.ndsu.nodak.edu/~achapwes/PICmicro/PS2/ps2.htm
// http://www.beyondlogic.org/keyboard/keybrd.htm
//
// From the keyboard
// 1 start bit
// 8 data bits
// 1 parity bit
// 1 stop bit
//
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |WISHBONE Datasheet
// |WISHBONE SoC Architecture Specification, Revision B.3
// |
// |Description: Specifications:
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |General Description: PS2 keyboard / mouse interface
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Supported Cycles: SLAVE,READ/WRITE
// | SLAVE,BLOCK READ/WRITE
// | SLAVE,RMW
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Data port, size: 8 bit
// |Data port, granularity: 8 bit
// |Data port, maximum operand size: 8 bit
// |Data transfer ordering: Undefined
// |Data transfer sequencing: Undefined
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Clock frequency constraints: none
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Supported signal list and Signal Name WISHBONE equiv.
// |cross reference to equivalent ack_o ACK_O
// |WISHBONE signals adr_i ADR_I()
// | clk_i CLK_I
// | cyc_i CYC_I
// | dat_i(7:0) DAT_I()
// | dat_o(7:0) DAT_O()
// | stb_i STB_I
// | we_i WE_I
// |
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Special requirements:
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
//==================================================================
 
`define KBD_TX 1 // include transmitter
 
`define S_KBDRX_WAIT_CLK 0
`define S_KBDRX_CHK_CLK_LOW 1
`define S_KBDRX_CAPTURE_BIT 2
 
module PS2kbd(
// WISHBONE/SoC bus interface
input rst_i,
input clk_i, // system clock
input cs_i,
input cyc_i,
input stb_i, // core select (active high)
output reg ack_o, // bus transfer acknowledged
input we_i, // I/O write taking place (active high)
input [3:0] adr_i, // address
input [11:0] dat_i, // data in
output reg [11:0] dat_o, // data out
inout tri [11:0] db,
//-------------
output irq, // interrupt request (active high)
input kclk_i, // keyboard clock from keyboard
output kclk_en, // 1 = drive clock low
input kdat_i, // keyboard data
output kdat_en // 1 = drive data low
);
parameter pClkFreq = 40000000;
parameter pAckStyle = 1'b0;
parameter p5us = pClkFreq / 200000; // number of clocks for 5us
parameter p100us = pClkFreq / 10000; // number of clocks for 100us
 
reg [13:0] os; // one shot
wire os_5us_done = os==p5us;
wire os_100us_done = os==p100us;
reg [10:0] q; // receive register
reg tc; // transmit complete indicator
reg [1:0] s_rx; // keyboard receive state
reg [7:0] kq;
reg [15:0] kqc;
// Use majority logic for bit capture
// 4 or more bits high = 1, otherwise 0
wire [2:0] kqs = {2'b0,kq[0]}+
{2'b0,kq[1]}+
{2'b0,kq[2]}+
{2'b0,kq[3]}+
{2'b0,kq[4]}+
{2'b0,kq[5]}+
{2'b0,kq[6]};
wire kqcne; // negative edge on kqc
wire kqcpe; // positive edge on kqc
assign irq = ~q[0];
reg kack; // keyboard acknowledge bit
`ifdef KBD_TX
reg [16:0] tx_state; // transmitter states
reg klow; // force clock line low
reg [10:0] t; // transmit register
wire rx_inh = ~tc; // inhibit receive while transmit occuring
reg [3:0] bitcnt;
wire shift_done = bitcnt==0;
reg tx_oe; // transmitter output enable / shift enable
`else
wire rx_inh = 0;
`endif
 
wire cs = cyc_i & stb_i & cs_i;
//reg ack,ack1;
//always @(posedge clk_i) begin ack <= cs; ack1 <= ack & cs; end
always_ff @(posedge clk_i)
ack_o <= cs ? 1'b1 : pAckStyle;// ? (we_i ? 1'b1 : ack) : 1'b0;
 
wire pe_cs;
edge_det ed1 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cs), .pe(pe_cs), .ne(), .ee() );
 
// register read path
// Latches data on positive edge of the circuit select, as reading the keyboard
// register triggers a clear of it.
always_ff @(posedge clk_i)
if (cs_i)
case(adr_i[1:0])
2'd0: dat_o <= {4'h0,q[8:1]};
2'd1: dat_o <= {4'h0,~q[0],tc,~kack,4'b0,~^q[9:1]};
2'd2: dat_o <= {4'h0,q[8:1]};
2'd3: dat_o <= {4'h0,~q[0],tc,~kack,4'b0,~^q[9:1]};
endcase
else
dat_o <= 12'h00;
 
assign db = (cs & ~we_i) ? dat_o : {12{1'bz}};
 
// Prohibit keyboard device from further transmits until
// this character has been processed.
// Holding the clock line low does this.
//assign kclk = irq ? 1'b0 : 1'bz;
`ifdef KBD_TX
// Force clock and data low during transmits
assign kclk_en = klow | irq;
assign kdat_en = tx_oe & ~t[0];// ? 1'b0 : 1'bz;
`else
assign kclk_en = irq;
`endif
 
// stabilize clock and data
always_ff @(posedge clk_i) begin
kq <= {kq[6:0],kdat_i};
kqc <= {kqc[14:0],kclk_i};
end
 
edge_det ed0 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(kqc[10]), .pe(kqcpe), .ne(kqcne), .ee() );
 
 
// The debounce one-shot and 100us timer
always @(posedge clk_i)
if (rst_i)
os <= 0;
else begin
if ((s_rx==`S_KBDRX_WAIT_CLK && kqcne && ~rx_inh)||
(s_rx==`S_KBDRX_CHK_CLK_LOW && rx_inh)
`ifdef KBD_TX
||tx_state[0]||tx_state[2]||tx_state[5]||tx_state[7]||tx_state[9]||tx_state[11]||tx_state[14]
`endif
)
os <= 0;
else
os <= os + 1;
end
 
 
// Receive state machine
always_ff @(posedge clk_i) begin
if (rst_i) begin
q <= 11'h7FF;
s_rx <= `S_KBDRX_WAIT_CLK;
end
else begin
 
// clear rx on write to status reg
if (cs && we_i && adr_i[1:0]==2'd1 && dat_i[7:0]==8'h00)
q <= 11'h7FF;
 
// Receive state machine
case (s_rx) // synopsys full_case parallel_case
// negedge on kclk ?
// then set debounce one-shot
`S_KBDRX_WAIT_CLK:
if (kqcne && ~rx_inh)
s_rx <= `S_KBDRX_CHK_CLK_LOW;
 
// wait 5us
// check if clock low
`S_KBDRX_CHK_CLK_LOW:
if (rx_inh)
s_rx <= `S_KBDRX_WAIT_CLK;
else if (os_5us_done) begin
// clock low ?
if (~kqc[10])
s_rx <= `S_KBDRX_CAPTURE_BIT;
else
s_rx <= `S_KBDRX_WAIT_CLK; // no - spurious
end
 
// capture keyboard bit
// keyboard transmits LSB first
`S_KBDRX_CAPTURE_BIT:
begin
q <= {kq[2],q[10:1]};
s_rx <= `S_KBDRX_WAIT_CLK;
end
 
default:
s_rx <= `S_KBDRX_WAIT_CLK;
endcase
end
end
 
 
`ifdef KBD_TX
 
// Transmit state machine
// a shift register / ring counter is used
reg adv_tx_state; // advance transmitter state
reg start_tx; // start the transmitter
reg clear_tx; // clear the transmit state
always_ff @(posedge clk_i)
if (rst_i)
tx_state <= 0;
else begin
if (clear_tx)
tx_state <= 0;
else if (start_tx)
tx_state[0] <= 1;
else if (adv_tx_state) begin
tx_state[6:0] <= {tx_state[5:0],1'b0};
tx_state[7] <= (tx_state[8] && !shift_done) || tx_state[6];
tx_state[8] <= tx_state[7];
tx_state[9] <= tx_state[8] && shift_done;
tx_state[16:10] <= tx_state[15:9];
end
end
 
 
// detect when to advance the transmit state
always_comb
case (1'b1) // synopsys parallel_case
tx_state[0]: adv_tx_state <= 1;
tx_state[1]: adv_tx_state <= os_100us_done;
tx_state[2]: adv_tx_state <= 1;
tx_state[3]: adv_tx_state <= os_5us_done;
tx_state[4]: adv_tx_state <= 1;
tx_state[5]: adv_tx_state <= kqcne;
tx_state[6]: adv_tx_state <= os_5us_done;
tx_state[7]: adv_tx_state <= kqcpe;
tx_state[8]: adv_tx_state <= os_5us_done;
tx_state[9]: adv_tx_state <= kqcpe;
tx_state[10]: adv_tx_state <= os_5us_done;
tx_state[11]: adv_tx_state <= kqcne;
tx_state[12]: adv_tx_state <= os_5us_done;
tx_state[13]: adv_tx_state <= 1;
tx_state[14]: adv_tx_state <= kqcpe;
tx_state[15]: adv_tx_state <= os_5us_done;
default: adv_tx_state <= 0;
endcase
 
wire load_tx = cs && we_i && adr_i[1:0]==2'b0;
wire shift_tx = (tx_state[7] & kqcpe)|tx_state[4];
 
// It can take up to 20ms for the keyboard to accept data
// from the host.
always_ff @(posedge clk_i) begin
if (rst_i) begin
klow <= 0;
tc <= 1;
start_tx <= 0;
tx_oe <= 0;
end
else begin
 
clear_tx <= 0;
start_tx <= 0;
 
// write to keyboard register triggers whole thing
if (load_tx) begin
start_tx <= 1;
tc <= 0;
end
// write to status register clears transmit state
else if (cs && we_i && adr_i[1:0]==2'd1 && dat_i[7:0]==8'hFF) begin
tc <= 1;
tx_oe <= 0;
klow <= 1'b0;
clear_tx <= 1;
end
else begin
 
case (1'b1) // synopsys parallel_case
 
tx_state[0]: klow <= 1'b1; // First step: pull the clock low
tx_state[1]: ; // wait 100 us (hold clock low)
tx_state[2]: tx_oe <= 1; // bring data low / enable shift
tx_state[3]: ; // wait 5us
// at this point the clock should go high
// and shift out the start bit
tx_state[4]: klow <= 0; // release clock line
tx_state[5]: ; // wait for clock to go low
tx_state[6]: ; // wait 5us
// state7, 8 shift the data out
tx_state[7]: ; // wait for clock to go high
tx_state[8]: ; // wait 5us, go back to state 7
tx_state[9]: tx_oe <= 0; // wait for clock to go high // disable transmit output / shift
tx_state[10]: ; // wait 5us
tx_state[11]: ; // wait for clock to go low
tx_state[12]: ; // wait 5us
tx_state[13]: kack <= kq[1]; // capture the ack_o bit from the keyboard
tx_state[14]: ; // wait for clock to go high
tx_state[15]: ; // wait 5us
tx_state[16]:
begin
tc <= 1; // transmit is now complete
clear_tx <= 1;
end
 
default: ;
 
endcase
end
end
end
 
 
// transmitter shift register
always_ff @(posedge clk_i)
if (rst_i)
t <= 11'd0;
else begin
if (load_tx)
t <= {~(^dat_i[7:0]),dat_i[7:0],2'b0};
else if (shift_tx)
t <= {1'b1,t[10:1]};
end
 
 
// transmitter bit counter
always_ff @(posedge clk_i)
if (rst_i)
bitcnt <= 4'd0;
else begin
if (load_tx)
bitcnt <= 4'd11;
else if (shift_tx)
bitcnt <= bitcnt - 4'd1;
end
 
`endif
 
endmodule
/trunk/rtl/noc/lib/BtnDebounce.v
0,0 → 1,53
// ============================================================================
// __
// \\__/ o\ (C) 2016-2021 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file 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 this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Button / switch debounce circuit.
// Assumes 25MHz clock
// Approximately 10ms of debounce is provided.
// ============================================================================
//
module BtnDebounce(clk, btn_i, o);
input clk;
input btn_i;
output reg o;
 
reg [18:0] counter;
reg val1, val2;
 
always @(posedge clk)
begin
val1 <= btn_i;
val2 <= val1;
end
 
always @(posedge clk)
if (val1 != val2)
counter <= 19'h0;
else if (counter[18])
counter <= 19'h0;
else
counter <= counter + 19'd1;
 
always @(posedge clk)
if (counter[18])
o <= val2;
 
endmodule
/trunk/rtl/noc/lib/BusError.v
0,0 → 1,64
`timescale 1ns / 1ps
// ============================================================================
// __
// \\__/ o\ (C) 2013-2018 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// BusError.v
// - generate a bus timeout error if a cycle has been active without an ack
// for too long of a time.
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file 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 this program. If not, see <http://www.gnu.org/licenses/>.
//
// ============================================================================
//
module BusError(rst_i, clk_i, cyc_i, ack_i, stb_i, adr_i, err_o);
parameter pTO=28'd50000;
input rst_i;
input clk_i;
input cyc_i;
input ack_i;
input stb_i;
input [31:0] adr_i;
output err_o;
reg err_o;
 
reg [27:0] tocnt;
 
always @(posedge clk_i)
if (rst_i) begin
err_o <= 1'b0;
tocnt <= 28'd1;
end
else begin
err_o <= 1'b0;
// If there is no bus cycle active, or if the bus cycle
// has been acknowledged, reset the timeout count.
if (ack_i || !cyc_i) begin
tocnt <= 28'd1;
err_o <= 1'b0;
end
else if (tocnt < pTO)
tocnt <= tocnt + 28'd1;
else if (cyc_i && stb_i && (adr_i[31:4]==28'hFFDCFFE)) begin // conflist with configrec ?
tocnt <= 28'd1;
err_o <= 1'b0;
end
else
err_o <= 1'b1;
end
 
endmodule
/trunk/rtl/noc/lib/random.sv
0,0 → 1,218
// ============================================================================
// __
// \\__/ o\ (C) 2011-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// random.v
// Multi-stream random number generator.
//
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file 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 this program. If not, see <http://www.gnu.org/licenses/>.
//
// Reg no.
// 0 read: random output bits [31:0], write: gen next number
// 1 random stream number
// 2 m_z seed setting bits [31:0]
// 3 m_w seed setting bits [31:0]
//
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |WISHBONE Datasheet
// |WISHBONE SoC Architecture Specification, Revision B.3
// |
// |Description: Specifications:
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |General Description: random number generator
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Supported Cycles: SLAVE,READ/WRITE
// | SLAVE,BLOCK READ/WRITE
// | SLAVE,RMW
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Data port, size: 16 bit
// |Data port, granularity: 16 bit
// |Data port, maximum operand size: 16 bit
// |Data transfer ordering: Undefined
// |Data transfer sequencing: Undefined
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Clock frequency constraints: none
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Supported signal list and Signal Name WISHBONE equiv.
// |cross reference to equivalent ack_o ACK_O
// |WISHBONE signals adr_i[43:0] ADR_I()
// | clk_i CLK_I
// | rst_i RST_I()
// | dat_i(15:0) DAT_I()
// | dat_o(15:0) DAT_O()
// | cyc_i CYC_I
// | stb_i STB_I
// | we_i WE_I
// |
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// |Special requirements:
// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
// ============================================================================
//
// Uses George Marsaglia's multiply method
//
// m_w = <choose-initializer>; /* must not be zero */
// m_z = <choose-initializer>; /* must not be zero */
//
// uint get_random()
// {
// m_z = 36969 * (m_z & 65535) + (m_z >> 16);
// m_w = 18000 * (m_w & 65535) + (m_w >> 16);
// return (m_z << 16) + m_w; /* 32-bit result */
// }
//
`define TRUE 1'b1
`define FALSE 1'b0
 
module random(rst_i, clk_i, cs_i, cyc_i, stb_i, ack_o, we_i, adr_i, dat_i, dat_o);
input rst_i;
input clk_i;
input cs_i;
input cyc_i;
input stb_i;
output reg ack_o;
input we_i;
input [3:0] adr_i;
input [11:0] dat_i;
output reg [11:0] dat_o;
parameter pAckStyle = 1'b0;
 
reg ack;
reg cs;
reg we;
reg [3:0] adr;
reg [11:0] dat;
always_ff @(posedge clk_i)
cs <= cs_i && cyc_i && stb_i;
always_ff @(posedge clk_i)
we <= we_i;
always_ff @(posedge clk_i)
adr <= adr_i;
always_ff @(posedge clk_i)
dat <= dat_i;
 
always_ff @(posedge clk_i)
ack_o <= cs & cs_i & cyc_i & stb_i;
//always @*
// ack_o <= cs ? ack : pAckStyle;
 
reg [9:0] stream;
reg [35:0] next_m_z;
reg [35:0] next_m_w;
reg [35:0] out;
reg wrw, wrz;
reg [35:0] w=32'd3,z=32'd17;
wire [35:0] m_zs;
wire [35:0] m_ws;
wire pe_we;
 
edge_det ued1 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(we), .pe(pe_we), .ne(), .ee());
rand_ram u1 (clk_i, wrw, stream, w, m_ws);
rand_ram u2 (clk_i, wrz, stream, z, m_zs);
 
always_comb
begin
next_m_z = (18'h36969 * m_zs[17:0]) + m_zs[35:18];
next_m_w = (18'h18000 * m_ws[17:0]) + m_ws[35:18];
end
 
reg [35:0] m_zsws;
always_comb
m_zsws <= {m_zs[17:0],18'd0} + m_ws;
 
// Register read path
//
always_ff @(posedge clk_i)
if (cs_i)
case(adr[3:0])
4'd0: dat_o <= 12'h0;
4'd1: dat_o <= m_zsws[35:24];
4'd2: dat_o <= m_zsws[23:12];
4'd3: dat_o <= m_zsws[11: 0];
4'd5: dat_o <= {2'h0,stream};
// Uncomment these for register read-back
// 3'd4: dat_o <= m_z[31:16];
// 3'd5: dat_o <= m_z[15: 0];
// 3'd6: dat_o <= m_w[31:16];
// 3'd7: dat_o <= m_w[15: 0];
default: dat_o <= 12'h000;
endcase
else
dat_o <= 12'h0;
 
// Register write path
//
always_ff @(posedge clk_i)
begin
wrw <= `FALSE;
wrz <= `FALSE;
if (cs) begin
if (pe_we)
case(adr[3:0])
4'd3:
begin
z <= next_m_z;
w <= next_m_w;
wrw <= `TRUE;
wrz <= `TRUE;
end
4'd5: stream <= dat[9:0];
4'd8: ;
4'd9: z[35:24] <= dat;
4'd10: z[23:12] <= dat;
4'd11: begin z[11: 0] <= dat; wrz <= `TRUE; end
4'd12: ;
4'd13: w[35:24] <= dat;
4'd14: w[23:12] <= dat;
4'd15: begin w[11:0] <= dat; wrw <= `TRUE; end
endcase
end
end
 
endmodule
 
 
// Tools were inferring a massive distributed ram so we help them out a bit by
// creating an explicit ram definition.
 
module rand_ram(clk, wr, ad, i, o);
input clk;
input wr;
input [9:0] ad;
input [35:0] i;
output [35:0] o;
 
reg [35:0] ri;
reg [9:0] regadr;
reg regwr;
(* RAM_STYLE="BLOCK" *)
reg [35:0] mem [0:1023];
 
always_ff @(posedge clk)
regadr <= ad;
always_ff @(posedge clk)
regwr <= wr;
always_ff @(posedge clk)
ri <= i;
always_ff @(posedge clk)
if (regwr)
mem[regadr] <= ri;
assign o = mem[regadr];
 
endmodule
/trunk/rtl/noc/memory/demomem.sv
0,0 → 1,189
// ============================================================================
// __
// \\__/ o\ (C) 2012-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ============================================================================
//
module demomem(rst_i, clk_i, cti_i, bok_o, cs_i, cyc_i, stb_i, ack_o, we_i, adr_i, dat_i, dat_o, sp);
input rst_i;
input clk_i;
input [2:0] cti_i;
output bok_o;
input cs_i;
input cyc_i;
input stb_i;
output ack_o;
input we_i;
input [13:0] adr_i;
input [11:0] dat_i;
output reg [11:0] dat_o;
input [23:0] sp;
 
integer n;
 
reg [11:0] rommem [16383:0];
reg [13:0] radr;
 
 
initial begin
for (n = 0; n < 16384; n = n + 1)
rommem[n] <= 12'h00;
`include "d:/cores2022/rf6809/software/boot/demo.ver";
end
 
wire cs = cs_i && cyc_i && stb_i;
assign bok_o = cs_i;
reg csd = 1'b0;
reg wed = 1'b0;
reg [13:0] adrd = 16'h00;
reg [11:0] datid = 8'h00;
reg [11:0] datod = 8'h00;
 
reg [2:0] cnt;
/*
reg rdy,rdy1;
always @(posedge clk_i)
if (rst_i) begin
rdy1 <= 1'b0;
rdy <= 1'b0;
end
else begin
rdy1 <= cs;
rdy <= rdy1 & cs && cnt!=3'b101;
end
assign ack_o = cs ? (we_i ? 1'b1 : rdy) : 1'b0;
*/
ack_gen #(
.READ_STAGES(2),
.WRITE_STAGES(1),
.REGISTER_OUTPUT(1)
) ag1
(
.clk_i(clk_i),
.ce_i(1'b1),
.i(cs && cnt != 3'b101),
.we_i(we_i && cs && cnt != 3'b101),
.o(ack_o),
.rid_i(0),
.wid_i(0),
.rid_o(),
.wid_o()
);
 
 
always @(posedge clk_i)
csd <= cs;
always @(posedge clk_i)
wed <= we_i;
always @(posedge clk_i)
adrd <= adr_i;
always @(posedge clk_i)
datid <= dat_i;
 
always @(posedge clk_i)
if (cs & we_i) begin
$display ("wrote to scratchmem: %h=%h", adr_i, dat_i);
/*
if (adr_i[14:3]==15'h3e9 && dat_i==64'h00) begin
$display("3e9=00");
$finish;
end
*/
end
genvar g;
generate begin : gRom
for (g = 0; g < 1; g = g + 1)
always @(posedge clk_i)
if (csd & wed)
rommem[adrd[13:0]][g*12+11:g*12] <= datid[g*12+11:g*12];
end
endgenerate
 
wire pe_cs;
edge_det u1(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cs), .pe(pe_cs), .ne(), .ee() );
 
reg [13:0] ctr;
always @(posedge clk_i)
if (rst_i) begin
cnt <= 3'd0;
ctr <= 14'd0;
end
else begin
if (pe_cs) begin
if (cti_i==3'b000)
ctr <= adr_i[13:0];
else
ctr <= adr_i[13:0] + 12'd1;
cnt <= 3'b000;
end
else if (cs && cnt[2:0]!=3'b100 && cti_i!=3'b000) begin
ctr <= ctr + 2'd1;
cnt <= cnt + 3'd1;
end
end
 
always @(posedge clk_i)
radr <= pe_cs ? adr_i[13:0] : ctr;
 
//assign dat_o = cs ? {smemH[radr],smemG[radr],smemF[radr],smemE[radr],
// smemD[radr],smemC[radr],smemB[radr],smemA[radr]} : 64'd0;
reg [13:0] spr;
always @(posedge clk_i)
spr <= sp[13:0];
 
always @(posedge clk_i)
if (rst_i)
datod <= 12'h00;
else begin
datod <= rommem[radr];
if (!we_i & cs)
$display("read from scratchmem: %h=%h", radr, rommem[radr]);
// $display("-------------- Stack --------------");
// for (n = -6; n < 8; n = n + 1) begin
// $display("%c%c %h %h", n==0 ? "-": " ", n==0 ?">" : " ",spr + n, rommem[spr+n]);
// end
end
 
always @(posedge clk_i)
if (rst_i)
dat_o <= 12'h00;
else begin
if (cs_i)
dat_o <= datod;
else
dat_o <= 12'd0;
end
 
endmodule
/trunk/rtl/noc/memory/scratchmem.sv
0,0 → 1,175
// ============================================================================
// __
// \\__/ o\ (C) 2012-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ============================================================================
//
module scratchmem(rst_i, clk_i, cti_i, bok_o, cs_i, cyc_i, stb_i, ack_o, we_i, adr_i, dat_i, dat_o, sp);
input rst_i;
input clk_i;
input [2:0] cti_i;
output bok_o;
input cs_i;
input cyc_i;
input stb_i;
output ack_o;
input we_i;
input [13:0] adr_i;
input [11:0] dat_i;
output reg [11:0] dat_o;
input [23:0] sp;
 
integer n;
 
reg [11:0] rommem [16383:0];
reg [13:0] radr;
 
 
initial begin
for (n = 0; n < 16384; n = n + 1)
rommem[n] <= 'h00;
`include "d:/cores2022/rf6809/software/a09/a09/debug/boot_rom.ver";
end
 
wire cs = cs_i && cyc_i && stb_i;
assign bok_o = cs_i;
reg csd = 1'b0;
reg wed = 1'b0;
reg [13:0] adrd = 16'h00;
reg [11:0] datid = 8'h00;
reg [11:0] datod = 'h00;
 
reg [2:0] cnt;
 
ack_gen #(
.READ_STAGES(2),
.WRITE_STAGES(1),
.REGISTER_OUTPUT(1)
) ag1
(
.clk_i(clk_i),
.ce_i(1'b1),
.i(cs && cnt != 3'b101),
.we_i(we_i && cs && cnt != 3'b101),
.o(ack_o),
.rid_i(0),
.wid_i(0),
.rid_o(),
.wid_o()
);
 
 
always @(posedge clk_i)
csd <= cs;
always @(posedge clk_i)
wed <= we_i;
always @(posedge clk_i)
adrd <= adr_i;
always @(posedge clk_i)
datid <= dat_i;
 
always @(posedge clk_i)
if (cs & we_i) begin
$display ("wrote to scratchmem: %h=%h", adr_i, dat_i);
/*
if (adr_i[14:3]==15'h3e9 && dat_i==64'h00) begin
$display("3e9=00");
$finish;
end
*/
end
genvar g;
generate begin : gRom
for (g = 0; g < 1; g = g + 1)
always @(posedge clk_i)
if (csd && wed)
rommem[adrd[13:0]][g*12+11:g*12] <= datid[11:0];
end
endgenerate
 
wire pe_cs;
edge_det u1(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cs), .pe(pe_cs), .ne(), .ee() );
 
reg [13:0] ctr;
always @(posedge clk_i)
if (rst_i) begin
cnt <= 3'd0;
ctr <= 14'd0;
end
else begin
if (pe_cs) begin
if (cti_i==3'b000)
ctr <= adr_i[13:0];
else
ctr <= adr_i[13:0] + 12'd1;
cnt <= 3'b000;
end
else if (cs && cnt[2:0]!=3'b100 && cti_i!=3'b000) begin
ctr <= ctr + 2'd1;
cnt <= cnt + 3'd1;
end
end
 
always @(posedge clk_i)
radr <= pe_cs ? adr_i[13:0] : ctr;
 
reg [13:0] spr;
always @(posedge clk_i)
spr <= sp[13:0];
 
always @(posedge clk_i)
if (rst_i)
datod <= 12'h00;
else begin
datod <= rommem[radr[13:0]];
if (!we_i & cs)
$display("read from scratchmem: %h=%h", radr, rommem[radr[13:0]]);
// $display("-------------- Stack --------------");
// for (n = -6; n < 8; n = n + 1) begin
// $display("%c%c %h %h", n==0 ? "-": " ", n==0 ?">" : " ",spr + n, rommem[spr+n]);
// end
end
 
always @(posedge clk_i)
if (rst_i)
dat_o <= 'h00;
else begin
if (cs_i)
dat_o <= datod;
else
dat_o <= 'd0;
end
 
endmodule
/trunk/rtl/noc/memory/semamem.sv
0,0 → 1,96
// ============================================================================
// __
// \\__/ o\ (C) 2018-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// semamem.sv
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Address
// 0b0nnnnnnaaaa read: decrement by aaaaaa, write increment by aaaaaa
// 0b1nnnnnn---- read: peek value, write absolute data
// ============================================================================
 
module semamem(rst_i, clk_i, cs_i, cyc_i, stb_i, ack_o, we_i, adr_i, dat_i, dat_o);
input rst_i;
input clk_i;
input cs_i;
input cyc_i;
input stb_i;
output ack_o;
input we_i;
input [12:0] adr_i;
input [11:0] dat_i;
output reg [11:0] dat_o;
 
wire cs = cs_i & cyc_i & stb_i;
reg ack;
always_ff @(posedge clk_i)
ack <= cs;
assign ack_o = ack & cs;
 
reg [11:0] mem [0:255];
reg [11:0] memi;
reg [11:0] memo;
reg [12:0] memopi,memomi;
always_comb
memo <= mem[adr_i[11:4]];
always_comb
memopi <= memo + adr_i[3:0];
always_comb
memomi <= memo - adr_i[3:0];
assign o = memo;
 
wire pe_cs, ne_cs;
edge_det ued1 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cs), .pe(pe_cs), .ne(ne_cs), .ee());
 
always_ff @(posedge clk_i)
if (pe_cs)
mem[adr_i[11:4]] <= memi;
 
always_comb
begin
casez({adr_i[12],we_i})
2'b00: memi <= memomi[12] ? 12'h000 : memomi[11:0];
2'b01: memi <= memopi[12] ? 12'hFFF : memopi[11:0];
2'b10: memi <= memo;
2'b11: memi <= dat_i;
endcase
end
 
always_ff @(posedge clk_i)
if (cs) begin
if (pe_cs)
dat_o <= mem[adr_i[11:4]];
end
else
dat_o <= 12'h00;
 
endmodule
/trunk/rtl/noc/video/VGASyncGen.v
0,0 → 1,114
// ============================================================================
// __
// \\__/ o\ (C) 2012-2020 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// VGASyncGen.v
// VGA sync generator
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file 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 this program. If not, see <http://www.gnu.org/licenses/>.
//
//
//
// VGA video sync generator.
//
// This module generates the basic sync timing signals required for a
// VGA display.
//
// ============================================================================
 
module VGASyncGen(rst, clk, eol, eof, hSync, vSync, hCtr, vCtr,
blank, vblank, vbl_int, border,
hTotal_i, vTotal_i,
hSyncOn_i, hSyncOff_i, vSyncOn_i, vSyncOff_i,
hBlankOn_i, hBlankOff_i, vBlankOn_i, vBlankOff_i,
hBorderOn_i, vBorderOn_i, hBorderOff_i, vBorderOff_i);
input rst; // reset
input clk; // video clock
output reg eol;
output reg eof;
output reg hSync, vSync; // sync outputs
output [11:0] hCtr;
output [11:0] vCtr;
output reg blank; // blanking output
output reg vblank;
output reg vbl_int;
output border;
input [11:0] hTotal_i;
input [11:0] vTotal_i;
input [11:0] hSyncOn_i;
input [11:0] hSyncOff_i;
input [11:0] vSyncOn_i;
input [11:0] vSyncOff_i;
input [11:0] hBlankOn_i;
input [11:0] hBlankOff_i;
input [11:0] vBlankOn_i;
input [11:0] vBlankOff_i;
input [11:0] hBorderOn_i;
input [11:0] hBorderOff_i;
input [11:0] vBorderOn_i;
input [11:0] vBorderOff_i;
 
//---------------------------------------------------------------------
//---------------------------------------------------------------------
 
reg hBlank1;
wire vBlank1;
wire vBorder,hBorder;
wire hSync1,vSync1;
reg border;
 
wire eol1 = hCtr==hTotal_i;
wire eof1 = vCtr==vTotal_i;
 
assign vSync1 = vCtr >= vSyncOn_i && vCtr < vSyncOff_i;
assign hSync1 = hCtr >= hSyncOn_i && hCtr < hSyncOff_i;
assign vBlank1 = ~(vCtr < vBlankOn_i && vCtr >= vBlankOff_i);
assign vBorder = ~(vCtr < vBorderOn_i && vCtr >= vBorderOff_i);
assign hBorder = ~(hCtr < hBorderOn_i && hCtr >= hBorderOff_i);
 
counter #(12) u1 (.rst(rst), .clk(clk), .ce(1'b1), .ld(eol1), .d(12'd1), .q(hCtr), .tc() );
counter #(12) u2 (.rst(rst), .clk(clk), .ce(eol1), .ld(eof1), .d(12'd1), .q(vCtr), .tc() );
 
always @(posedge clk)
if (rst)
hBlank1 <= 1'b0;
else begin
if (hCtr==hBlankOn_i)
hBlank1 <= 1'b1;
else if (hCtr==hBlankOff_i)
hBlank1 <= 1'b0;
end
 
always @(posedge clk)
blank <= #1 hBlank1|vBlank1;
always @(posedge clk)
vblank <= #1 vBlank1;
always @(posedge clk)
border <= #1 hBorder|vBorder;
always @(posedge clk)
hSync <= #1 hSync1;
always @(posedge clk)
vSync <= #1 vSync1;
always @(posedge clk)
eof <= eof1;
always @(posedge clk)
eol <= eol1;
always @(posedge clk)
vbl_int <= hCtr==12'd8 && vCtr==12'd1;
 
endmodule
 
/trunk/rtl/noc/video/gfx_calc_address.sv
0,0 → 1,153
// ============================================================================
// __
// \\__/ o\ (C) 2015-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ============================================================================
//
// Compute the graphics address
//
import gfx_pkg::*;
 
module gfx_calc_address(clk, base_address_i, color_depth_i, bmp_width_i, x_coord_i, y_coord_i,
address_o, mb_o, me_o, ce_o);
parameter SW = 96; // strip width in bits
parameter BN = 6;
input clk;
input [31:0] base_address_i;
input [3:0] color_depth_i;
input [15:0] bmp_width_i; // pixel per line
input [15:0] x_coord_i;
input [15:0] y_coord_i;
output [31:0] address_o;
output [BN:0] mb_o; // mask begin
output [BN:0] me_o; // mask end
output [BN:0] ce_o; // color bits end
 
// This coefficient is a fixed point fraction representing the inverse of the
// number of pixels per strip. The inverse (reciprocal) is used for a high
// speed divide operation.
reg [15:0] coeff;
always @(color_depth_i)
case(color_depth_i)
BPP6: coeff = 65536*6/SW;
BPP8: coeff = 65536*8/SW;
BPP12: coeff = 65536*12/SW;
BPP16: coeff = 65536*16/SW;
BPP18: coeff = 65536*18/SW;
BPP21: coeff = 65536*21/SW;
BPP24: coeff = 65536*24/SW;
BPP27: coeff = 65536*27/SW;
BPP32: coeff = 65536*32/SW;
BPP33: coeff = 65536*33/SW;
default: coeff = 65536*16/SW;
endcase
 
// Bits per pixel minus one.
reg [5:0] bpp;
always @(color_depth_i)
case(color_depth_i)
BPP6: bpp = 5;
BPP8: bpp = 7;
BPP12: bpp = 11;
BPP16: bpp = 15;
BPP18: bpp = 17;
BPP21: bpp = 20;
BPP24: bpp = 23;
BPP27: bpp = 26;
BPP32: bpp = 31;
BPP33: bpp = 32;
default: bpp = 15;
endcase
 
// Color bits per pixel minus one.
reg [5:0] cbpp;
always @(color_depth_i)
case(color_depth_i)
BPP6: cbpp = 2;
BPP8: cbpp = 4;
BPP12: cbpp = 8;
BPP16: cbpp = 11;
BPP18: cbpp = 14;
BPP21: cbpp = 17;
BPP24: cbpp = 20;
BPP27: cbpp = 23;
BPP32: cbpp = 26;
BPP33: cbpp = 29;
default: cbpp = 11;
endcase
 
// This coefficient is the number of bits used by all pixels in the strip.
// Used to determine pixel placement in the strip.
reg [7:0] coeff2;
always @(color_depth_i)
case(color_depth_i)
BPP6: coeff2 = SW-(SW % 6);
BPP8: coeff2 = SW-(SW % 8);
BPP12: coeff2 = SW-(SW % 12);
BPP16: coeff2 = SW-(SW % 16);
BPP18: coeff2 = SW-(SW % 18);
BPP21: coeff2 = SW-(SW % 21);
BPP24: coeff2 = SW-(SW % 24);
BPP27: coeff2 = SW-(SW % 27);
BPP32: coeff2 = SW-(SW % 32);
BPP33: coeff2 = SW-(SW % 33);
default: coeff2 = SW-(SW % 16);
endcase
 
// Compute the fixed point horizonal strip number value. This has 16 binary
// point places.
wire [31:0] strip_num65k = x_coord_i * coeff;
// Truncate off the binary fraction to get the strip number. The strip
// number will be used to form part of the address.
wire [17:0] strip_num = strip_num65k[31:16];
// Calculate pixel position within strip using the fractional part of the
// horizontal strip number.
wire [15:0] strip_fract = strip_num65k[15:0]+16'h7F; // +7F to round
// Pixel beginning bit is ratio of pixel # into all bits used by pixels
wire [15:0] ndx = strip_fract[15:7] * coeff2;
assign mb_o = ndx[15:9]; // Get whole pixel position (discard fraction)
assign me_o = mb_o + bpp; // Set high order position for mask
assign ce_o = mb_o + cbpp;
// num_strips is essentially a constant value unless the screen resolution changes.
// Gain performance here by regstering the multiply so that there aren't two
// cascaded multiplies when calculating the offset.
reg [31:0] num_strips65k;
always @(posedge clk)
num_strips65k <= bmp_width_i * coeff;
wire [15:0] num_strips = num_strips65k[31:16];
 
wire [31:0] offset = {(({4'b0,num_strips} * y_coord_i) + strip_num),4'h0};
 
assign address_o = base_address_i + offset;
 
endmodule
/trunk/rtl/noc/video/rfColorROM.v
0,0 → 1,122
// ============================================================================
// __
// \\__/ o\ (C) 2006-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// rfColorROM.sv
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ============================================================================
 
// TC64 color codes
`define TC64_BLACK 5'd0
`define TC64_WHITE 5'd1
`define TC64_RED 5'd2
`define TC64_CYAN 5'd3
`define TC64_PURPLE 5'd4
`define TC64_GREEN 5'd5
`define TC64_BLUE 5'd6
`define TC64_YELLOW 5'd7
`define TC64_ORANGE 5'd8
`define TC64_BROWN 5'd9
`define TC64_PINK 5'd10
`define TC64_DARK_GREY 5'd11
`define TC64_MEDIUM_GREY 5'd12
`define TC64_LIGHT_GREEN 5'd13
`define TC64_LIGHT_BLUE 5'd14
`define TC64_LIGHT_GREY 5'd15
 
`define TC64_BLACKa 5'd16
`define TC64_WHITEa 5'd17
`define TC64_REDa 5'd18
`define TC64_CYANa 5'd19
`define TC64_PURPLEa 5'd20
`define TC64_GREENa 5'd21
`define TC64_BLUEa 5'd22
`define TC64_YELLOWa 5'd23
`define TC64_ORANGEa 5'd24
`define TC64_BROWNa 5'd25
`define TC64_PINKa 5'd26
`define TC64_DARK_GREYa 5'd27
`define TC64_GREY3 5'd28
`define TC64_LIGHT_GREENa 5'd29
`define TC64_LIGHT_BLUEa 5'd30
`define TC64_GREY5 5'd31
 
module rfColorROM(clk, ce, code, color);
input clk;
input ce;
input [4:0] code;
output [23:0] color;
reg [23:0] color;
 
always @(posedge clk)
if (ce) begin
case (code)
`TC64_BLACK: color = 24'h10_10_10;
`TC64_WHITE: color = 24'hFF_FF_FF;
`TC64_RED: color = 24'hE0_40_40;
`TC64_CYAN: color = 24'h60_FF_FF;
`TC64_PURPLE: color = 24'hE0_60_E0;
`TC64_GREEN: color = 24'h40_E0_40;
`TC64_BLUE: color = 24'h40_40_E0;
`TC64_YELLOW: color = 24'hFF_FF_40;
`TC64_ORANGE: color = 24'hE0_A0_40;
`TC64_BROWN: color = 24'h9C_74_48;
`TC64_PINK: color = 24'hFF_A0_A0;
`TC64_DARK_GREY: color = 24'h54_54_54;
`TC64_MEDIUM_GREY: color = 24'h88_88_88;
`TC64_LIGHT_GREEN: color = 24'hA0_FF_A0;
`TC64_LIGHT_BLUE: color = 24'hA0_A0_FF;
`TC64_LIGHT_GREY: color = 24'hC0_C0_C0;
 
`TC64_BLACKa: color = 24'h10_10_10;
`TC64_WHITEa: color = 24'hFF_FF_FF;
`TC64_REDa: color = 24'hE0_40_40;
`TC64_CYANa: color = 24'h60_FF_FF;
`TC64_PURPLEa: color = 24'hE0_60_E0;
`TC64_GREENa: color = 24'h40_E0_40;
`TC64_BLUEa: color = 24'h40_40_E0;
`TC64_YELLOWa: color = 24'hFF_FF_40;
`TC64_ORANGEa: color = 24'hE0_A0_40;
`TC64_BROWNa: color = 24'h9C_74_48;
`TC64_PINKa: color = 24'hFF_A0_A0;
`TC64_DARK_GREYa: color = 24'h54_54_54;
`TC64_GREY3: color = 24'h30_30_30;
`TC64_LIGHT_GREENa: color = 24'hA0_FF_A0;
`TC64_LIGHT_BLUEa: color = 24'hA0_A0_FF;
`TC64_GREY5: color = 24'h50_50_50;
 
endcase
end
 
endmodule
 
 
/trunk/rtl/noc/video/rfFrameBuffer_x12.sv
0,0 → 1,1169
// ============================================================================
// Bitmap Controller (Frame Buffer Display)
// - Displays a bitmap from memory.
//
//
// __
// \\__/ o\ (C) 2008-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// The default base screen address is:
// $0200000 - the third meg of RAM
//
//
// Verilog 1995
//
// ============================================================================
 
//`define USE_CLOCK_GATE 1'b1
`define INTERNAL_SYNC_GEN 1'b1
 
`define ABITS 31:0
`define HIGH 1'b1
`define LOW 1'b0
`define TRUE 1'b1
`define FALSE 1'b0
 
module rfFrameBuffer_x12 (
rst_i, irq_o,
s_clk_i, s_cs_i, s_cyc_i, s_stb_i, s_ack_o, s_we_i, s_adr_i, s_dat_i, s_dat_o,
m_clk_i, m_cyc_o, m_stb_o, m_ack_i, m_we_o, m_sel_o, m_adr_o, m_dat_i, m_dat_o,
dot_clk_i, zrgb_o, xonoff_i, xal_o,
`ifdef INTERNAL_SYNC_GEN
, hsync_o, vsync_o, blank_o, border_o, hctr_o, vctr_o, fctr_o, vblank_o
`else
, hsync_i, vsync_i, blank_i
`endif
);
parameter MDW = 96; // Bus master data width
parameter MAP = 12'd0;
parameter BM_BASE_ADDR1 = 32'h0020_0000;
parameter BM_BASE_ADDR2 = 32'h0028_0000;
parameter REG_CTRL = 11'd0;
parameter REG_REFDELAY = 11'd1;
parameter REG_PAGE1ADDR = 11'd2;
parameter REG_PAGE2ADDR = 11'd3;
parameter REG_PXYZ = 11'd4;
parameter REG_PCOLCMD = 11'd5;
parameter REG_TOTAL = 11'd8;
parameter REG_SYNC_ONOFF = 11'd9;
parameter REG_BLANK_ONOFF = 11'd10;
parameter REG_BORDER_ONOFF = 11'd11;
parameter REG_RASTCMP = 11'd12;
parameter REG_BMPSIZE = 11'd13;
parameter REG_OOB_COLOR = 11'd14;
parameter REG_WINDOW = 11'd15;
 
parameter BPP6 = 4'd1;
parameter BPP8 = 4'd2;
parameter BPP12 = 4'd3;
parameter BPP16 = 4'd4;
parameter BPP18 = 4'd5;
parameter BPP21 = 4'd6;
parameter BPP24 = 4'd7;
parameter BPP27 = 4'd8;
parameter BPP32 = 4'd9;
parameter BPP33 = 4'd10;
 
parameter OPBLACK = 4'd0;
parameter OPCOPY = 4'd1;
parameter OPINV = 4'd2;
parameter OPAND = 4'd4;
parameter OPOR = 4'd5;
parameter OPXOR = 4'd6;
parameter OPANDN = 4'd7;
parameter OPNAND = 4'd8;
parameter OPNOR = 4'd9;
parameter OPXNOR = 4'd10;
parameter OPORN = 4'd11;
parameter OPWHITE = 4'd15;
 
// Sync Generator defaults: 800x600 60Hz
parameter phSyncOn = 40; // 40 front porch
parameter phSyncOff = 168; // 128 sync
parameter phBlankOff = 252; //256 // 88 back porch
//parameter phBorderOff = 336; // 80 border
parameter phBorderOff = 256; // 80 border
//parameter phBorderOn = 976; // 640 display
parameter phBorderOn = 1056; // 800 display
parameter phBlankOn = 1052; // 4 border
parameter phTotal = 1056; // 1056 total clocks
parameter pvSyncOn = 1; // 1 front porch
parameter pvSyncOff = 5; // 4 vertical sync
parameter pvBlankOff = 28; // 23 back porch
parameter pvBorderOff = 28; // 44 border 0
//parameter pvBorderOff = 72; // 44 border 0
parameter pvBorderOn = 628; // 600 display
//parameter pvBorderOn = 584; // 512 display
parameter pvBlankOn = 628; // 44 border 0
parameter pvTotal = 628; // 628 total scan lines
 
 
// SYSCON
input rst_i; // system reset
output irq_o;
 
// Peripheral IO slave port
input s_clk_i;
input s_cs_i;
input s_cyc_i;
input s_stb_i;
output s_ack_o;
input s_we_i;
input [13:0] s_adr_i;
input [11:0] s_dat_i;
output [11:0] s_dat_o;
reg [11:0] s_dat_o;
 
// Video Memory Master Port
// Used to read memory via burst access
input m_clk_i; // system bus interface clock
output reg m_cyc_o; // video burst request
output reg m_stb_o;
output reg m_we_o;
output reg [MDW/12-1:0] m_sel_o;
input m_ack_i; // vid_acknowledge from memory
output reg [`ABITS] m_adr_o; // address for memory access
input [MDW-1:0] m_dat_i; // memory data input
output reg [MDW-1:0] m_dat_o;
 
// Video
input dot_clk_i; // Video clock 80 MHz
`ifdef INTERNAL_SYNC_GEN
output hsync_o;
output vsync_o;
output blank_o;
output vblank_o;
output border_o;
output [11:0] hctr_o;
output [11:0] vctr_o;
output [5:0] fctr_o;
`else
input hsync_i; // start/end of scan line
input vsync_i; // start/end of frame
input blank_i; // blank the output
`endif
output [31:0] zrgb_o; // 24-bit RGB output + z-order
reg [31:0] zrgb_o;
 
input xonoff_i;
output reg xal_o; // external access line (sprite access)
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// IO registers
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
reg irq_o;
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
wire vclk;
reg cs;
reg we;
reg [13:0] adri;
reg [11:0] dat;
 
always @(posedge s_clk_i)
cs <= s_cyc_i & s_stb_i & s_cs_i;
always @(posedge s_clk_i)
we <= s_we_i;
always @(posedge s_clk_i)
adri <= s_adr_i;
always @(posedge s_clk_i)
dat <= s_dat_i;
 
ack_gen #(
.READ_STAGES(2),
.WRITE_STAGES(0),
.REGISTER_OUTPUT(1)
) uag1
(
.rst_i(rst_i),
.clk_i(s_clk_i),
.ce_i(1'b1),
.i(cs),
.we_i(s_cyc_i & s_stb_i & s_cs_i & s_we_i),
.o(s_ack_o),
.rid_i(0),
.wid_i(0),
.rid_o(),
.wid_o()
);
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
integer n;
reg [11:0] rastcmp;
reg [`ABITS] bm_base_addr1,bm_base_addr2;
reg [3:0] color_depth;
wire [7:0] fifo_cnt;
reg onoff;
reg [2:0] hres,vres;
reg greyscale;
reg page;
reg [3:0] pals; // palette select
reg [15:0] hrefdelay;
reg [15:0] vrefdelay;
reg [15:0] windowLeft;
reg [15:0] windowTop;
reg [11:0] windowWidth,windowHeight;
reg [11:0] map; // memory access period
reg [11:0] mapctr;
reg [15:0] bmpWidth; // scan line increment (pixels)
reg [15:0] bmpHeight;
reg [`ABITS] baseAddr; // base address register
wire [MDW-1:0] rgbo1, rgbo1e, rgbo1o, rgbo1m;
reg [31:0] rgbo2,rgbo4;
reg [MDW-1:0] rgbo3;
reg [15:0] pixelRow;
reg [15:0] pixelCol;
wire [11:0] pal_wo;
wire [47:0] pal_o;
reg [15:0] px;
reg [15:0] py;
reg [11:0] pz;
reg [1:0] pcmd,pcmd_o;
reg [3:0] raster_op;
reg [32:0] oob_color;
reg [31:0] color;
reg [31:0] color_o;
reg rstcmd,rstcmd1;
reg [11:0] hTotal = phTotal;
reg [11:0] vTotal = pvTotal;
reg [11:0] hSyncOn = phSyncOn, hSyncOff = phSyncOff;
reg [11:0] vSyncOn = pvSyncOn, vSyncOff = pvSyncOff;
reg [11:0] hBlankOn = phBlankOn, hBlankOff = phBlankOff;
reg [11:0] vBlankOn = pvBlankOn, vBlankOff = pvBlankOff;
reg [11:0] hBorderOn = phBorderOn, hBorderOff = phBorderOff;
reg [11:0] vBorderOn = pvBorderOn, vBorderOff = pvBorderOff;
reg sgLock;
wire pe_hsync, pe_hsync2;
wire pe_vsync;
 
`ifdef INTERNAL_SYNC_GEN
wire hsync_i, vsync_i, blank_i;
 
VGASyncGen usg1
(
.rst(rst_i),
.clk(vclk),
.eol(),
.eof(),
.hSync(hsync_o),
.vSync(vsync_o),
.hCtr(hctr_o),
.vCtr(vctr_o),
.blank(blank_o),
.vblank(vblank),
.vbl_int(),
.border(border_o),
.hTotal_i(hTotal),
.vTotal_i(vTotal),
.hSyncOn_i(hSyncOn),
.hSyncOff_i(hSyncOff),
.vSyncOn_i(vSyncOn),
.vSyncOff_i(vSyncOff),
.hBlankOn_i(hBlankOn),
.hBlankOff_i(hBlankOff),
.vBlankOn_i(vBlankOn),
.vBlankOff_i(vBlankOff),
.hBorderOn_i(hBorderOn),
.hBorderOff_i(hBorderOff),
.vBorderOn_i(vBorderOn),
.vBorderOff_i(vBorderOff)
);
assign hsync_i = hsync_o;
assign vsync_i = vsync_o;
assign blank_i = blank_o;
assign vblank_o = vblank;
`endif
 
edge_det edcs1
(
.rst(rst_i),
.clk(s_clk_i),
.ce(1'b1),
.i(cs),
.pe(cs_edge),
.ne(),
.ee()
);
 
// Frame counter
//
VT163 #(6) ub1
(
.clk(vclk),
.clr_n(!rst_i),
.ent(pe_vsync),
.enp(1'b1),
.ld_n(1'b1),
.d(6'd0),
.q(fctr_o),
.rco()
);
 
reg rst_irq;
always_ff @(posedge vclk)
if (rst_i)
irq_o <= `LOW;
else begin
if (hctr_o==12'd02 && rastcmp==vctr_o)
irq_o <= `HIGH;
else if (rst_irq)
irq_o <= `LOW;
end
 
always @(page or bm_base_addr1 or bm_base_addr2)
baseAddr = page ? bm_base_addr2 : bm_base_addr1;
 
// Color palette RAM for 8bpp modes
syncRam512x48_1rw1r upal1 // Actually 1024x48
(
.clka(s_clk_i), // input wire clka
.ena(cs & adri[13]), // input wire ena
.wea(we), // input wire [3 : 0] wea
.addra(adri[11:0]), // input wire [8 : 0] addra
.dina(dat), // input wire [31 : 0] dina
.douta(pal_wo), // output wire [31 : 0] douta
.clkb(vclk), // input wire clkb
.enb(1'b1), // input wire enb
.web(1'b0), // input wire [3 : 0] web
.addrb({pals[2:0],rgbo4[5:0]}), // input wire [8 : 0] addrb
.dinb(48'h0), // input wire [31 : 0] dinb
.doutb(pal_o) // output wire [31 : 0] doutb
);
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
always_ff @(posedge s_clk_i)
if (rst_i) begin
page <= 1'b0;
pals <= 4'h0;
hres <= 3'd2;
vres <= 3'd2;
windowWidth <= 12'd400;
windowHeight <= 12'd300;
onoff <= 1'b0;
color_depth <= BPP16;
greyscale <= 1'b0;
bm_base_addr1 <= BM_BASE_ADDR1;
bm_base_addr2 <= BM_BASE_ADDR2;
hrefdelay = 16'hFF99;//12'd103;
vrefdelay = 16'hFFF3;//12'd13;
windowLeft <= 16'h0;
windowTop <= 16'h0;
windowWidth <= 16'd400;
windowHeight <= 16'd300;
bmpWidth <= 16'd400;
bmpHeight <= 16'd300;
map <= MAP;
pcmd <= 2'b00;
rstcmd1 <= 1'b0;
rst_irq <= 1'b0;
rastcmp <= 12'hFFF;
oob_color <= 32'h00003C00;
end
else begin
rstcmd1 <= rstcmd;
rst_irq <= 1'b0;
if (rstcmd & ~rstcmd1)
pcmd <= 2'b00;
if (cs_edge) begin
if (we) begin
casez(adri[13:3])
REG_CTRL:
case(adri[2:0])
3'd0: onoff <= dat[0];
3'd1:
begin
color_depth <= dat[3:0];
greyscale <= dat[4];
end
3'd2:
begin
hres <= dat[2:0];
vres <= dat[6:4];
end
3'd3:
begin
page <= dat[0];
pals <= dat[3:1];
end
3'd6: ;
3'd7: map[11:0] <= dat;
default: ;
endcase
REG_REFDELAY:
case(adri[2:0])
3'd0: hrefdelay[15:12] <= dat[3:0];
3'd1: hrefdelay[11: 0] <= dat;
3'd2: vrefdelay[15:12] <= dat[3:0];
3'd3: vrefdelay[11: 0] <= dat;
default: ;
endcase
REG_PAGE1ADDR:
case(adri[2:0])
3'd1: bm_base_addr1[31:24] <= dat[7:0];
3'd2: bm_base_addr1[23:12] <= dat;
3'd3: bm_base_addr1[11: 0] <= dat;
default: ;
endcase
REG_PAGE2ADDR:
case(adri[2:0])
3'd1: bm_base_addr2[31:24] <= dat[7:0];
3'd2: bm_base_addr2[23:12] <= dat;
3'd3: bm_base_addr2[11: 0] <= dat;
default: ;
endcase
REG_PXYZ:
case(adri[2:0])
3'd0: px[15:12] <= dat[3:0];
3'd1: px[11: 0] <= dat;
3'd2: py[15:12] <= dat[3:0];
3'd3: py[11: 0] <= dat;
3'd5: pz[11: 0] <= dat;
default: ;
endcase
REG_PCOLCMD:
case(adri[2:0])
3'd0: pcmd <= dat[1:0];
3'd2: raster_op <= dat[3:0];
3'd4: ;
3'd5: color[31:24] <= dat[7:0];
3'd6: color[23:12] <= dat;
3'd7: color[11: 0] <= dat;
default: ;
endcase
REG_RASTCMP:
case(adri[2:0])
3'd0: ;
3'd1: rastcmp[11: 0] <= dat;
3'd7: rst_irq <= dat[11];
default: ;
endcase
REG_BMPSIZE:
case(adri[2:0])
3'd2: bmpWidth[15:12] <= dat[3:0];
3'd3: bmpWidth[11:0] <= dat;
3'd6: bmpHeight[15:12] <= dat[3:0];
3'd7: bmpHeight[11:0] <= dat;
default: ;
endcase
REG_OOB_COLOR:
case(adri[2:0])
3'd1: oob_color[31:24] <= dat[7:0];
3'd2: oob_color[23:12] <= dat;
3'd3: oob_color[11: 0] <= dat;
default: ;
endcase
REG_WINDOW:
case(adri[2:0])
3'd0: windowWidth <= dat;
3'd1: windowHeight <= dat;
3'd4: windowLeft[15:12] <= dat[3:0];
3'd5: windowLeft[11: 0] <= dat;
3'd6: windowTop[15:12] <= dat[3:0];
3'd7: windowTop[11: 0] <= dat;
endcase
 
`ifdef INTERNAL_SYNC_GEN
REG_TOTAL:
case(adri[2:0])
3'd0: if (!sgLock) hTotal <= dat;
3'd1: if (!sgLock) vTotal <= dat;
3'd7: if (dat==12'hA12)
sgLock <= 1'b1;
else if (dat==12'h21A)
sgLock <= 1'b0;
default: ;
endcase
REG_SYNC_ONOFF:
case(adri[2:0])
3'd0: if (!sgLock) hSyncOff <= dat;
3'd1: if (!sgLock) hSyncOn <= dat;
3'd2: if (!sgLock) vSyncOff <= dat;
3'd3: if (!sgLock) vSyncOn <= dat;
default: ;
endcase
REG_BLANK_ONOFF:
case(adri[2:0])
3'd0: if (!sgLock) hBlankOff <= dat;
3'd1: if (!sgLock) hBlankOn <= dat;
3'd2: if (!sgLock) vBlankOff <= dat;
3'd3: if (!sgLock) vBlankOn <= dat;
default: ;
endcase
REG_BORDER_ONOFF:
case(adri[2:0])
3'd0: if (!sgLock) hBorderOff <= dat;
3'd1: if (!sgLock) hBorderOn <= dat;
3'd2: if (!sgLock) vBorderOff <= dat;
3'd3: if (!sgLock) vBorderOn <= dat;
default: ;
endcase
`endif
default: ;
endcase
end
end
if (s_cs_i)
casez(adri[13:3])
REG_CTRL: ;
/*
begin
s_dat_o[0] <= onoff;
s_dat_o[10:8] <= color_depth;
s_dat_o[12] <= greyscale;
s_dat_o[18:16] <= hres;
s_dat_o[22:20] <= vres;
s_dat_o[24] <= page;
s_dat_o[28:25] <= pals;
s_dat_o[47:32] <= bmpWidth;
s_dat_o[59:48] <= map;
end
*/
REG_REFDELAY:
case(adri[2:0])
3'd0: s_dat_o <= {8'h00,hrefdelay[15:12]};
3'd1: s_dat_o <= hrefdelay[11: 0];
3'd2: s_dat_o <= {8'h00,vrefdelay[15:12]};
3'd3: s_dat_o <= vrefdelay[11: 0];
default: s_dat_o <= 12'h0;
endcase
REG_PAGE1ADDR:
case(adri[2:0])
3'd1: s_dat_o <= {4'h0,bm_base_addr1[31:24]};
3'd2: s_dat_o <= bm_base_addr1[23:12];
3'd3: s_dat_o <= bm_base_addr1[11: 0];
default: s_dat_o <= 12'h0;
endcase
REG_PAGE2ADDR:
case(adri[2:0])
3'd1: s_dat_o <= {4'h0,bm_base_addr2[31:24]};
3'd2: s_dat_o <= bm_base_addr2[23:12];
3'd3: s_dat_o <= bm_base_addr2[11: 0];
default: s_dat_o <= 12'h0;
endcase
REG_PXYZ:
case(adri[2:0])
3'd0: s_dat_o <= {8'h00,px[15:12]};
3'd1: s_dat_o <= px[11: 0];
3'd2: s_dat_o <= {8'h00,py[15:12]};
3'd3: s_dat_o <= py[11: 0];
3'd5: s_dat_o <= pz[11: 0];
default: s_dat_o <= 12'h0;
endcase
REG_PCOLCMD:
case(adri[2:0])
3'd0: s_dat_o <= {10'h0,pcmd};
3'd2: s_dat_o <= {8'h0,raster_op};
3'd5: s_dat_o <= {4'h0,color[31:24]};
3'd6: s_dat_o <= color[23:12];
3'd7: s_dat_o <= color[11: 0];
default: s_dat_o <= 12'h0;
endcase
REG_OOB_COLOR:
case(adri[2:0])
3'd1: s_dat_o <= {4'h0,oob_color[31:24]};
3'd2: s_dat_o <= oob_color[23:12];
3'd3: s_dat_o <= oob_color[11: 0];
default: s_dat_o <= 12'h0;
endcase
REG_WINDOW:
case(adri[2:0])
3'd0: s_dat_o <= windowWidth <= dat;
3'd1: s_dat_o <= windowHeight <= dat;
3'd4: s_dat_o <= {8'h00,windowLeft[15:12]};
3'd5: s_dat_o <= windowLeft[11: 0];
3'd6: s_dat_o <= {8'h00,windowTop[15:12]};
3'd7: s_dat_o <= windowTop[11: 0];
default: s_dat_o <= 12'h0;
endcase
11'b1?_????_????_?: s_dat_o <= pal_wo;
default: s_dat_o <= 12'd0;
endcase
else
s_dat_o <= 12'h0;
end
 
//`ifdef USE_CLOCK_GATE
//BUFHCE ucb1
//(
// .I(dot_clk_i),
// .CE(onoff),
// .O(vclk)
//);
//`else
assign vclk = dot_clk_i;
//`endif
 
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Horizontal and Vertical timing reference counters
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
reg lef; // load even fifo
reg lof; // load odd fifo
 
edge_det edh1
(
.rst(rst_i),
.clk(vclk),
.ce(1'b1),
.i(hsync_i),
.pe(pe_hsync),
.ne(),
.ee()
);
 
edge_det edh2
(
.rst(1'b0),
.clk(m_clk_i),
.ce(1'b1),
.i(hsync_i),
.pe(pe_hsync2),
.ne(),
.ee()
);
 
edge_det edv1
(
.rst(rst_i),
.clk(vclk),
.ce(1'b1),
.i(vsync_i),
.pe(pe_vsync),
.ne(),
.ee()
);
 
reg [3:0] hc = 4'd1;
always_ff @(posedge vclk)
if (pe_hsync) begin
hc <= 4'd1;
pixelCol <= hrefdelay;
end
else begin
if (hc==hres) begin
hc <= 4'd1;
pixelCol <= pixelCol + 16'd1;
end
else
hc <= hc + 4'd1;
end
 
reg [3:0] vc = 4'd1;
always_ff @(posedge vclk)
if (pe_vsync) begin
vc <= 4'd1;
pixelRow <= vrefdelay;
end
else begin
if (pe_hsync) begin
vc <= vc + 4'd1;
if (vc==vres) begin
vc <= 4'd1;
pixelRow <= pixelRow + 16'd1;
end
end
end
always_comb
lef = ~pixelRow[0];
always_comb
lof = pixelRow[0];
 
always_ff @(posedge vclk)
xal_o <= vc != 4'd1;
 
// Bits per pixel minus one.
reg [4:0] bpp;
always_comb
case(color_depth)
BPP6: bpp = 5;
BPP8: bpp = 7;
BPP12: bpp = 11;
BPP16: bpp = 15;
BPP18: bpp = 17;
BPP21: bpp = 20;
BPP24: bpp = 23;
BPP27: bpp = 26;
BPP32: bpp = 31;
BPP33: bpp = 32;
default: bpp = 15;
endcase
 
reg [5:0] shifts;
always_comb
case(MDW)
96:
case(color_depth)
BPP6: shifts = 6'd16;
BPP8: shifts = 6'd12;
BPP12: shifts = 6'd8;
BPP16: shifts = 6'd6;
BPP18: shifts = 6'd5;
BPP21: shifts = 6'd4;
BPP24: shifts = 6'd4;
BPP27: shifts = 6'd3;
BPP32: shifts = 6'd3;
BPP33: shifts = 6'd2;
default: shifts = 6'd8;
endcase
default:
begin
$display("rfFrameBuffer_x12: Bad master bus width");
$finish;
end
endcase
 
wire vFetch = !vblank;//pixelRow < windowHeight;
reg fifo_rrst;
reg fifo_wrst;
always_comb fifo_rrst = pixelCol==16'hFFFF;
always_comb fifo_wrst = pe_hsync2 && vc==4'd1;
 
wire[31:0] grAddr,xyAddr;
reg [11:0] fetchCol;
localparam CMS = MDW==128 ? 6 : MDW==64 ? 5 : 4;
wire [CMS:0] mb,me,ce;
reg [MDW-1:0] mem_strip;
wire [MDW-1:0] mem_strip_o;
wire [31:0] mem_color;
 
// Compute fetch address
gfx_calc_address #(MDW) u1
(
.clk(m_clk_i),
.base_address_i(baseAddr),
.color_depth_i(color_depth),
.bmp_width_i(bmpWidth),
.x_coord_i(windowLeft),
.y_coord_i(windowTop + pixelRow),
.address_o(grAddr),
.mb_o(),
.me_o(),
.ce_o()
);
 
// Compute address for get/set pixel
gfx_calc_address #(MDW) u2
(
.clk(m_clk_i),
.base_address_i(baseAddr),
.color_depth_i(color_depth),
.bmp_width_i(bmpWidth),
.x_coord_i(px),
.y_coord_i(py),
.address_o(xyAddr),
.mb_o(mb),
.me_o(me),
.ce_o(ce)
);
 
always_ff @(posedge m_clk_i)
if (pe_hsync2)
mapctr <= 12'hFFE;
else begin
if (mapctr == map)
mapctr <= 12'd0;
else
mapctr <= mapctr + 12'd1;
end
wire memreq = mapctr==12'd0 && vc==4'd1;
 
// The following bypasses loading the fifo when all the pixels from a scanline
// are buffered in the fifo and the pixel row doesn't change. Since the fifo
// pointers are reset at the beginning of a scanline, the fifo can be used like
// a cache.
wire blankEdge;
edge_det ed2(.rst(rst_i), .clk(m_clk_i), .ce(1'b1), .i(blank_i), .pe(blankEdge), .ne(), .ee() );
reg do_loads;
reg load_fifo = 1'b0;
always_ff @(posedge m_clk_i)
//load_fifo <= fifo_cnt < 10'd1000 && vFetch && onoff && xonoff && !m_cyc_o && do_loads;
load_fifo <= /*fifo_cnt < 8'd224 &&*/ vFetch && onoff && xonoff_i && (fetchCol < windowWidth) && memreq;
// The following table indicates the number of pixel that will fit into the
// video fifo.
reg [11:0] hCmp;
always_comb
case(color_depth)
BPP6: hCmp = 128 * $floor(MDW/6); // must fit in 12 bits
BPP8: hCmp = 128 * $floor(MDW/8);
BPP12: hCmp = 128 * $floor(MDW/12);
BPP16: hCmp = 128 * $floor(MDW/16);
BPP18: hCmp = 128 * $floor(MDW/18);
BPP21: hCmp = 128 * $floor(MDW/21);
BPP24: hCmp = 128 * $floor(MDW/24);
BPP27: hCmp = 128 * $floor(MDW/27);
BPP32: hCmp = 128 * $floor(MDW/32);
BPP33: hCmp = 128 * $floor(MDW/33);
default: hCmp = 128 * $floor(MDW/16);
endcase
/*
always @(posedge m_clk_i)
// if windowWidth > hCmp we always load because the fifo isn't large enough to act as a cache.
if (!(windowWidth < hCmp))
do_loads <= 1'b1;
// otherwise load the fifo only when the row changes to conserve memory bandwidth
else if (vc==4'd1)//pixelRow != opixelRow)
do_loads <= 1'b1;
else if (blankEdge)
do_loads <= 1'b0;
*/
always_comb m_stb_o = m_cyc_o;
always_comb m_sel_o = MDW==128 ? 16'hFFFF : MDW==64 ? 8'hFF : 4'hF;
 
reg [31:0] adr;
reg [3:0] state;
reg [127:0] icolor1;
parameter IDLE = 4'd0;
parameter LOADCOLOR = 4'd2;
parameter LOADSTRIP = 4'd3;
parameter STORESTRIP = 4'd4;
parameter ACKSTRIP = 4'd5;
parameter WAITLOAD = 4'd6;
parameter WAITRST = 4'd7;
parameter ICOLOR1 = 4'd8;
parameter ICOLOR2 = 4'd9;
parameter ICOLOR3 = 4'd10;
parameter ICOLOR4 = 4'd11;
parameter WAIT_NACK = 4'd12;
parameter LOAD_OOB = 4'd13;
 
function rastop;
input [3:0] op;
input a;
input b;
case(op)
OPBLACK: rastop = 1'b0;
OPCOPY: rastop = b;
OPINV: rastop = ~a;
OPAND: rastop = a & b;
OPOR: rastop = a | b;
OPXOR: rastop = a ^ b;
OPANDN: rastop = a & ~b;
OPNAND: rastop = ~(a & b);
OPNOR: rastop = ~(a | b);
OPXNOR: rastop = ~(a ^ b);
OPORN: rastop = a | ~b;
OPWHITE: rastop = 1'b1;
default: rastop = 1'b0;
endcase
endfunction
 
always_ff @(posedge m_clk_i)
if (fifo_wrst)
adr <= grAddr;
else begin
if ((state==WAITLOAD && m_ack_i) || state==LOAD_OOB)
case(MDW)
32: adr <= adr + 32'd4;
64: adr <= adr + 32'd8;
default: adr <= adr + 32'd16;
endcase
end
 
always_ff @(posedge m_clk_i)
if (fifo_wrst)
fetchCol <= 12'd0;
else begin
if ((state==WAITLOAD && m_ack_i) || state==LOAD_OOB)
fetchCol <= fetchCol + shifts;
end
 
// Check for legal (positive) coordinates
// Illegal coordinates result in a red display
wire [15:0] xcol = fetchCol;
reg legal_x, legal_y;
always_comb legal_x = ~&xcol[15:12] && xcol < bmpWidth;
always_comb legal_y = ~&pixelRow[15:12] && pixelRow < bmpHeight;
 
reg modd;
always_comb
case(MDW)
32: modd <= m_adr_o[5:2]==4'hF;
64: modd <= m_adr_o[5:3]==3'h7;
default: modd <= m_adr_o[5:4]==2'h3;
endcase
 
always @(posedge m_clk_i)
if (rst_i) begin
wb_nack();
rstcmd <= 1'b0;
state <= IDLE;
end
else begin
case(state)
WAITRST:
if (pcmd==2'b00 && ~m_ack_i) begin
rstcmd <= 1'b0;
state <= IDLE;
end
else
rstcmd <= 1'b1;
IDLE:
if (load_fifo && !(legal_x && legal_y))
state <= LOAD_OOB;
else if (load_fifo & ~m_ack_i) begin
m_cyc_o <= `HIGH;
m_we_o <= `LOW;
m_adr_o <= adr;
state <= WAITLOAD;
end
// The adr_o[5:3]==3'b111 causes the controller to wait until all eight
// 64 bit strips from the memory controller have been processed. Otherwise
// there would be cache thrashing in the memory controller and the memory
// bandwidth available would be greatly reduced. However fetches are also
// allowed when loads are not active or all strips for the current scan-
// line have been fetched.
else if (pcmd!=2'b00 && (modd || !(vFetch && onoff && xonoff_i && fetchCol < windowWidth))) begin
m_cyc_o <= `HIGH;
m_we_o <= `LOW;
m_adr_o <= xyAddr;
state <= LOADSTRIP;
end
LOADSTRIP:
if (m_ack_i) begin
wb_nack();
mem_strip <= m_dat_i;
icolor1 <= {96'b0,color} << mb;
rstcmd <= 1'b1;
if (pcmd==2'b01)
state <= ICOLOR3;
else if (pcmd==2'b10)
state <= ICOLOR2;
else begin
state <= WAITRST;
end
end
// Registered inline mem2color
ICOLOR3:
begin
color_o <= mem_strip >> mb;
state <= ICOLOR4;
end
ICOLOR4:
begin
for (n = 0; n < 32; n = n + 1)
color_o[n] <= (n <= bpp) ? color_o[n] : 1'b0;
state <= pcmd == 2'b0 ? (~m_ack_i ? IDLE : WAITRST) : WAITRST;
if (pcmd==2'b00)
rstcmd <= 1'b0;
end
// Registered inline color2mem
ICOLOR2:
begin
for (n = 0; n < MDW; n = n + 1)
m_dat_o[n] <= (n >= mb && n <= me)
? ((n <= ce) ? rastop(raster_op, mem_strip[n], icolor1[n]) : icolor1[n])
: mem_strip[n];
state <= STORESTRIP;
end
STORESTRIP:
if (~m_ack_i) begin
m_cyc_o <= `HIGH;
m_we_o <= `HIGH;
state <= ACKSTRIP;
end
ACKSTRIP:
if (m_ack_i) begin
wb_nack();
state <= pcmd == 2'b0 ? IDLE : WAITRST;
if (pcmd==2'b00)
rstcmd <= 1'b0;
end
WAITLOAD:
if (m_ack_i) begin
wb_nack();
state <= IDLE;
end
LOAD_OOB:
state <= IDLE;
WAIT_NACK:
if (~m_ack_i)
state <= IDLE;
default: state <= IDLE;
endcase
end
 
task wb_nack;
begin
m_cyc_o <= `LOW;
m_we_o <= `LOW;
end
endtask
 
always_ff @(posedge vclk)
case(color_depth)
BPP6: rgbo4 <= {rgbo3[5:3],5'h00,21'd0,rgbo3[2:0]}; // feeds into palette
BPP8: rgbo4 <= {rgbo3[7:5],6'h00,18'h0,rgbo3[4:0]}; // feeds into palette
BPP12: rgbo4 <= {rgbo3[11:9],5'd0,rgbo3[8:6],5'd0,rgbo3[5:3],5'd0,rgbo3[2:0],5'd0};
BPP16: rgbo4 <= {rgbo3[15:13],5'b0,rgbo3[11:8],4'b0,rgbo3[7:4],4'b0,rgbo3[3:0],4'b0};
BPP18: rgbo4 <= {rgbo3[17:15],5'b0,rgbo3[14:10],3'b0,rgbo3[9:5],3'b0,rgbo3[4:0],3'b0};
BPP21: rgbo4 <= {rgbo3[20:18],5'b0,rgbo3[17:12],2'b0,rgbo3[11:6],2'b0,rgbo3[5:0],2'b0};
BPP24: rgbo4 <= {rgbo3[23:21],5'b0,rgbo3[20:14],1'b0,rgbo3[13:7],1'b0,rgbo3[6:0],1'b0};
BPP27: rgbo4 <= {rgbo3[26:24],5'b0,rgbo3[23:16],rgbo3[15:8],rgbo3[7:0]};
BPP32: rgbo4 <= {rgbo3[31:29],2'b0,rgbo3[26:18],rgbo3[17:9],rgbo3[8:0]};
default: rgbo4 <= {rgbo3[15:13],5'b0,rgbo3[11:8],4'b0,rgbo3[7:4],4'b0,rgbo3[3:0],4'b0};
endcase
 
reg rd_fifo,rd_fifo1,rd_fifo2;
reg de;
always_ff @(posedge vclk)
if (rd_fifo1)
de <= ~blank_i;
 
always_ff @(posedge vclk)
if (onoff && xonoff_i && !blank_i) begin
if (color_depth[2:1]==2'b00) begin
if (!greyscale)
zrgb_o <= pal_o[31:0];
else
zrgb_o <= {pal_o[31:24],{3{pal_o[7:0]}}};
end
else
zrgb_o <= rgbo4;
end
else
zrgb_o <= 32'h00000000;
 
// Before the hrefdelay expires, pixelCol will be negative, which is greater
// than windowWidth as the value is unsigned. That means that fifo reading is
// active only during the display area 0 to windowWidth.
reg shift1;
always_comb shift1 = hc==hres;
reg [5:0] shift_cnt;
always_ff @(posedge vclk)
if (pe_hsync)
shift_cnt <= 5'd1;
else begin
if (shift1) begin
if (pixelCol==16'hFFFF)
shift_cnt <= shifts;
else if (!pixelCol[15]) begin
shift_cnt <= shift_cnt + 5'd1;
if (shift_cnt==shifts)
shift_cnt <= 5'd1;
end
else
shift_cnt <= 5'd1;
end
end
 
reg next_strip;
always_comb next_strip = (shift_cnt==shifts) && (hc==hres);
 
wire vrd;
reg shift,shift2;
always_ff @(posedge vclk) shift2 <= shift1;
always_ff @(posedge vclk) shift <= shift2;
always_ff @(posedge vclk) rd_fifo2 <= next_strip;
always_ff @(posedge vclk) rd_fifo <= rd_fifo2;
always_ff @(posedge vclk)
if (rd_fifo)
rgbo3 <= lef ? rgbo1o : rgbo1e;
else if (shift) begin
case(color_depth)
BPP6: rgbo3 <= {4'h0,rgbo3[MDW-1:6]};
BPP8: rgbo3 <= {8'h0,rgbo3[MDW-1:8]};
BPP12: rgbo3 <= {12'h0,rgbo3[MDW-1:12]};
BPP16: rgbo3 <= {16'h0,rgbo3[MDW-1:16]};
BPP18: rgbo3 <= {18'h0,rgbo3[MDW-1:18]};
BPP21: rgbo3 <= {21'h0,rgbo3[MDW-1:21]};
BPP24: rgbo3 <= {24'h0,rgbo3[MDW-1:24]};
BPP27: rgbo3 <= {27'h0,rgbo3[MDW-1:27]};
BPP32: rgbo3 <= {32'h0,rgbo3[MDW-1:32]};
BPP32: rgbo3 <= {33'h0,rgbo3[MDW-1:33]};
default: rgbo3 <= {16'h0,rgbo3[MDW-1:16]};
endcase
end
 
 
/* Debugging
wire [127:0] dat;
assign dat[11:0] = pixelRow[0] ? 12'hEA4 : 12'h000;
assign dat[23:12] = pixelRow[1] ? 12'hEA4 : 12'h000;
assign dat[35:24] = pixelRow[2] ? 12'hEA4 : 12'h000;
assign dat[47:36] = pixelRow[3] ? 12'hEA4 : 12'h000;
assign dat[59:48] = pixelRow[4] ? 12'hEA4 : 12'h000;
assign dat[71:60] = pixelRow[5] ? 12'hEA4 : 12'h000;
assign dat[83:72] = pixelRow[6] ? 12'hEA4 : 12'h000;
assign dat[95:84] = pixelRow[7] ? 12'hEA4 : 12'h000;
assign dat[107:96] = pixelRow[8] ? 12'hEA4 : 12'h000;
assign dat[119:108] = pixelRow[9] ? 12'hEA4 : 12'h000;
*/
 
reg [MDW-1:0] oob_dat;
always_comb
case(color_depth)
BPP6: oob_dat <= {MDW/6{oob_color[5:0]}};
BPP8: oob_dat <= {MDW/8{oob_color[7:0]}};
BPP12: oob_dat <= {MDW/12{oob_color[11:0]}};
BPP16: oob_dat <= {MDW/16{oob_color[15:0]}};
BPP18: oob_dat <= {MDW/18{oob_color[17:0]}};
BPP21: oob_dat <= {MDW/21{oob_color[20:0]}};
BPP24: oob_dat <= {MDW/24{oob_color[23:0]}};
BPP27: oob_dat <= {MDW/27{oob_color[26:0]}};
BPP32: oob_dat <= {MDW/32{oob_color[31:0]}};
BPP33: oob_dat <= {MDW/33{oob_color[32:0]}};
default: oob_dat <= {MDW/16{oob_color[15:0]}};
endcase
 
rfVideoFifo #(MDW) uf1
(
.wrst(fifo_wrst),
.wclk(m_clk_i),
.wr(((m_ack_i && state==WAITLOAD) || state==LOAD_OOB) && lef),
.di((state==LOAD_OOB) ? oob_dat : m_dat_i),
.rrst(fifo_rrst),
.rclk(vclk),
.rd(rd_fifo & lof),
.dout(rgbo1e),
.cnt()
);
 
rfVideoFifo #(MDW) uf2
(
.wrst(fifo_wrst),
.wclk(m_clk_i),
.wr(((m_ack_i && state==WAITLOAD) || state==LOAD_OOB) && lof),
.di((state==LOAD_OOB) ? oob_dat : m_dat_i),
.rrst(fifo_rrst),
.rclk(vclk),
.rd(rd_fifo & lef),
.dout(rgbo1o),
.cnt()
);
 
endmodule
/trunk/rtl/noc/video/rfSpriteController_x12.sv
0,0 → 1,1067
`timescale 1ns / 1ps
// ============================================================================
// __
// \\__/ o\ (C) 2005-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// rfSpriteController_x12.v
// sprite / hardware cursor controller, 12-bit slave bus
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Sprite Controller
//
// FEATURES
// - parameterized number of sprites 1,2,4,6,8,14 or 32
// - sprite image cache buffers
// - each image cache is capable of holding multiple
// sprite images
// - an embedded DMA controller is used for sprite reload
// - programmable image offset within cache
// - programmable sprite width,height, and pixel size
// - sprite width and height may vary from 1 to 64 as long
// as the product doesn't exceed 4096.
// - pixels may be programmed to be 1,2,3 or 4 video clocks
// both height and width are programmable
// - programmable sprite position
// - programmable 8, 16 or 32 bits for color
// eg 32k color + 1 bit alpha blending indicator (1,5,5,5)
// - fixed display and DMA priority
// sprite 0 highest, sprite 31 lowest
// - graphics plane control
//
// This core requires an external timing generator to
// provide horizontal and vertical sync signals, but
// otherwise can be used as a display controller on it's
// own. However, normally this core would be embedded
// within another core such as a VGA controller. Sprite
// positions are referenced to the rising edge of the
// vertical and horizontal sync pulses.
// The core includes an embedded dual port RAM to hold the
// sprite images. The image RAM is updated using a built in DMA
// controller. The DMA controller uses 32 bit accesses to fill
// the sprite buffers. The circuit features an automatic bus
// transaction timeout; if the system bus hasn't responded
// within 20 clock cycles, the DMA controller moves onto the
// next address.
// The controller uses a ram underlay to cache the values
// of the registers. This is a lot cheaper resource wise than
// using a 32 to 1 multiplexor (well at least for an FPGA).
//
// All registers are 32 bits wide
//
// These registers repeat in incrementing block of four registers
// and pertain to each sprite
// 00: - position register
// HPOS [11: 0] horizontal position (hctr value)
// VPOS [27:16] vertical position (vctr value)
//
// 04: SZ - size register
// bits
// [ 7: 0] width of sprite in pixels - 1
// [15: 8] height of sprite in pixels -1
// [19:16] size of horizontal pixels - 1 in clock cycles
// [23:20] size of vertical pixels in scan-lines - 1
// * the product of width * height cannot exceed 2048 !
// if it does, the display will begin repeating
// [27:24] output plane
// [31:30] color depth 01=RGB332,10=RGB555+A,11=RGB888+A
//
// 08: ADR [31:12] 20 bits sprite image address bits
// This registers contain the high order address bits of the
// location of the sprite image in system memory.
// The DMA controller will assign the low order 12 bits
// during DMA.
// [11:0] image offset bits [11:0]
// offset of the sprite image within the sprite image cache
// typically zero
//
// 0C: TC [23:0] transparent color
// This register identifies which color of the sprite
// is transparent
//
//
//
// 0C-1FC: registers reserved for up to thirty-one other sprites
//
// 200: DMA burst reg sprite 0
// [8:0] burst start
// [24:16] burst end
// ...
// 27C: DMA burst reg sprite 31
//
// Global status and control
// 3C0: EN [31:0] sprite enable register
// 3C4: IE [31:0] sprite interrupt enable / status
// 3C8: SCOL [31:0] sprite-sprite collision register
// 3CC: BCOL [31:0] sprite-background collision register
// 3D0: DT [31:0] sprite DMA trigger on
// 3D4: DT [31:0] sprite DMA trigger off
// 3D8: VDT [31:0] sprite vertical sync DMA trigger
// 3EC: BC [23:0] background color
// 3FC: ADDR [31:0] sprite DMA address bits [63:32]
//
//=============================================================================
 
module rfSpriteController_x12(
// Bus Slave interface
//------------------------------
// Slave signals
input rst_i, // reset
input s_clk_i, // clock
input s_cs_i,
input s_cyc_i, // cycle valid
input s_stb_i, // data transfer
output s_ack_o, // transfer acknowledge
input s_we_i, // write
input [ 9:0] s_adr_i, // address
input [11:0] s_dat_i, // data input
output reg [11:0] s_dat_o, // data output
//------------------------------
// Bus Master Signals
input m_clk_i, // clock
output [1:0] m_bte_o,
output [2:0] m_cti_o,
output reg m_cyc_o, // cycle is valid
output m_stb_o, // strobe output
input m_ack_i, // input data is ready
input m_err_i,
output m_we_o,
output [3:0] m_sel_o,
output reg [35:0] m_adr_o, // DMA address
input [47:0] m_dat_i, // data input
output [47:0] m_dat_o,
output [4:0] m_spriteno_o,
//--------------------------
input dot_clk_i, // video dot clock
input hsync_i, // horizontal sync pulse
input vsync_i, // vertical sync pulse
input blank_i, // blanking signal
//input [3:0] rgbPlane_i, // 0 = background, higher numbers closer to front
input [31:0] zrgb_i, // input pixel stream
//output reg [3:0] rgbPlane_o,
output [31:0] zrgb_o, // output pixel stream
output irq, // interrupt request
input test
);
 
reg m_soc_o;
wire vclk = dot_clk_i;
wire hSync = hsync_i;
wire vSync = vsync_i;
wire [31:0] zrgbIn = zrgb_i;
reg [31:0] zrgbOut;
assign zrgb_o = zrgbOut;
 
//--------------------------------------------------------------------
// Core Parameters
//--------------------------------------------------------------------
parameter pnSpr = 32; // number of sprites
parameter phBits = 12; // number of bits in horizontal timing counter
parameter pvBits = 12; // number of bits in vertical timing counter
localparam pnSprm = pnSpr-1;
 
 
//--------------------------------------------------------------------
// Variable Declarations
//--------------------------------------------------------------------
 
reg [9:0] adr_i;
reg [11:0] dat_i;
reg we_i;
 
wire [4:0] sprN = adr_i[8:4];
 
reg [phBits-1:0] hctr; // horizontal reference counter (counts dots since hSync)
reg [pvBits-1:0] vctr; // vertical reference counter (counts scanlines since vSync)
reg sprSprIRQ;
reg sprBkIRQ;
 
reg [23:0] out; // sprite output
reg outact; // sprite output is active
reg [3:0] outplane;
reg [pnSprm:0] bkCollision; // sprite-background collision
reg [23:0] bgTc; // background transparent color
reg [23:0] bkColor; // background color
 
 
reg [pnSprm:0] sprWe; // block ram write enable for image cache update
reg [pnSprm:0] sprRe; // block ram read enable for image cache update
 
// Global control registers
reg [31:0] sprEn; // enable sprite
reg [pnSprm:0] sprCollision; // sprite-sprite collision
reg sprSprIe; // sprite-sprite interrupt enable
reg sprBkIe; // sprite-background interrupt enable
reg sprSprIRQPending; // sprite-sprite collision interrupt pending
reg sprBkIRQPending; // sprite-background collision interrupt pending
reg sprSprIRQPending1; // sprite-sprite collision interrupt pending
reg sprBkIRQPending1; // sprite-background collision interrupt pending
reg sprSprIRQ1; // vclk domain regs
reg sprBkIRQ1;
 
// Sprite control registers
reg [31:0] sprSprCollision;
reg [pnSprm:0] sprSprCollision1;
reg [31:0] sprBkCollision;
reg [pnSprm:0] sprBkCollision1;
reg [23:0] sprTc [pnSprm:0]; // sprite transparent color code
// How big the pixels are:
// 1 to 16 video clocks
reg [3:0] hSprRes [pnSprm:0]; // sprite horizontal resolution
reg [3:0] vSprRes [pnSprm:0]; // sprite vertical resolution
reg [7:0] sprWidth [pnSprm:0]; // number of pixels in X direction
reg [7:0] sprHeight [pnSprm:0]; // number of vertical pixels
reg [3:0] sprPlane [pnSprm:0]; // output plane sprite is in
reg [1:0] sprColorDepth [pnSprm:0];
reg [1:0] colorBits;
// Sprite DMA control
reg [8:0] sprBurstStart [pnSprm:0];
reg [8:0] sprBurstEnd [pnSprm:0];
reg [31:0] vSyncT; // DMA on vSync
 
// display and timing signals
reg [31:0] hSprReset; // horizontal reset
reg [31:0] vSprReset; // vertical reset
reg [31:0] hSprDe; // sprite horizontal display enable
reg [31:0] vSprDe; // sprite vertical display enable
reg [31:0] sprDe; // display enable
reg [phBits-1:0] hSprPos [pnSprm:0]; // sprite horizontal position
reg [pvBits-1:0] vSprPos [pnSprm:0]; // sprite vertical position
reg [7:0] hSprCnt [pnSprm:0]; // sprite horizontal display counter
reg [7:0] vSprCnt [pnSprm:0]; // vertical display counter
reg [11:0] sprImageOffs [pnSprm:0]; // offset within sprite memory
reg [12:0] sprAddr [pnSprm:0]; // index into sprite memory (pixel number)
reg [9:0] sprAddr1 [pnSprm:0]; // index into sprite memory
reg [9:0] sprAddr2 [pnSprm:0]; // index into sprite memory
reg [9:0] sprAddr3 [pnSprm:0]; // index into sprite memory
reg [9:0] sprAddr4 [pnSprm:0]; // index into sprite memory
reg [11:0] sprAddrB [pnSprm:0]; // backup address cache for rescan
wire [23:0] sprOut4 [pnSprm:0]; // sprite image data output
reg [23:0] sprOut [pnSprm:0]; // sprite image data output
reg [23:0] sprOut5 [pnSprm:0]; // sprite image data output
 
// DMA access
reg [31:12] sprSysAddr [pnSprm:0]; // system memory address of sprite image (low bits)
reg [4:0] dmaOwner; // which sprite has the DMA channel
reg [31:0] sprDt; // DMA trigger register
reg dmaActive; // this flag indicates that a block DMA transfer is active
 
genvar g;
 
//--------------------------------------------------------------------
// DMA control / bus interfacing
//--------------------------------------------------------------------
reg cs_regs;
always_ff @(posedge s_clk_i)
cs_regs <= s_cyc_i & s_stb_i & s_cs_i;
always_ff @(posedge s_clk_i)
adr_i <= s_adr_i;
always_ff @(posedge s_clk_i)
dat_i <= s_dat_i;
always_ff @(posedge s_clk_i)
we_i <= s_we_i;
 
ack_gen #(
.READ_STAGES(3),
.WRITE_STAGES(1),
.REGISTER_OUTPUT(1)
)
uag1 (
.clk_i(s_clk_i),
.ce_i(1'b1),
.i(cs_regs),
.we_i(cs_regs & we_i),
.o(s_ack_o)
);
 
assign irq = sprSprIRQ|sprBkIRQ;
 
//--------------------------------------------------------------------
// DMA control / bus interfacing
//--------------------------------------------------------------------
 
reg [5:0] dmaStart;
reg [8:0] cob; // count of burst cycles
 
assign m_bte_o = 2'b00;
assign m_cti_o = 3'b000;
assign m_stb_o = m_cyc_o;
assign m_we_o = 1'b0;
assign m_sel_o = {4{m_cyc_o}};
assign m_dat_o = 48'h0;
assign m_spriteno_o = dmaOwner;
 
reg [2:0] mstate;
parameter IDLE = 3'd0;
parameter ACTIVE = 3'd1;
parameter ACK = 3'd2;
parameter NACK = 3'd3;
 
wire pe_m_ack_i;
edge_det ued2 (.rst(rst_i), .clk(m_clk_i), .ce(1'b1), .i(m_ack_i), .pe(pe_m_ack_i), .ne(), .ee());
 
always_ff @(posedge m_clk_i)
if (rst_i)
mstate <= IDLE;
else begin
case(mstate)
IDLE:
if (|sprDt)
mstate <= ACTIVE;
ACTIVE:
mstate <= ACK;
ACK:
if (m_ack_i | m_err_i)
mstate <= NACK;
NACK:
if (~(m_ack_i|m_err_i))
mstate <= cob==sprBurstEnd[dmaOwner] ? IDLE : ACTIVE;
default:
mstate <= IDLE;
endcase
end
 
integer n30;
always_ff @(posedge m_clk_i)
begin
case(mstate)
IDLE:
begin
dmaOwner <= 5'd0;
for (n30 = pnSprm; n30 >= 0; n30 = n30 - 1)
if (sprDt[n30])
dmaOwner <= n30;
end
default: ;
endcase
end
 
always_ff @(posedge m_clk_i)
if (rst_i)
dmaStart <= 6'b0;
else begin
dmaStart <= {dmaStart[4:0],1'b0};
case(mstate)
IDLE:
if (|sprDt)
dmaStart <= 6'h3F;
default: ;
endcase
end
 
integer n32;
always_ff @(posedge m_clk_i)
begin
case(mstate)
IDLE:
for (n32 = pnSprm; n32 >= 0; n32 = n32 - 1)
if (sprDt[n32])
cob <= sprBurstStart[n32];
ACTIVE:
cob <= cob + 2'd1;
default: ;
endcase
end
 
always_ff @(posedge m_clk_i)
if (rst_i)
wb_m_nack();
else begin
case(mstate)
IDLE:
wb_m_nack();
ACTIVE:
begin
m_cyc_o <= 1'b1;
m_adr_o <= {sprSysAddr[dmaOwner],cob[8:0],3'h0};
end
ACK:
if (m_ack_i|m_err_i)
wb_m_nack();
endcase
end
 
task wb_m_nack;
begin
m_cyc_o <= 1'b0;
m_adr_o <= 36'h0;
end
endtask
 
 
// generate a write enable strobe for the sprite image memory
integer n1;
always_ff @(posedge m_clk_i)
for (n1 = 0; n1 < pnSpr; n1 = n1 + 1)
sprWe[n1] <= (dmaOwner==n1 && m_ack_i);
 
reg [8:0] m_adr_or;
reg [47:0] m_dat_ir;
always_ff @(posedge m_clk_i)
if (m_ack_i)
m_adr_or <= m_adr_o[11:3];
always_ff @(posedge m_clk_i)
if (m_ack_i) begin
if (test)
m_dat_ir <= {4{1'b0,dmaOwner,10'b0}};
else
m_dat_ir <= m_dat_i;
end
 
//--------------------------------------------------------------------
//--------------------------------------------------------------------
 
reg [11:0] reg_shadow [0:1023];
reg [9:0] radr;
always_ff @(posedge s_clk_i)
begin
if (cs_regs & we_i) reg_shadow[adr_i[9:0]] <= dat_i;
end
always @(posedge s_clk_i)
radr <= adr_i[9:0];
wire [11:0] reg_shadow_o = reg_shadow[radr];
 
// register/sprite memory output mux
always_ff @(posedge s_clk_i)
if (cs_regs)
case (adr_i[9:0]) // synopsys full_case parallel_case
10'b1111000000: s_dat_o <= 12'h0;
10'b1111000001: s_dat_o <= {4'h0,sprEn[31:24]};
10'b1111000010: s_dat_o <= sprEn[23:12];
10'b1111000011: s_dat_o <= sprEn[11: 0];
10'b1111000100: s_dat_o <= {10'b0,sprBkIe,sprSprIe};
10'b1111000101: s_dat_o <= {4'h0,sprBkIRQPending|sprSprIRQPending,5'b0,sprBkIRQPending,sprSprIRQPending};
10'b1111001000: s_dat_o <= 12'h0;
10'b1111001001: s_dat_o <= {4'h0,sprSprCollision[31:24]};
10'b1111001010: s_dat_o <= sprSprCollision[23:12];
10'b1111001011: s_dat_o <= sprSprCollision[11: 0];
10'b1111001100: s_dat_o <= 12'h0;
10'b1111001101: s_dat_o <= {4'h0,sprBkCollision[31:24]};
10'b1111001110: s_dat_o <= sprBkCollision[23:12];
10'b1111001111: s_dat_o <= sprBkCollision[11: 0];
10'b1111010000: s_dat_o <= 12'h0;
10'b1111010001: s_dat_o <= {4'h0,sprDt[31:24]};
10'b1111010010: s_dat_o <= sprDt[23:12];
10'b1111010011: s_dat_o <= sprDt[11: 0];
default: s_dat_o <= reg_shadow_o;
endcase
else
s_dat_o <= 12'h0;
 
 
// vclk -> clk_i
always @(posedge s_clk_i)
begin
sprSprIRQ <= sprSprIRQ1;
sprBkIRQ <= sprBkIRQ1;
sprSprIRQPending <= sprSprIRQPending1;
sprBkIRQPending <= sprBkIRQPending1;
sprSprCollision <= sprSprCollision1;
sprBkCollision <= sprBkCollision1;
end
 
 
// register updates
// on the clk_i domain
reg vSync1;
integer n33;
always_ff @(posedge s_clk_i)
if (rst_i) begin
vSyncT <= 32'hFFFFFFFF;
sprEn <= 32'hFFFFFFFF;
sprDt <= 0;
for (n33 = 0; n33 < pnSpr; n33 = n33 + 1) begin
sprSysAddr[n33] <= 24'b0000_0000_0000_0011_0000_0000 + n33; //0030_0000
end
sprSprIe <= 0;
sprBkIe <= 0;
 
// Set reasonable starting positions on the screen
// so that the sprites might be visible for testing
for (n33 = 0; n33 < pnSpr; n33 = n33 + 1) begin
hSprPos[n33] <= 200 + (n33 & 7) * 70;
vSprPos[n33] <= 100 + (n33 >> 3) * 100;
sprTc[n33] <= 24'h396739;
sprWidth[n33] <= 8'd56; // 56x36 sprites
sprHeight[n33] <= 8'd36;
hSprRes[n33] <= 0; // our standard display
vSprRes[n33] <= 0;
sprImageOffs[n33] <= 0;
sprPlane[n33] <= 4'hF;//n[3:0];
sprBurstStart[n33] <= 9'h000;
sprBurstEnd[n33] <= 9'h1FF;
sprColorDepth[n33] <= 2'b10;
end
hSprPos[0] <= 210;
vSprPos[0] <= 72;
 
bgTc <= 24'h08_08_08;
bkColor <= 24'hFF_FF_60;
end
else begin
vSync1 <= vSync;
if (vSync & ~vSync1)
sprDt <= sprDt | vSyncT;
 
// clear DMA trigger bit once DMA is recognized
if (dmaStart[5])
sprDt[dmaOwner] <= 1'b0;
 
if (cs_regs & we_i) begin
 
casez (adr_i[9:0])
10'b100?????00: sprBurstStart[adr_i[6:2]] <= dat_i[8:0];
10'b100?????01: sprBurstEnd[adr_i[6:2]] <= dat_i[8:0];
10'b1111000000: ; // 3C0
10'b1111000001: sprEn[31:24] <= dat_i[7:0];
10'b1111000010: sprEn[23:12] <= dat_i;
10'b1111000011: sprEn[11: 0] <= dat_i;
10'b1111000100: // 3C4
begin
sprSprIe <= dat_i[0];
sprBkIe <= dat_i[1];
end
// update DMA trigger
// s_dat_i[7:0] indicates which triggers to set (1=set,0=ignore)
// s_dat_i[7:0] indicates which triggers to clear (1=clear,0=ignore)
10'b1111010000: ; // 3D0
10'b1111010001: sprDt[31:24] <= sprDt[31:24] | dat_i[7:0];
10'b1111010010: sprDt[23:12] <= sprDt[23:12] | dat_i;
10'b1111010011: sprDt[11: 0] <= sprDt[11: 0] | dat_i;
10'b1111010100: ; // 3D4
10'b1111010101: sprDt[31:24] <= sprDt[31:24] & ~dat_i[7:0];
10'b1111010110: sprDt[23:12] <= sprDt[23:12] & ~dat_i;
10'b1111010111: sprDt[11: 0] <= sprDt[11: 0] & ~dat_i;
10'b1111011000: ; // 3D8
10'b1111011001: vSyncT[31:24] <= dat_i[7:0];
10'b1111011010: vSyncT[23:12] <= dat_i;
10'b1111011011: vSyncT[11: 0] <= dat_i;
10'b1111101000: ; // 3E8
10'b1111101001: ;
10'b1111101010: bgTc[23:12] <= dat_i;
10'b1111101011: bgTc[11: 0] <= dat_i;
10'b1111101100: ; // 3EC
10'b1111101101: ;
10'b1111101110: bkColor[23:12] <= dat_i;
10'b1111101111: bkColor[11: 0] <= dat_i;
10'b0?????0000: hSprPos[sprN] <= dat_i[10: 0];
10'b0?????0001: vSprPos[sprN] <= dat_i[10: 0];
10'b0?????0100: sprWidth[sprN] <= dat_i[7:0];
10'b0?????0101: sprHeight[sprN] <= dat_i[7:0];
10'b0?????0110:
begin
hSprRes[sprN] <= dat_i[3:0];
vSprRes[sprN] <= dat_i[7:4];
end
10'b0?????0111:
begin
sprPlane[sprN] <= dat_i[3:0];
sprColorDepth[sprN] <= dat_i[7:6];
end
10'b0?????1000: ;// DMA address set on clk_i domain
10'b0?????1001: sprSysAddr[sprN][31:24] <= dat_i[7:0];
10'b0?????1010: sprSysAddr[sprN][23:12] <= dat_i;
10'b0?????1011: sprImageOffs[sprN][10:0] <= dat_i[10:0];
10'b0?????1100: sprTc[sprN][23:12] <= dat_i;
10'b0?????1101: sprTc[sprN][11: 0] <= dat_i;
default: ;
endcase
end
end
 
//-------------------------------------------------------------
// Sprite Image Cache RAM
// This RAM is dual ported with an SoC side and a display
// controller side.
//-------------------------------------------------------------
 
integer n2;
always_ff @(posedge vclk)
for (n2 = 0; n2 < pnSpr; n2 = n2 + 1)
case(sprColorDepth[n2])
2'd1: sprAddr1[n2] <= sprAddr[n2][11:2];
2'd2: sprAddr1[n2] <= sprAddr[n2][10:1];
2'd3: sprAddr1[n2] <= sprAddr[n2][ 9:0];
default: ;
endcase
 
integer n4, n5, n27;
always_ff @(posedge vclk)
for (n4 = 0; n4 < pnSpr; n4 = n4 + 1)
sprAddr2[n4] <= sprAddr1[n4];
always_ff @(posedge vclk)
for (n5 = 0; n5 < pnSpr; n5 = n5 + 1)
sprAddr3[n5] <= sprAddr2[n5];
always_ff @(posedge vclk)
for (n27 = 0; n27 < pnSpr; n27 = n27 + 1)
sprAddr4[n27] <= sprAddr3[n27];
 
// The pixels are displayed from most signicant to least signicant bits of the
// word. Display order is opposite to memory storage. So, the least significant
// address bits are flipped to get the correct display.
integer n3;
always_ff @(posedge vclk)
for (n3 = 0; n3 < pnSpr; n3 = n3 + 1)
case(sprColorDepth[n3])
2'd1:
case(~sprAddr4[n3][1:0])
2'd3: sprOut5[n3] <= sprOut4[n3][23:18];
2'd2: sprOut5[n3] <= sprOut4[n3][17:12];
2'd1: sprOut5[n3] <= sprOut4[n3][11:6];
2'd0: sprOut5[n3] <= sprOut4[n3][5:0];
endcase
2'd2:
case(~sprAddr4[n3][0])
1'd0: sprOut5[n3] <= {sprOut4[n3][12],20'h0000,sprOut4[n3][10:0]};
1'd1: sprOut5[n3] <= {sprOut4[n3][23],20'h0000,sprOut4[n3][22:12]};
endcase
2'd3:
sprOut5[n3] <= sprOut4[n3];
default: ;
endcase
 
generate
for (g = 0; g < pnSpr; g = g + 1) begin : sprRam
SpriteRam_x12 sprRam0
(
.clka(m_clk_i),
.addra(m_adr_or),
.dina(m_dat_ir),
.ena(sprWe[g]),
.wea(sprWe[g]),
// Core reg and output reg 3 clocks from read address
.clkb(vclk),
.addrb(sprAddr1[g]),
.doutb(sprOut4[g]),
.enb(1'b1)
);
end
endgenerate
 
//-------------------------------------------------------------
// Timing counters and addressing
// Sprites are like miniature bitmapped displays, they need
// all the same timing controls.
//-------------------------------------------------------------
 
// Create a timing reference using horizontal and vertical
// sync
wire hSyncEdge, vSyncEdge;
edge_det ed0(.rst(rst_i), .clk(vclk), .ce(1'b1), .i(hSync), .pe(hSyncEdge), .ne(), .ee() );
edge_det ed1(.rst(rst_i), .clk(vclk), .ce(1'b1), .i(vSync), .pe(vSyncEdge), .ne(), .ee() );
 
always_ff @(posedge vclk)
if (hSyncEdge) hctr <= {phBits{1'b0}};
else hctr <= hctr + 2'd1;
 
always_ff @(posedge vclk)
if (vSyncEdge) vctr <= {pvBits{1'b0}};
else if (hSyncEdge) vctr <= vctr + 2'd1;
 
// track sprite horizontal reset
integer n19;
always_ff @(posedge vclk)
for (n19 = 0; n19 < pnSpr; n19 = n19 + 1)
hSprReset[n19] <= hctr==hSprPos[n19];
 
// track sprite vertical reset
integer n20;
always_ff @(posedge vclk)
for (n20 = 0; n20 < pnSpr; n20 = n20 + 1)
vSprReset[n20] <= vctr==vSprPos[n20];
 
integer n21;
always_comb
for (n21 = 0; n21 < pnSpr; n21 = n21 + 1)
sprDe[n21] <= hSprDe[n21] & vSprDe[n21];
 
 
// take care of sprite size scaling
// video clock division
reg [31:0] hSprNextPixel;
reg [31:0] vSprNextPixel;
reg [3:0] hSprPt [31:0]; // horizontal pixel toggle
reg [3:0] vSprPt [31:0]; // vertical pixel toggle
integer n17;
always_comb
for (n17 = 0; n17 < pnSpr; n17 = n17 + 1)
hSprNextPixel[n17] = hSprPt[n17]==hSprRes[n17];
integer n18;
always_comb
for (n18 = 0; n18 < pnSpr; n18 = n18 + 1)
vSprNextPixel[n18] = vSprPt[n18]==vSprRes[n18];
 
// horizontal pixel toggle counter
integer n6;
always_ff @(posedge vclk)
for (n6 = 0; n6 < pnSpr; n6 = n6 + 1)
if (hSprReset[n6])
hSprPt[n6] <= 4'd0;
else if (hSprNextPixel[n6])
hSprPt[n6] <= 4'd0;
else
hSprPt[n6] <= hSprPt[n6] + 2'd1;
 
// vertical pixel toggle counter
integer n7;
always_ff @(posedge vclk)
for (n7 = 0; n7 < pnSpr; n7 = n7 + 1)
if (hSprReset[n7]) begin
if (vSprReset[n7])
vSprPt[n7] <= 4'd0;
else if (vSprNextPixel[n7])
vSprPt[n7] <= 4'd0;
else
vSprPt[n7] <= vSprPt[n7] + 2'd1;
end
 
 
// clock sprite image address counters
integer n8;
always_ff @(posedge vclk)
for (n8 = 0; n8 < pnSpr; n8 = n8 + 1) begin
// hReset and vReset - top left of sprite,
// reset address to image offset
if (hSprReset[n8] & vSprReset[n8]) begin
sprAddr[n8] <= sprImageOffs[n8];
sprAddrB[n8] <= sprImageOffs[n8];
end
// hReset:
// If the next vertical pixel
// set backup address to current address
// else
// set current address to backup address
// in order to rescan the line
else if (hSprReset[n8]) begin
if (vSprNextPixel[n8])
sprAddrB[n8] <= sprAddr[n8];
else
sprAddr[n8] <= sprAddrB[n8];
end
// Not hReset or vReset - somewhere on the sprite scan line
// just advance the address when the next pixel should be
// fetched
else if (hSprDe[n8] & hSprNextPixel[n8])
sprAddr[n8] <= sprAddr[n8] + 2'd1;
end
 
 
// clock sprite column (X) counter
integer n9;
always_ff @(posedge vclk)
for (n9 = 0; n9 < pnSpr; n9 = n9 + 1)
if (hSprReset[n9])
hSprCnt[n9] <= 8'd1;
else if (hSprNextPixel[n9])
hSprCnt[n9] <= hSprCnt[n9] + 2'd1;
 
 
// clock sprite horizontal display enable
integer n10;
always_ff @(posedge vclk)
for (n10 = 0; n10 < pnSpr; n10 = n10 + 1) begin
if (hSprReset[n10])
hSprDe[n10] <= 1'b1;
else if (hSprNextPixel[n10]) begin
if (hSprCnt[n10] == sprWidth[n10])
hSprDe[n10] <= 1'b0;
end
end
 
 
// clock the sprite row (Y) counter
integer n11;
always_ff @(posedge vclk)
for (n11 = 0; n11 < pnSpr; n11 = n11 + 1)
if (hSprReset[n11]) begin
if (vSprReset[n11])
vSprCnt[n11] <= 8'd1;
else if (vSprNextPixel[n11])
vSprCnt[n11] <= vSprCnt[n11] + 2'd1;
end
 
 
// clock sprite vertical display enable
integer n12;
always_ff @(posedge vclk)
for (n12 = 0; n12 < pnSpr; n12 = n12 + 1) begin
if (hSprReset[n12]) begin
if (vSprReset[n12])
vSprDe[n12] <= 1'b1;
else if (vSprNextPixel[n12]) begin
if (vSprCnt[n12] == sprHeight[n12])
vSprDe[n12] <= 1'b0;
end
end
end
 
 
//-------------------------------------------------------------
// Output stage
//-------------------------------------------------------------
 
// function used for color blending
// given an alpha and a color component, determine the resulting color
// this blends towards black or white
// alpha is eight bits ranging between 0 and 1.999...
// 1 bit whole, 7 bits fraction
function [7:0] fnBlend;
input [7:0] alpha;
input [7:0] colorbits;
 
begin
fnBlend = (({8'b0,colorbits} * alpha) >> 7);
end
endfunction
 
 
// pipeline delays for display enable
reg [31:0] sprDe1, sprDe2, sprDe3, sprDe4, sprDe5, sprDe6;
reg [31:0] sproact;
integer n13;
always_ff @(posedge vclk)
for (n13 = 0; n13 < pnSpr; n13 = n13 + 1)
sprDe1[n13] <= sprDe[n13];
integer n22;
always_ff @(posedge vclk)
for (n22 = 0; n22 < pnSpr; n22 = n22 + 1)
sprDe2[n22] <= sprDe1[n22];
integer n23;
always_ff @(posedge vclk)
for (n23 = 0; n23 < pnSpr; n23 = n23 + 1)
sprDe3[n23] <= sprDe2[n23];
integer n24;
always_ff @(posedge vclk)
for (n24 = 0; n24 < pnSpr; n24 = n24 + 1)
sprDe4[n24] <= sprDe3[n24];
integer n25;
always_ff @(posedge vclk)
for (n25 = 0; n25 < pnSpr; n25 = n25 + 1)
sprDe5[n25] <= sprDe4[n25];
integer n26;
always_ff @(posedge vclk)
for (n26 = 0; n26 < pnSpr; n26 = n26 + 1)
sprDe6[n26] <= sprDe5[n26];
 
 
// Detect which sprite outputs are active
// The sprite output is active if the current display pixel
// address is within the sprite's area, the sprite is enabled,
// and it's not a transparent pixel that's being displayed.
integer n14;
always_ff @(posedge vclk)
for (n14 = 0; n14 < pnSpr; n14 = n14 + 1)
sproact[n14] <= sprEn[n14] && sprDe5[n14] && sprTc[n14]!=sprOut5[n14];
integer n15;
always_ff @(posedge vclk)
for (n15 = 0; n15 < pnSpr; n15 = n15 + 1)
sprOut[n15] <= sprOut5[n15];
 
// register sprite activity flag
// The image combiner uses this flag to know what to do with
// the sprite output.
always_ff @(posedge vclk)
outact <= |sproact;
 
// Display data comes from the active sprite with the
// highest display priority.
// Make sure that alpha blending is turned off when
// no sprite is active.
integer n16;
always_ff @(posedge vclk)
begin
out <= 24'h080; // alpha blend max (and off)
outplane <= 4'h0;
colorBits <= 2'b00;
for (n16 = pnSprm; n16 >= 0; n16 = n16 - 1)
if (sproact[n16]) begin
out <= sprOut[n16];
outplane <= sprPlane[n16];
colorBits <= sprColorDepth[n16];
end
end
 
 
// combine the text / graphics color output with sprite color output
// blend color output
wire [23:0] blendedColor = {
fnBlend(out[7:0],zrgbIn[23:16]), // R
fnBlend(out[7:0],zrgbIn[15: 8]), // G
fnBlend(out[7:0],zrgbIn[ 7: 0])}; // B
 
 
always_ff @(posedge vclk)
if (blank_i)
zrgbOut <= 0;
else begin
if (outact) begin
if (zrgbIn[31:28] > outplane) begin // rgb input is in front of sprite
zrgbOut <= zrgbIn;
end
else
if (!out[23]) begin // a sprite is displayed without alpha blending
case(colorBits)
2'd0: zrgbOut <= {outplane,4'h0,out[5:4],6'b0,out[3:2],6'b0,out[1:0],6'b0};
2'd1: zrgbOut <= {outplane,4'h0,out[5:4],6'b0,out[3:2],6'b0,out[1:0],6'b0};
2'd2: zrgbOut <= {outplane,4'h0,out[10:7],4'b0,out[6:3],4'b0,out[2:0],5'b0};
2'd3: zrgbOut <= {outplane,4'h0,out[22:15],out[14:7],out[6:0]};
endcase
end
else
zrgbOut <= {outplane,4'h0,blendedColor};
end
else
zrgbOut <= zrgbIn;
end
 
 
//--------------------------------------------------------------------
// Collision logic
//--------------------------------------------------------------------
 
// Detect when a sprite-sprite collision has occurred. The criteria
// for this is that a pixel from the sprite is being displayed, while
// there is a pixel from another sprite that could be displayed at the
// same time.
 
//--------------------------------------------------------------------
// Note this case has to be modified for the number of sprites
//--------------------------------------------------------------------
integer m1;
always_comb
begin
sprCollision = sproact!=32'd0;
for (m1 = 0; m1 < pnSpr; m1 = m1 + 1)
sprCollision = sprCollision && !(sproact == (32'd1 << m1));
end
 
// Detect when a sprite-background collision has occurred
integer n31;
always_comb
for (n31 = 0; n31 < pnSpr; n31 = n31 + 1)
bkCollision[n31] <=
sproact[n31] && zrgbIn[31:28]==sprPlane[n31];
 
// Load the sprite collision register. This register continually
// accumulates collision bits until reset by reading the register.
// Set the collision IRQ on the first collision and don't set it
// again until after the collision register has been read.
always @(posedge vclk)
if (rst_i) begin
sprSprIRQPending1 <= 0;
sprSprCollision1 <= 0;
sprSprIRQ1 <= 0;
end
else if (sprCollision) begin
// isFirstCollision
if ((sprSprCollision1==0)||(cs_regs && adr_i[9:2]==8'b11110010)) begin
sprSprIRQPending1 <= 1;
sprSprIRQ1 <= sprSprIe;
sprSprCollision1 <= sproact;
end
else
sprSprCollision1 <= sprSprCollision1|sproact;
end
else if (cs_regs && adr_i[9:2]==8'b11110010) begin
sprSprCollision1 <= 0;
sprSprIRQPending1 <= 0;
sprSprIRQ1 <= 0;
end
 
 
// Load the sprite background collision register. This register
// continually accumulates collision bits until reset by reading
// the register.
// Set the collision IRQ on the first collision and don't set it
// again until after the collision register has been read.
// Note the background collision indicator is externally supplied,
// it will come from the color processing logic.
always @(posedge vclk)
if (rst_i) begin
sprBkIRQPending1 <= 0;
sprBkCollision1 <= 0;
sprBkIRQ1 <= 0;
end
else if (|bkCollision) begin
// Is the register being cleared at the same time
// a collision occurss ?
// isFirstCollision
if ((sprBkCollision1==0) || (cs_regs && adr_i[9:2]==8'b11110011)) begin
sprBkIRQ1 <= sprBkIe;
sprBkCollision1 <= bkCollision;
sprBkIRQPending1 <= 1;
end
else
sprBkCollision1 <= sprBkCollision1|bkCollision;
end
else if (cs_regs && adr_i[9:2]==8'b11110011) begin
sprBkCollision1 <= 0;
sprBkIRQPending1 <= 0;
sprBkIRQ1 <= 0;
end
 
endmodule
 
/*
module SpriteRam32 (
clka, adra, dia, doa, cea, wea,
clkb, adrb, dib, dob, ceb, web
);
input clka;
input [9:0] adra;
input [31:0] dia;
output [31:0] doa;
input cea;
input wea;
input clkb;
input [9:0] adrb;
input [31:0] dib;
output [31:0] dob;
input ceb;
input web;
 
reg [31:0] mem [0:1023];
reg [9:0] radra;
reg [9:0] radrb;
 
always @(posedge clka) if (cea) radra <= adra;
always @(posedge clkb) if (ceb) radrb <= adrb;
assign doa = mem [radra];
assign dob = mem [radrb];
always @(posedge clka)
if (cea & wea) mem[adra] <= dia;
always @(posedge clkb)
if (ceb & web) mem[adrb] <= dib;
 
endmodule
 
*/
/trunk/rtl/noc/video/rfTextController_x12.sv
0,0 → 1,976
// ============================================================================
// __
// \\__/ o\ (C) 2006-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// rfTextController.sv
// text controller
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Text Controller
//
// FEATURES
//
// This core requires an external timing generator to provide horizontal
// and vertical sync signals, but otherwise can be used as a display
// controller on it's own. However, this core may also be embedded within
// another core such as a VGA controller.
//
// Window positions are referenced to the rising edge of the vertical and
// horizontal sync pulses.
//
// The core includes an embedded dual port RAM to hold the screen
// characters.
//
// The controller expects a 64kB memory region to be reserved.
//
// Memory Map:
// 0000-3FFF display ram
// DF00-DFFF controller registers
// E000-FFFF character bitmap ram
//
//--------------------------------------------------------------------
// Registers
//
// 00h
// 7 - 0 cccccccc number of columns (horizontal displayed number of characters)
// 15- 8 rrrrrrrr number of rows (vertical displayed number of characters)
// 19-16 dddd character output delay
// 43-32 nnnn nnnnnnnn window left (horizontal sync position - reference for left edge of displayed)
// 59-48 nnnn nnnnnnnn window top (vertical sync position - reference for the top edge of displayed)
// 01h
// 4- 0 nnnnn maximum scan line (char ROM max value is 7)
// 11- 8 wwww pixel size - width
// 15-12 hhhh pixel size - height
// 24 r reset state bit
// 32 e controller enable
// 40 m multi-color mode
// 48-52 nnnnn yscroll
// 56-60 nnnnn xscroll
// 02h
// 23- 0 cccccccc cccccccc color code for transparent background RGB 8,8,8 (only RGB 7,7,7 used)
// 63-32 cccc...cccc border color ZRGB 8,8,8,8
// 03h
// 23- 0 cccccccc cccccccc tile color code 1
// 55-32 cccccccc cccccccc tile color code 2
// 04h
// 4- 0 eeeee cursor end
// 7- 5 bbb blink control
// BP: 00=no blink
// BP: 01=no display
// BP: 10=1/16 field rate blink
// BP: 11=1/32 field rate blink
// 12- 8 sssss cursor start
// 15-14 tt cursor image type (box, underline, sidebar, asterisk
// 47-32 aaaaaaaa aaaaaaaa cursor position
// 05h
// 15- 0 aaaaaaaa aaaaaaaa start address (index into display memory)
// 07h
// 150 - - aaaaaaaa aaaaaaaa light pen position
//--------------------------------------------------------------------
//
// ============================================================================
 
//`define USE_CLOCK_GATE
`define INTERNAL_RAMS 1'b1
 
module rfTextController_x12(
rst_i, clk_i, cs_i,
cti_i, cyc_i, stb_i, ack_o, wr_i, adr_i, dat_i, dat_o,
txt_clk_o, txt_cyc_o, txt_stb_o, txt_ack_i, txt_we_o, txt_sel_o, txt_adr_o, txt_dat_o, txt_dat_i,
cbm_clk_o, cbm_cyc_o, cbm_stb_o, cbm_ack_i, cbm_we_o, cbm_sel_o, cbm_adr_o, cbm_dat_o, cbm_dat_i,
lp_i,
dot_clk_i, hsync_i, vsync_i, blank_i, border_i, zrgb_i, zrgb_o, xonoff_i
);
parameter num = 4'd1;
parameter COLS = 8'd64;
parameter ROWS = 8'd32;
 
// Syscon
input rst_i; // reset
input clk_i; // clock
 
// Slave signals
input cs_i; // circuit select
input [2:0] cti_i;
input cyc_i; // valid bus cycle
input stb_i; // data strobe
output ack_o; // data acknowledge
input wr_i; // write
input [15:0] adr_i; // address
input [11:0] dat_i; // data input
output reg [11:0] dat_o; // data output
 
// Master Signals
output txt_clk_o;
output reg txt_cyc_o;
output reg txt_stb_o;
input txt_ack_i;
output txt_we_o;
output [7:0] txt_sel_o;
output reg [16:0] txt_adr_o;
output [63:0] txt_dat_o;
input [63:0] txt_dat_i;
 
output cbm_clk_o; // character bitmap data fetch clock
output reg cbm_cyc_o;
output reg cbm_stb_o;
input cbm_ack_i;
output cbm_we_o;
output [7:0] cbm_sel_o;
output reg [15:0] cbm_adr_o;
output [63:0] cbm_dat_o;
input [63:0] cbm_dat_i;
 
input lp_i; // light pen
 
// Video signals
input dot_clk_i; // video dot clock
input hsync_i; // end of scan line
input vsync_i; // end of frame
input blank_i; // blanking signal
input border_i; // border area
input [31:0] zrgb_i; // input pixel stream
output reg [31:0] zrgb_o; // output pixel stream
input xonoff_i;
 
reg controller_enable;
reg [31:0] bkColor32, bkColor32d; // background color
reg [31:0] fgColor32, fgColor32d; // foreground color
 
wire [1:0] pix; // pixel value from character generator 1=on,0=off
 
reg por;
wire vclk;
assign txt_clk_o = vclk;
assign txt_we_o = por;
assign txt_sel_o = 8'hFF;
assign cbm_clk_o = vclk;
assign cbm_we_o = 1'b0;
assign cbm_sel_o = 8'hFF;
 
reg [63:0] rego;
reg [4:0] yscroll;
reg [5:0] xscroll;
reg [11:0] windowTop;
reg [11:0] windowLeft;
reg [ 7:0] numCols;
reg [ 7:0] numRows;
reg [ 7:0] charOutDelay;
reg [ 1:0] mode;
reg [ 4:0] maxRowScan;
reg [ 5:0] maxScanpix;
reg [1:0] tileWidth; // width of tile in bytes (0=1,1=2,2=4,3=8)
reg [ 4:0] cursorStart, cursorEnd;
reg [15:0] cursorPos;
reg [1:0] cursorType;
reg [15:0] startAddress;
reg [ 2:0] rBlink;
reg [3:0] bdrCode;
wire [23:0] bdrColor; // Border color
reg [ 3:0] pixelWidth; // horizontal pixel width in clock cycles
reg [ 3:0] pixelHeight; // vertical pixel height in scan lines
reg mcm; // multi-color mode
 
wire [11:0] hctr; // horizontal reference counter (counts clocks since hSync)
wire [11:0] scanline; // scan line
reg [ 7:0] row; // vertical reference counter (counts rows since vSync)
reg [ 7:0] col; // horizontal column
reg [ 4:0] rowscan; // scan line within row
reg [ 5:0] colscan; // pixel column number within cell
wire nxt_row; // when to increment the row counter
wire nxt_col; // when to increment the column counter
reg [ 5:0] bcnt; // blink timing counter
wire blink;
reg iblank;
reg [4:0] maxScanlinePlusOne;
 
wire nhp; // next horizontal pixel
wire ld_shft = nxt_col & nhp;
 
 
// display and timing signals
reg [15:0] txtAddr; // index into memory
reg [15:0] penAddr;
wire [23:0] screen_ram_out; // character code
wire [23:0] txtBkColor; // background color code
wire [23:0] txtFgColor; // foreground color code
wire [5:0] txtZorder;
reg [3:0] txtTcCode; // transparent color code
wire [23:0] txtTcColor;
reg [3:0] tileCode1;
reg [3:0] tileCode2;
wire [23:0] tileColor1;
wire [23:0] tileColor2;
reg bgt, bgtd;
 
wire [11:0] tdat_o;
wire [8:0] chdat_o;
 
wire [2:0] scanindex = rowscan[2:0];
 
//--------------------------------------------------------------------
// bus interfacing
// Address Decoding
// I/O range Dx
//--------------------------------------------------------------------
// Register the inputs
reg cs_rom, cs_reg, cs_text, cs_any;
reg [15:0] radr_i;
reg [11:0] rdat_i;
reg rwr_i;
always_ff @(posedge clk_i)
cs_rom <= cs_i && cyc_i && stb_i && (adr_i[15:8] > 8'hDF);
always_ff @(posedge clk_i)
cs_reg <= cs_i && cyc_i && stb_i && (adr_i[15:8] == 8'hDF);
always_ff @(posedge clk_i)
cs_text <= cs_i && cyc_i && stb_i && (adr_i[15:8] < 8'hDF);
always_ff @(posedge clk_i)
cs_any <= cs_i && cyc_i && stb_i;
always_ff @(posedge clk_i)
rwr_i <= wr_i;
always_ff @(posedge clk_i)
radr_i <= adr_i;
always_ff @(posedge clk_i)
rdat_i <= dat_i;
 
// Register outputs
always @(posedge clk_i)
if (cs_i)
casez({cs_rom,cs_reg,cs_text})
3'b1??: dat_o <= {3'b0,chdat_o};
3'b01?: dat_o <= rego;
3'b001: dat_o <= tdat_o;
default: dat_o <= 12'h0;
endcase
else
dat_o <= 12'h0;
 
//always @(posedge clk_i)
// if (cs_text) begin
// $display("TC WRite: %h %h", adr_i, dat_i);
// $stop;
// end
 
// - there is a four cycle latency for reads, an ack is generated
// after the synchronous RAM read
// - writes can be acknowledged right away.
 
ack_gen #(
.READ_STAGES(5),
.WRITE_STAGES(1),
.REGISTER_OUTPUT(1)
)
uag1 (
.rst_i(rst_i),
.clk_i(clk_i),
.ce_i(1'b1),
.i(cs_any),
.we_i(cs_any & rwr_i),
.o(ack_o),
.rid_i(0),
.wid_i(0),
.rid_o(),
.wid_o()
);
 
//--------------------------------------------------------------------
//--------------------------------------------------------------------
`ifdef USE_CLOCK_GATE
BUFHCE ucb1 (.I(dot_clk_i), .CE(controller_enable), .O(vclk));
`else
assign vclk = dot_clk_i;
`endif
 
//--------------------------------------------------------------------
// Video Memory
//--------------------------------------------------------------------
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Address Calculation:
// - Simple: the row times the number of cols plus the col plus the
// base screen address
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
reg [15:0] rowcol;
always_ff @(posedge vclk)
txtAddr <= startAddress + rowcol + col;
 
// Register read-back memory
// Allows reading back of register values by shadowing them with ram
 
wire [5:0] rrm_adr = radr_i[5:0];
wire [11:0] rrm_o;
 
regReadbackMem #(.WID(12)) rrm0L
(
.wclk(clk_i),
.adr(rrm_adr),
.wce(cs_reg),
.we(rwr_i),
.i(rdat_i[11:0]),
.o(rrm_o[11:0])
);
 
wire [23:0] lfsr_o;
lfsr #(24) ulfsr1(rst_i, dot_clk_i, 1'b1, 1'b0, lfsr_o);
assign m_dat_o = lfsr_o;
 
/*
wire pe_cs;
edge_det u1(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(cs_text), .pe(pe_cs), .ne(), .ee() );
 
reg [14:0] ctr;
always @(posedge clk_i)
if (pe_cs) begin
if (cti_i==3'b000)
ctr <= adr_i[16:3];
else
ctr <= adr_i[16:3] + 12'd1;
cnt <= 3'b000;
end
else if (cs_text && cnt[2:0]!=3'b100 && cti_i!=3'b000) begin
ctr <= ctr + 2'd1;
cnt <= cnt + 3'd1;
end
 
reg [13:0] radr;
always @(posedge clk_i)
radr <= pe_cs ? adr_i[16:3] : ctr;
*/
// text screen RAM
wire [13:0] bram_adr = radr_i[13:0];
 
`ifdef INTERNAL_RAMS
rfTextControllerRam_x12 screen_ram1
(
.clka(clk_i),
.ena(cs_text),
.wea(rwr_i),
.addra({radr_i[12:0],radr_i[13]}),
.dina(rdat_i),
.douta(tdat_o),
.clkb(vclk),
.enb(ld_shft|por),
.web(por),
.addrb(txtAddr[12:0]),
.dinb({12'hE6,lfsr_o[11:0]}),
.doutb(screen_ram_out)
);
 
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Character bitmap ROM
// - room for 512 8x8 characters
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
wire [63:0] char_bmp; // character ROM output
char_ram charRam0
(
.clk_i(clk_i),
.cs_i(cs_rom),
.we_i(1'b0),
.adr_i(radr_i[14:0]),
.dat_i(rdat_i),
.dat_o(chdat_o),
.dot_clk_i(vclk),
.ce_i(ld_shft),
.char_code_i(screen_ram_out[8:0]),
.maxscanline_i(maxScanlinePlusOne),
.scanline_i(rowscan[4:0]),
.bmp_o(char_bmp)
);
//assign char_bmp[63:9] = 55'h0;
`else
reg [63:0] char_bmp; // character ROM output
`endif
 
reg [63:0] txt_dati;
reg [31:0] bmp_ndx;
`ifdef INTERNAL_RAMS
`else
always_ff @(posedge vclk)
bmp_ndx <= (maxScanlinePlusOne * txt_dati[15:0] + rowscan[4:0]) << tileWidth;
always_ff @(posedge vclk)
begin
if (ld_shft) begin
txt_cyc_o <= 1'b1;
txt_stb_o <= 1'b1;
txt_adr_o <= {txtAddr[13:0],3'b0};
cbm_cyc_o <= 1'b1;
cbm_stb_o <= 1'b1;
cbm_adr_o <= {bmp_ndx[31:3],3'b0};
end
if (txt_ack_i) begin
txt_cyc_o <= 1'b0;
txt_stb_o <= 1'b0;
txt_dati <= txt_dat_i;
end
if (cbm_ack_i) begin
cbm_cyc_o <= 1'b0;
cbm_stb_o <= 1'b0;
case(tileWidth)
2'd0: char_bmp <= cbm_dat_i >> {bmp_ndx[2:0],3'b0};
2'd1: char_bmp <= cbm_dat_i >> {bmp_ndx[2:1],4'b0};
2'd2: char_bmp <= cbm_dat_i >> {bmp_ndx[2],5'b0};
2'd3: char_bmp <= cbm_dat_i;
endcase
end
end
`endif
 
/*
syncRam4kx9 charRam0
(
.clka(clk_i), // input wire clka
.ena(cs_rom), // input wire ena
.wea(1'b0),//rwr_i), // input wire [0 : 0] wea
.addra(bram_adr), // input wire [11 : 0] addra
.dina(rdat_i[8:0]), // input wire [8 : 0] dina
.douta(chdat_o), // output wire [8 : 0] douta
.clkb(vclk), // input wire clkb
.enb(ld_shft), // input wire enb
.web(1'b0), // input wire [0 : 0] web
.addrb({screen_ram_out[8:0],scanline[2:0]}), // input wire [11 : 0] addrb
.dinb(9'h0), // input wire [8 : 0] dinb
.doutb(char_bmp) // output wire [8 : 0] doutb
);
*/
 
// pipeline delay - sync color with character bitmap output
reg [5:0] txtZorder1;
 
wire [3:0] txtBkCode1 = screen_ram_out[15:12];
wire [3:0] txtFgCode1 = screen_ram_out[19:16];
rfColorROM ucr1(vclk, ld_shft, {1'b0,txtBkCode1}, txtBkColor);
rfColorROM ucr2(vclk, ld_shft, {1'b0,txtFgCode1}, txtFgColor);
rfColorROM ucr3(vclk, 1'b1, {1'b0,txtTcCode}, txtTcColor);
rfColorROM ucr4(vclk, 1'b1, {1'b0,bdrCode}, bdrColor);
rfColorROM ucr5(vclk, ld_shft, {1'b0,tileCode1}, tileColor1);
rfColorROM ucr6(vclk, ld_shft, {1'b0,tileCode2}, tileColor2);
 
always @(posedge vclk)
if (ld_shft) txtZorder1 <= 6'h3F;
 
//--------------------------------------------------------------------
// Light Pen
//--------------------------------------------------------------------
wire lpe;
edge_det u1 (.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(lp_i), .pe(lpe), .ne(), .ee() );
 
always @(posedge clk_i)
if (rst_i)
penAddr <= 32'h0000_0000;
else begin
if (lpe)
penAddr <= txtAddr;
end
 
 
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Register read port
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
always @*
if (cs_reg) begin
case(radr_i[5:0])
6'd56: rego <= {8'h00,penAddr[15:12]};
6'd57: rego <= penAddr[11:0];
default: rego <= rrm_o;
endcase
end
else
rego <= 12'h000;
 
 
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Register write port
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
always @(posedge clk_i)
if (rst_i) begin
por <= 1'b1;
mcm <= 1'b0;
controller_enable <= 1'b1;
xscroll <= 6'd0;
yscroll <= 5'd0;
txtTcCode <= 4'hE;
bdrCode <= 4'hE;
startAddress <= 16'h0000;
cursorStart <= 5'd00;
cursorEnd <= 5'd31;
cursorPos <= 16'h0003;
cursorType <= 2'b00;
// 104x63
/*
windowTop <= 12'd26;
windowLeft <= 12'd260;
pixelWidth <= 4'd0;
pixelHeight <= 4'd1; // 525 pixels (408 with border)
*/
// 52x31
/*
// 84x47
windowTop <= 12'd16;
windowLeft <= 12'd90;
pixelWidth <= 4'd1; // 681 pixels
pixelHeight <= 4'd1; // 384 pixels
*/
// 48x29
if (num==4'd1) begin
windowTop <= 12'd4058;//12'd16;
windowLeft <= 12'd3956;//12'd3930;//12'd86;
pixelWidth <= 4'd0; // 800 pixels
pixelHeight <= 4'd0; // 600 pixels
numCols <= COLS;
numRows <= ROWS;
maxRowScan <= 5'd17;
maxScanpix <= 6'd11;
rBlink <= 3'b111; // 01 = non display
charOutDelay <= 8'd5;
end
else if (num==4'd2) begin
windowTop <= 12'd4032;//12'd16;
windowLeft <= 12'd3720;//12'd86;
pixelWidth <= 4'd0; // 800 pixels
pixelHeight <= 4'd0; // 600 pixels
numCols <= 40;
numRows <= 25;
maxRowScan <= 5'd7;
maxScanpix <= 6'd7;
rBlink <= 3'b111; // 01 = non display
charOutDelay <= 8'd6;
end
end
else begin
if (bcnt > 6'd10)
por <= 1'b0;
if (cs_reg & rwr_i) begin // register write ?
$display("TC Write: r%d=%h", rrm_adr, rdat_i);
case(radr_i[5:0])
6'd0: numCols <= rdat_i[7:0];
6'd1: numRows <= rdat_i[7:0];
6'd2: charOutDelay <= rdat_i;
6'd4: ;
6'd5: windowLeft[11:0] <= rdat_i;
6'd6: ;
6'd7: windowTop[11:0] <= rdat_i;
6'd8: maxRowScan <= rdat_i[4:0];
6'd9:
begin
pixelHeight <= rdat_i[7:4];
pixelWidth <= rdat_i[3:0]; // horizontal pixel width
end
6'd11: por <= rdat_i[0];
6'd12: controller_enable <= rdat_i[0];
6'd13: mcm <= rdat_i[0];
6'd14: yscroll <= rdat_i[4:0];
6'd15: xscroll <= rdat_i[5:0];
6'd16: txtTcCode <= rdat_i[7:0];
6'd20: bdrCode <= rdat_i[7:0];
6'd24: tileCode1 <= rdat_i[7:0];
6'd28: tileCode2 <= rdat_i[7:0];
6'd31: maxScanpix <= rdat_i[5:0];
6'd32:
begin
cursorEnd <= rdat_i[4:0]; // scan line sursor starts on
rBlink <= rdat_i[7:5];
end
6'd33:
begin
cursorStart <= rdat_i[4:0]; // scan line cursor ends on
cursorType <= rdat_i[7:6];
end
6'd34: cursorPos[15:12] <= rdat_i[3:0];
6'd35: cursorPos[11: 0] <= rdat_i;
6'd40: startAddress[15:12] <= rdat_i[3:0];
6'd41: startAddress[11: 0] <= rdat_i;
default: ;
endcase
end
end
 
 
//--------------------------------------------------------------------
//--------------------------------------------------------------------
 
// "Box" cursor bitmap
reg [7:0] curout;
always @*
case({cursorType,scanindex})
// Box cursor
5'b00_000: curout = 8'b11111110;
5'b00_001: curout = 8'b10000010;
5'b00_010: curout = 8'b10000010;
5'b00_011: curout = 8'b10000010;
5'b00_100: curout = 8'b10000010;
5'b00_101: curout = 8'b10000010;
5'b00_110: curout = 8'b10010010;
5'b00_111: curout = 8'b11111110;
// vertical bar cursor
5'b01_000: curout = 8'b11000000;
5'b01_001: curout = 8'b10000000;
5'b01_010: curout = 8'b10000000;
5'b01_011: curout = 8'b10000000;
5'b01_100: curout = 8'b10000000;
5'b01_101: curout = 8'b10000000;
5'b01_110: curout = 8'b10000000;
5'b01_111: curout = 8'b11000000;
// underline cursor
5'b10_000: curout = 8'b00000000;
5'b10_001: curout = 8'b00000000;
5'b10_010: curout = 8'b00000000;
5'b10_011: curout = 8'b00000000;
5'b10_100: curout = 8'b00000000;
5'b10_101: curout = 8'b00000000;
5'b10_110: curout = 8'b00000000;
5'b10_111: curout = 8'b11111111;
// Asterisk
5'b11_000: curout = 8'b00000000;
5'b11_001: curout = 8'b00000000;
5'b11_010: curout = 8'b00100100;
5'b11_011: curout = 8'b00011000;
5'b11_100: curout = 8'b01111110;
5'b11_101: curout = 8'b00011000;
5'b11_110: curout = 8'b00100100;
5'b11_111: curout = 8'b00000000;
endcase
 
 
//-------------------------------------------------------------
// Video Stuff
//-------------------------------------------------------------
 
wire pe_hsync;
wire pe_vsync;
edge_det edh1
(
.rst(rst_i),
.clk(vclk),
.ce(1'b1),
.i(hsync_i),
.pe(pe_hsync),
.ne(),
.ee()
);
 
edge_det edv1
(
.rst(rst_i),
.clk(vclk),
.ce(1'b1),
.i(vsync_i),
.pe(pe_vsync),
.ne(),
.ee()
);
 
// Horizontal counter:
//
/*
HVCounter uhv1
(
.rst(rst_i),
.vclk(vclk),
.pixcce(1'b1),
.sync(hsync_i),
.cnt_offs(windowLeft),
.pixsz(pixelWidth),
.maxpix(maxScanpix),
.nxt_pix(nhp),
.pos(col),
.nxt_pos(nxt_col),
.ctr(hctr)
);
*/
 
// Vertical counter:
//
/*
HVCounter uhv2
(
.rst(rst_i),
.vclk(vclk),
.pixcce(pe_hsync),
.sync(vsync_i),
.cnt_offs(windowTop),
.pixsz(pixelHeight),
.maxpix(maxRowScan),
.nxt_pix(),
.pos(row),
.nxt_pos(nxt_row),
.ctr(scanline)
);
*/
 
// We generally don't care about the exact reset point, unless debugging in
// simulation. The counters will eventually cycle to a proper state. A little
// bit of logic / routing can be avoided by omitting the reset.
`ifdef SIM
wire sym_rst = rst_i;
`else
wire sym_rst = 1'b0;
`endif
 
// Raw scanline counter
vid_counter #(12) u_vctr (.rst(sym_rst), .clk(vclk), .ce(pe_hsync), .ld(pe_vsync), .d(windowTop), .q(scanline), .tc());
vid_counter #(12) u_hctr (.rst(sym_rst), .clk(vclk), .ce(1'b1), .ld(pe_hsync), .d(windowLeft), .q(hctr), .tc());
 
// Vertical pixel height counter, synchronized to scanline #0
reg [3:0] vpx;
wire nvp = vpx==pixelHeight;
always @(posedge vclk)
if (sym_rst)
vpx <= 4'b0;
else begin
if (pe_hsync) begin
if (scanline==12'd0)
vpx <= 4'b0;
else if (nvp)
vpx <= 4'd0;
else
vpx <= vpx + 4'd1;
end
end
 
reg [3:0] hpx;
assign nhp = hpx==pixelWidth;
always @(posedge vclk)
if (sym_rst)
hpx <= 4'b0;
else begin
if (hctr==12'd0)
hpx <= 4'b0;
else if (nhp)
hpx <= 4'd0;
else
hpx <= hpx + 4'd1;
end
 
// The scanline row within a character bitmap
always @(posedge vclk)
if (sym_rst)
rowscan <= 5'd0;
else begin
if (pe_hsync & nvp) begin
if (scanline==12'd0)
rowscan <= yscroll;
else if (rowscan==maxRowScan)
rowscan <= 5'd0;
else
rowscan <= rowscan + 5'd1;
end
end
 
assign nxt_col = colscan==maxScanpix;
always @(posedge vclk)
if (sym_rst)
colscan <= 6'd0;
else begin
if (nhp) begin
if (hctr==12'd0)
colscan <= xscroll;
else if (nxt_col)
colscan <= 6'd0;
else
colscan <= colscan + 2'd1;
end
end
 
// The screen row
always @(posedge vclk)
if (sym_rst)
row <= 8'd0;
else begin
if (pe_hsync & nvp) begin
if (scanline==12'd0)
row <= 8'd0;
else if (rowscan==maxRowScan)
row <= row + 8'd1;
end
end
 
// The screen column
always @(posedge vclk)
if (sym_rst)
col <= 8'd0;
else begin
if (hctr==12'd0)
col <= 8'd0;
else if (nhp) begin
if (nxt_col)
col <= col + 8'd1;
end
end
 
// More useful, the offset of the start of the text display on a line.
always @(posedge vclk)
if (sym_rst)
rowcol <= 16'd0;
else begin
if (pe_hsync & nvp) begin
if (scanline==12'd0)
rowcol <= 8'd0;
else if (rowscan==maxRowScan)
rowcol <= rowcol + numCols;
end
end
 
// Takes 3 clock for scanline to become stable, but should be stable before any
// chars are displayed.
reg [13:0] rxmslp1;
always @(posedge vclk)
maxScanlinePlusOne <= maxRowScan + 4'd1;
//always @(posedge vclk)
// rxmslp1 <= row * maxScanlinePlusOne;
//always @(posedge vclk)
// scanline <= scanline - rxmslp1;
 
 
// Blink counter
//
always @(posedge vclk)
if (sym_rst)
bcnt <= 6'd0;
else begin
if (pe_vsync)
bcnt <= bcnt + 6'd1;
end
 
reg blink_en;
always @(posedge vclk)
blink_en <= (cursorPos+4==txtAddr) && (rowscan[4:0] >= cursorStart) && (rowscan[4:0] <= cursorEnd);
 
VT151 ub2
(
.e_n(!blink_en),
.s(rBlink),
.i0(1'b1), .i1(1'b0), .i2(bcnt[4]), .i3(bcnt[5]),
.i4(1'b1), .i5(1'b0), .i6(bcnt[4]), .i7(bcnt[5]),
.z(blink),
.z_n()
);
 
always @(posedge vclk)
if (ld_shft)
bkColor32 <= {txtZorder1,2'b00,txtBkColor};
always @(posedge vclk)
if (nhp)
bkColor32d <= bkColor32;
always @(posedge vclk)
if (ld_shft)
fgColor32 <= {txtZorder1,2'b00,txtFgColor};
always @(posedge vclk)
if (nhp)
fgColor32d <= fgColor32;
 
always @(posedge vclk)
if (ld_shft)
bgt <= txtBkCode1==txtTcCode;
always @(posedge vclk)
if (nhp)
bgtd <= bgt;
 
// Convert character bitmap to pixels
reg [63:0] charout1;
always @(posedge vclk)
charout1 <= blink ? (char_bmp ^ curout) : char_bmp;
 
// Convert parallel to serial
ParallelToSerial ups1
(
.rst(rst_i),
.clk(vclk),
.mcm(mcm),
.ce(nhp),
.ld(ld_shft),
.a(maxScanpix[5:3]),
.qin(2'b0),
.d(charout1),
.qh(pix)
);
/*
always_ff @(posedge vclk)
if (rst_i) begin
pix <= 64'd0;
end
else begin
if (nhp) begin
if (ld_shft)
pix <= charout1;
else begin
if (mcm)
pix <= {2'b00,pix[63:2]};
else
pix <= {1'b0,pix[63:1]};
end
end
end
*/
reg [1:0] pix1;
always_ff @(posedge vclk)
if (nhp)
pix1 <= pix[1:0];
 
// Pipelining Effect:
// - character output is delayed by 2 or 3 character times relative to the video counters
// depending on the resolution selected
// - this means we must adapt the blanking signal by shifting the blanking window
// two or three character times.
wire bpix = hctr[2] ^ rowscan[4];// ^ blink;
always_ff @(posedge vclk)
if (nhp)
iblank <= (row >= numRows) || (col >= numCols + charOutDelay) || (col < charOutDelay);
 
// Choose between input RGB and controller generated RGB
// Select between foreground and background colours.
// Note the ungated dot clock must be used here, or output from other
// controllers would not be visible if the clock were gated off.
always_ff @(posedge dot_clk_i)
casez({controller_enable&xonoff_i,blank_i,iblank,border_i,bpix,mcm,pix1})
8'b01??????: zrgb_o <= 32'h00000000;
8'b11??????: zrgb_o <= 32'h00000000;
8'b1001????: zrgb_o <= bdrColor;
//6'b10010?: zrgb_o <= 32'hFFBF2020;
//6'b10011?: zrgb_o <= 32'hFFDFDFDF;
8'b1000?00?: zrgb_o <= (zrgb_i[31:24] > bkColor32d[31:24]) ? zrgb_i : bkColor32d;
// 8'b1000?0?0: zrgb_o <= bkColor32d;
8'b1000?01?: zrgb_o <= fgColor32d; // ToDo: compare z-order
8'b1000?100: zrgb_o <= (zrgb_i[31:24] > bkColor32d[31:24]) ? zrgb_i : bkColor32d;
8'b1000?101: zrgb_o <= fgColor32d;
8'b1000?110: zrgb_o <= {8'hFF,tileColor1};
8'b1000?111: zrgb_o <= {8'hFF,tileColor2};
// 6'b1010?0: zrgb_o <= bgtd ? zrgb_i : bkColor32d;
// 6'b1010?1: zrgb_o <= fgColor32d;
default: zrgb_o <= zrgb_i;
endcase
 
endmodule
 
/trunk/rtl/noc/video/rfVideoFifo.v
0,0 → 1,75
`timescale 1ns / 1ps
// ============================================================================
// __
// \\__/ o\ (C) 2008-2021 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file 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 this program. If not, see <http://www.gnu.org/licenses/>.
//
//
// Verilog 1995
//
// ============================================================================
//
module rfVideoFifo(wrst, wclk, wr, di, rrst, rclk, rd, dout, cnt);
parameter WID=128;
input wrst;
input wclk;
input wr;
input [WID-1:0] di;
input rrst;
input rclk;
input rd;
output [WID-1:0] dout;
output [7:0] cnt;
reg [7:0] cnt;
 
reg [7:0] wr_ptr;
reg [7:0] rd_ptr,rrd_ptr;
reg [WID-1:0] mem [0:255];
 
wire [7:0] wr_ptr_p1 = wr_ptr + 8'd1;
wire [7:0] rd_ptr_p1 = rd_ptr + 8'd1;
reg [7:0] rd_ptrs;
 
always @(posedge wclk)
if (wrst)
wr_ptr <= 8'd0;
else if (wr) begin
mem[wr_ptr] <= di;
wr_ptr <= wr_ptr_p1;
end
always @(posedge wclk) // synchronize read pointer to wclk domain
rd_ptrs <= rd_ptr;
 
always @(posedge rclk)
if (rrst)
rd_ptr <= 8'd0;
else if (rd)
rd_ptr <= rd_ptr_p1;
always @(posedge rclk)
rrd_ptr <= rd_ptr;
 
assign dout = mem[rrd_ptr[7:0]];
 
always @(wr_ptr or rd_ptrs)
if (rd_ptrs > wr_ptr)
cnt <= wr_ptr + (9'd256 - rd_ptrs);
else
cnt <= wr_ptr - rd_ptrs;
 
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.