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 |