2018-01-10 16:39:18 +11:00
|
|
|
`define LED_KEYS
|
|
|
|
|
2018-01-02 00:33:20 +11:00
|
|
|
module top(
|
2018-01-10 16:39:18 +11:00
|
|
|
input clk,
|
2018-01-02 00:33:20 +11:00
|
|
|
|
|
|
|
input uart_rx,
|
|
|
|
output uart_tx,
|
|
|
|
output uart_cts,
|
|
|
|
|
2018-01-10 16:39:18 +11:00
|
|
|
`ifdef LED_KEYS
|
2018-01-02 00:33:20 +11:00
|
|
|
output tm_cs,
|
|
|
|
output tm_clk,
|
|
|
|
inout tm_dio,
|
2018-01-10 16:39:18 +11:00
|
|
|
`endif
|
2018-01-02 00:33:20 +11:00
|
|
|
|
|
|
|
output reg [7:0] led
|
|
|
|
);
|
|
|
|
|
2018-01-12 01:01:34 +11:00
|
|
|
wire clk_phi;
|
2018-01-10 16:39:18 +11:00
|
|
|
wire res, rw, irq, nmi;
|
|
|
|
wire [15:0] ab;
|
|
|
|
wire [7:0] dbo;
|
|
|
|
reg [7:0] dbi;
|
|
|
|
|
2018-01-02 00:33:20 +11:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// USB UART
|
|
|
|
|
2018-01-12 01:01:34 +11:00
|
|
|
wire received, is_receiving, rx_error, is_transmitting, transmit;
|
|
|
|
reg [6:0] tx_byte;
|
|
|
|
wire [7:0] rx_byte;
|
2018-01-02 00:33:20 +11:00
|
|
|
|
|
|
|
uart #(.CLOCK_DIVIDE( 625 )) my_uart (
|
2018-01-10 16:39:18 +11:00
|
|
|
clk, // master clock for this component
|
2018-01-02 00:33:20 +11:00
|
|
|
~res, // synchronous reset line (resets if high)
|
|
|
|
uart_rx, // receive data on this line
|
|
|
|
uart_tx, // transmit data on this line
|
|
|
|
transmit, // signal to indicate that the UART should start a transmission
|
2018-01-10 16:39:18 +11:00
|
|
|
{1'b0, tx_byte}, // 8-bit bus with byte to be transmitted when transmit is raised high
|
2018-01-02 00:33:20 +11:00
|
|
|
received, // output flag raised high for one cycle of clk when a byte is received
|
|
|
|
rx_byte, // byte which has just been received when received is raise
|
|
|
|
is_receiving, // indicates that we are currently receiving data on the rx lin
|
|
|
|
is_transmitting, // indicates that we are currently sending data on the tx line
|
|
|
|
rx_error // rx packet corrupt
|
|
|
|
);
|
|
|
|
|
2018-01-10 16:39:18 +11:00
|
|
|
// sync the TX latch to the clk domain
|
2018-01-02 00:33:20 +11:00
|
|
|
reg apple_tx;
|
2018-01-10 16:39:18 +11:00
|
|
|
assign transmit = apple_tx;
|
2018-01-02 00:33:20 +11:00
|
|
|
|
|
|
|
// sync the RX flag, using flag and ack
|
|
|
|
reg [6:0] apple_rx_buf;
|
|
|
|
reg apple_rx_ack;
|
|
|
|
reg apple_rx_flag;
|
|
|
|
|
2018-01-10 16:39:18 +11:00
|
|
|
always @(posedge clk)
|
2018-01-02 00:33:20 +11:00
|
|
|
begin
|
|
|
|
if (received && !apple_rx_flag && !apple_rx_ack) begin
|
|
|
|
apple_rx_flag <= 1;
|
|
|
|
apple_rx_buf <= rx_byte[6:0];
|
|
|
|
end
|
|
|
|
|
|
|
|
if (apple_rx_flag && apple_rx_ack)
|
|
|
|
apple_rx_flag <= 0;
|
|
|
|
end
|
|
|
|
|
|
|
|
// implement basic hardware flow control so 6502 can catch up
|
|
|
|
assign uart_cts = is_receiving || apple_rx_flag;
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// TM1638 Display
|
|
|
|
|
2018-01-10 16:39:18 +11:00
|
|
|
`ifdef LED_KEYS
|
2018-01-02 00:33:20 +11:00
|
|
|
reg [3:0] display;
|
|
|
|
reg [7:0] digits[7:0];
|
|
|
|
reg [7:0] leds;
|
|
|
|
wire [7:0] keys;
|
|
|
|
|
|
|
|
ledAndKey my_led_and_keys (
|
2018-01-10 16:39:18 +11:00
|
|
|
.clk (clk_phi),
|
2018-01-02 00:33:20 +11:00
|
|
|
.rst (~res),
|
|
|
|
.display (display),
|
|
|
|
.digit1 (digits[0]),
|
|
|
|
.digit2 (digits[1]),
|
|
|
|
.digit3 (digits[2]),
|
|
|
|
.digit4 (digits[3]),
|
|
|
|
.digit5 (digits[4]),
|
|
|
|
.digit6 (digits[5]),
|
|
|
|
.digit7 (digits[6]),
|
|
|
|
.digit8 (digits[7]),
|
|
|
|
.leds (leds),
|
|
|
|
.keys (keys),
|
|
|
|
.tm_cs (tm_cs),
|
|
|
|
.tm_clk (tm_clk),
|
|
|
|
.tm_dio (tm_dio)
|
|
|
|
);
|
2018-01-10 16:39:18 +11:00
|
|
|
`endif
|
2018-01-02 00:33:20 +11:00
|
|
|
|
2018-01-12 01:01:34 +11:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// 6502 reset
|
|
|
|
|
|
|
|
reg [7:0] start;
|
|
|
|
always @(posedge clk)
|
|
|
|
if (~start[7]) start <= start + 1;
|
|
|
|
|
|
|
|
assign res = start[7];
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// 6502 phi0 clock
|
|
|
|
|
|
|
|
reg [3:0] div;
|
|
|
|
always @(posedge clk)
|
|
|
|
div <= div + 1;
|
|
|
|
|
|
|
|
SB_GB bg_phi (
|
|
|
|
.USER_SIGNAL_TO_GLOBAL_BUFFER(div[3]),
|
|
|
|
.GLOBAL_BUFFER_OUTPUT(clk_phi)
|
|
|
|
);
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// 6502
|
|
|
|
|
|
|
|
chip_6502 chip_6502 (
|
|
|
|
.clk (clk),
|
|
|
|
.phi (clk_phi),
|
|
|
|
.res (res && ~keys[0]),
|
|
|
|
.so (1'b0),
|
|
|
|
.rdy (1'b1),
|
|
|
|
.nmi (nmi),
|
|
|
|
.irq (irq),
|
|
|
|
.rw (rw),
|
|
|
|
.dbi (dbi),
|
|
|
|
.dbo (dbo),
|
|
|
|
.ab (ab)
|
|
|
|
);
|
|
|
|
|
2018-01-02 00:33:20 +11:00
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// I/O locations
|
|
|
|
|
2018-01-12 01:01:34 +11:00
|
|
|
localparam UART_RX = 16'hD010; // PIA.A register on Apple 1 - RX byte
|
|
|
|
localparam UART_RXCR = 16'hD011; // PIA.A register on Apple 1 - RX control
|
|
|
|
localparam UART_TX = 16'hD012; // PIA.B register on Apple 1 - TX byte
|
|
|
|
localparam LED_KEYS = 16'hD020; // Start address of the Led&Keys module
|
|
|
|
localparam LED = 16'hD000; // Breakout board LEDs
|
2018-01-02 00:33:20 +11:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// RAM and ROM
|
|
|
|
|
2018-01-10 16:39:18 +11:00
|
|
|
reg [7:0] ram[0:8191] /* synthesis syn_ramstyle = "block_ram" */;
|
|
|
|
reg [7:0] rom[0:255] /* synthesis syn_ramstyle = "block_ram" */;
|
2018-01-12 01:01:34 +11:00
|
|
|
reg [7:0] basic[0:4095] /* synthesis syn_ramstyle = "block_ram" */;
|
2018-01-10 16:39:18 +11:00
|
|
|
|
2018-01-02 00:33:20 +11:00
|
|
|
initial begin
|
2018-01-12 13:40:44 +11:00
|
|
|
$readmemh("../roms/ram.hex", ram, 0, 8191);
|
|
|
|
$readmemh("../roms/rom.hex", rom, 0, 255);
|
|
|
|
$readmemh("../roms/basic.hex", basic, 0, 4095);
|
2018-01-02 00:33:20 +11:00
|
|
|
end
|
|
|
|
|
|
|
|
always @(posedge clk_phi)
|
|
|
|
begin
|
|
|
|
// clear the UART RX ack if set
|
|
|
|
if (apple_rx_ack)
|
|
|
|
apple_rx_ack <= 0;
|
|
|
|
|
|
|
|
// clear the UART TX latch if set
|
|
|
|
if (apple_tx)
|
|
|
|
apple_tx <= 0;
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
begin
|
|
|
|
case(ab)
|
|
|
|
// UART TX control and TX register
|
|
|
|
UART_TX:
|
|
|
|
begin
|
|
|
|
if (rw)
|
|
|
|
dbi <= {is_transmitting, 7'd0};
|
|
|
|
else
|
|
|
|
begin
|
|
|
|
// Apple 1 terminal only uses 7 bits, MSB indicates
|
|
|
|
// terminal has ack'd RX
|
2018-01-10 16:39:18 +11:00
|
|
|
tx_byte <= dbo[6:0];
|
2018-01-02 00:33:20 +11:00
|
|
|
apple_tx <= 1;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// UART RX control register
|
|
|
|
UART_RXCR:
|
|
|
|
begin
|
|
|
|
if (rw)
|
|
|
|
dbi <= {apple_rx_flag, 7'b0};
|
|
|
|
end
|
|
|
|
|
|
|
|
// UART RX register
|
|
|
|
UART_RX:
|
|
|
|
begin
|
|
|
|
if (rw)
|
|
|
|
begin
|
|
|
|
// Apple 1 terminal only uses 7 bits, MSB tied high
|
|
|
|
// Wozmon checks for MSB being high
|
|
|
|
dbi <= apple_rx_flag ? {1'b1, apple_rx_buf} : 8'b0;
|
|
|
|
apple_rx_ack <= 1;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-01-10 16:39:18 +11:00
|
|
|
`ifdef LED_KEYS
|
2018-01-02 00:33:20 +11:00
|
|
|
// LED&KEYS registers
|
|
|
|
LED_KEYS: if (rw) dbi <= {4'b0, display}; else display <= dbo[3:0];
|
|
|
|
LED_KEYS + 1: if (rw) dbi <= digits[0]; else digits[0] <= dbo;
|
|
|
|
LED_KEYS + 2: if (rw) dbi <= digits[1]; else digits[1] <= dbo;
|
|
|
|
LED_KEYS + 3: if (rw) dbi <= digits[2]; else digits[2] <= dbo;
|
|
|
|
LED_KEYS + 4: if (rw) dbi <= digits[3]; else digits[3] <= dbo;
|
|
|
|
LED_KEYS + 5: if (rw) dbi <= digits[4]; else digits[4] <= dbo;
|
|
|
|
LED_KEYS + 6: if (rw) dbi <= digits[5]; else digits[5] <= dbo;
|
|
|
|
LED_KEYS + 7: if (rw) dbi <= digits[6]; else digits[6] <= dbo;
|
|
|
|
LED_KEYS + 8: if (rw) dbi <= digits[7]; else digits[7] <= dbo;
|
|
|
|
LED_KEYS + 9: if (rw) dbi <= leds; else leds <= dbo;
|
|
|
|
LED_KEYS + 10: if (rw) dbi <= keys;
|
2018-01-10 16:39:18 +11:00
|
|
|
`endif
|
2018-01-02 00:33:20 +11:00
|
|
|
|
|
|
|
// breakout board LED registers
|
|
|
|
LED: if (rw) dbi <= led; else led <= dbo;
|
|
|
|
|
|
|
|
default:
|
|
|
|
begin
|
2018-01-10 16:39:18 +11:00
|
|
|
if (ab[15:12] == 4'b0000 || ab[15:12] == 4'b0001)
|
2018-01-02 00:33:20 +11:00
|
|
|
begin
|
2018-01-10 16:39:18 +11:00
|
|
|
// 0x0000 -> 0x1FFF - RAM
|
2018-01-02 00:33:20 +11:00
|
|
|
dbi <= ram[ab[12:0]];
|
2018-01-10 16:39:18 +11:00
|
|
|
if (~rw) ram[ab[12:0]] <= dbo;
|
|
|
|
end
|
|
|
|
else if (ab[15:12] == 4'b1110)
|
|
|
|
begin
|
|
|
|
// 0xE000 -> 0xEFFF - BASIC
|
|
|
|
dbi <= basic[ab[11:0]];
|
|
|
|
end
|
|
|
|
else if (ab[15:8] == 8'b11111111)
|
|
|
|
begin
|
|
|
|
// 0xFF00 -> 0xFFFF - ROM
|
|
|
|
dbi <= rom[ab[7:0]];
|
2018-01-02 00:33:20 +11:00
|
|
|
end
|
|
|
|
else
|
|
|
|
// unknown address return zero
|
2018-01-12 01:01:34 +11:00
|
|
|
dbi <= 8'h0;
|
2018-01-02 00:33:20 +11:00
|
|
|
end
|
|
|
|
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// set irq and nmi high. for later use
|
|
|
|
assign irq = 1;
|
|
|
|
assign nmi = 1;
|
|
|
|
|
|
|
|
endmodule
|