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

Subversion Repositories pdp1

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /pdp1/trunk
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

/rtl/verilog/vector2scanline.v
0,0 → 1,93
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer: Yann Vernier
//
// Create Date: 21:37:32 02/19/2011
// Design Name:
// Module Name: vector2scanline
// Project Name: PDP-1
// Target Devices: Spartan 3A
// Tool versions:
// Description: Converts vector data (exposed points) into raster video
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
 
module vector2scanline(
input clk,
 
input strobe,
input [9:0] x,
input [9:0] y,
 
input [9:0] xout,
input [9:0] yout,
input newline,
input newframe,
output [7:0] pixel
);
 
parameter X_WIDTH = 10;
parameter Y_WIDTH = 10;
parameter HIST_WIDTH = 10;
parameter AGE_WIDTH = 8;
 
reg [X_WIDTH+Y_WIDTH+AGE_WIDTH-1:0] exposures [(2**HIST_WIDTH)-1:0];
reg [X_WIDTH+Y_WIDTH+AGE_WIDTH-1:0] expr;
wire [X_WIDTH-1:0] expx;
wire [Y_WIDTH-1:0] expy;
wire [7:0] expi;
wire exposed;
reg [HIST_WIDTH-1:0] exprptr=0, expwptr=0;
// double-buffered; one gets wiped as it is displayed
// the other gets filled in with current exposures
reg [AGE_WIDTH-1:0] scanline0 [(2**X_WIDTH)-1:0];
reg [AGE_WIDTH-1:0] scanline1 [(2**X_WIDTH)-1:0];
reg [AGE_WIDTH-1:0] pixelout;
reg bufsel = 0;
wire [X_WIDTH-1:0] sl0w, sl1w;
 
always @(posedge clk) begin
expr<=exposures[exprptr];
if (!strobe) begin
exprptr<=exprptr+1;
end
end
assign expx = strobe?x:expr[X_WIDTH+Y_WIDTH+AGE_WIDTH-1:Y_WIDTH+AGE_WIDTH];
assign expy = strobe?y:expr[Y_WIDTH+AGE_WIDTH-1:AGE_WIDTH];
assign expi = strobe?(2**AGE_WIDTH)-1:expr[AGE_WIDTH-1:0];
assign exposed = expi!=0;
 
always @(posedge clk) begin
// Feed incoming exposures into exposure buffer
if (exposed) begin
exposures[expwptr] <= {expx, expy, expy==yout?expi-1:expi};
expwptr <= expwptr+1;
end
end
 
assign sl0w=bufsel?expx:xout;
assign sl1w=bufsel?xout:expx;
always @(posedge clk) begin
// Read out & wipe front buffer
// Store exposures for current scanline as well
if (expy==(y+1)) begin
scanline0[sl0w] <= bufsel?expi:0;
scanline1[sl1w] <= bufsel?0:expi;
pixelout <= bufsel?scanline1[xout]:scanline0[xout];
end
if (newframe) begin
bufsel <= ~bufsel;
end
end
 
assign pixel = pixelout;
 
endmodule
/rtl/vhdl/top.vhd
0,0 → 1,267
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 21:25:57 02/09/2009
-- Design Name:
-- Module Name: top - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity top is
Port (
CLK_50M : in STD_LOGIC;
CLK_AUX : in STD_LOGIC; -- 133.33 MHz
LED : out std_logic_vector(7 downto 0) := (others=>'0');
SW : in std_logic_vector(3 downto 0);
AWAKE : out std_logic := '0';
-- SPI is in use for DAC outputs to oscilloscope
SPI_MOSI : OUT std_logic := 'L';
DAC_CS : OUT std_logic := '1';
SPI_SCK : OUT std_logic := 'L';
DAC_CLR : OUT std_logic := 'L';
DAC_OUT : IN std_logic := 'L';
-- VGA is (planned) for emulated vector graphics
VGA_R : out STD_LOGIC_VECTOR (3 downto 0);
VGA_G : out STD_LOGIC_VECTOR (3 downto 0);
VGA_B : out STD_LOGIC_VECTOR (3 downto 0);
VGA_HSYNC : out STD_LOGIC := '1';
VGA_VSYNC : out STD_LOGIC := '0';
-- DCE serial port is used for communications with PC
RS232_DCE_RXD : IN std_logic;
RS232_DCE_TXD : OUT std_logic := '1';
-- pushbutton to be debounced
BTN_EAST : IN std_logic := '0'
);
end top;
 
architecture Behavioral of top is
subtype word is std_logic_vector(0 to 17);
component vga is
Port ( VGA_R : out STD_LOGIC_VECTOR (3 downto 0);
VGA_G : out STD_LOGIC_VECTOR (3 downto 0);
VGA_B : out STD_LOGIC_VECTOR (3 downto 0);
VGA_HSYNC : out STD_LOGIC := '1';
VGA_VSYNC : out STD_LOGIC := '0';
CLK_50M : in STD_LOGIC;
CLK_133M33 : in STD_LOGIC);
end component;
 
component pdp1io is
Port (
CLK_50M : in STD_LOGIC;
CLK_PDP : in STD_LOGIC;
 
IO_SET : out STD_LOGIC;
IO_TO_CPU : out STD_LOGIC_VECTOR(0 to 17);
AC, IO_FROM_CPU : in STD_LOGIC_VECTOR(0 to 17);
IOT : in STD_LOGIC_VECTOR(0 to 63);
IO_RESTART : out STD_LOGIC;
IO_DORESTART : in STD_LOGIC;
 
-- SPI is in use for DAC outputs to oscilloscope
SPI_MOSI : OUT std_logic;
DAC_CS : OUT std_logic;
SPI_SCK : OUT std_logic;
DAC_CLR : OUT std_logic;
DAC_OUT : IN std_logic;
-- DCE serial port is used for communications with PC
RS232_DCE_RXD : IN std_logic;
RS232_DCE_TXD : OUT std_logic
);
end component;
 
COMPONENT flagcross
generic ( width : integer := 0 );
PORT(
ClkA, ClkB, FastClk : IN std_logic;
A : IN std_logic;
B : OUT std_logic;
A_reg : in STD_LOGIC_VECTOR(0 to width-1);
B_reg : out STD_LOGIC_VECTOR(0 to width-1)
);
END COMPONENT;
 
component coremem
Port ( A : in STD_LOGIC_VECTOR (0 to 11);
CLK : in STD_LOGIC;
WE : in STD_LOGIC;
DI : in word;
DO : inout word);
end component;
 
component clockdiv
Port ( CLK_50M : in STD_LOGIC;
CLK : out STD_LOGIC; -- 2MHz
LOCKED : out STD_LOGIC);
end component;
 
component pdp1cpu
Port ( M_DO : in word;
M_DI : out word;
MW : inout STD_LOGIC;
MA : out STD_LOGIC_VECTOR (0 to 11);
 
AWAKE : out STD_LOGIC;
 
CLK : in STD_LOGIC;
 
IOT : out STD_LOGIC_VECTOR(0 to 63);
IODOPULSE : out STD_LOGIC;
IODONE : in STD_LOGIC;
IO_set : in STD_LOGIC;
IO_IN : in STD_LOGIC_VECTOR(0 to 17);
 
PC : inout unsigned(0 to 11); -- program counter
AC, IO : inout word;
SW_SENSE : in STD_LOGIC_VECTOR(1 to 6);
RESET : in STD_LOGIC);
end component;
 
COMPONENT debounce
PORT(
clk : IN std_logic;
clken : IN std_logic;
input : IN std_logic;
output : INOUT std_logic
);
END COMPONENT;
 
signal CLK, CLK_LOCKED, RESET : std_logic := '0';
signal mem_we : std_logic := '0';
signal mem_di, mem_do, io, ac, io_in : word := (others=>'0');
signal sw_sense : std_logic_vector(1 to 6) := o"00";
signal mem_a : std_logic_vector(0 to 11) := (others=>'0');
 
signal pc : unsigned(0 to 11);
signal io_dopulse, io_done, io_set : std_logic := '0';
signal IOT : std_logic_vector(0 to 63) := (others=>'0');
signal display_trig, display_done: std_logic;
constant pdp1_enabled : boolean := true;
begin
RESET <= (not CLK_LOCKED) or BTN_EAST;
 
vga_out : vga port map (
CLK_50M => CLK_50M,
CLK_133M33 => CLK_AUX,
VGA_R => VGA_R,
VGA_G => VGA_G,
VGA_B => VGA_B,
VGA_HSYNC => VGA_HSYNC,
VGA_VSYNC => VGA_VSYNC
);
 
dummy: if not pdp1_enabled generate
begin
LED <= (others => '0');
SPI_SCK <= '0';
RS232_DCE_TXD <= '1';
SPI_MOSI <= '0';
DAC_CLR <= '0';
AWAKE <= '1';
DAC_CS <= '1';
end generate;
 
disabled: if pdp1_enabled generate
begin
clock : clockdiv
port map (
CLK_50M => CLK_50M,
CLK => CLK,
LOCKED => CLK_LOCKED
);
 
core : coremem
port map (
CLK => CLK,
WE => mem_we,
DI => mem_di,
DO => mem_do,
A => mem_a
);
-- AWAKE <= '1';
cpu : pdp1cpu
port map (
CLK => CLK,
AWAKE => AWAKE,
 
M_DO => mem_do,
M_DI => mem_di,
MW => mem_we,
MA => mem_a,
 
IOT => IOT,
IODOPULSE => io_dopulse,
IODONE => io_done,
IO_IN => io_in,
IO_SET => io_set,
 
PC => pc,
IO => IO,
AC => AC,
SW_SENSE => SW_SENSE,
RESET => RESET
);
iodevices : pdp1io port map (
CLK_50M => CLK_50M,
CLK_PDP => CLK,
IO_SET => io_set,
IO_TO_CPU => io_in,
IO_FROM_CPU => IO,
AC => AC,
IOT => iot,
IO_RESTART => io_done,
IO_DORESTART => io_dopulse,
-- display device uses DAC
SPI_MOSI => SPI_MOSI,
DAC_CS => DAC_CS,
SPI_SCK => SPI_SCK,
DAC_CLR => DAC_CLR,
DAC_OUT => DAC_OUT,
-- paper tape reader uses RS232
RS232_DCE_RXD => RS232_DCE_RXD,
RS232_DCE_TXD => RS232_DCE_TXD);
 
with SW select
LED <=
std_logic_vector(PC(11-7 to 11)) when "0000",
IO(0 to 7) when others;
SW_SENSE(1 to 4) <= SW(3 downto 0);
 
Inst_debounce: debounce PORT MAP(
clk => CLK,
clken => '1',
input => BTN_EAST,
output => SW_SENSE(5)
);
end generate;
 
end Behavioral;
/rtl/vhdl/testtop.vhd
0,0 → 1,164
--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 00:00:04 08/14/2009
-- Design Name:
-- Module Name: /home/yann/fpga/work/pdp1-3/testtop.vhd
-- Project Name: pdp1-3
-- Target Device:
-- Tool versions:
-- Description:
--
-- VHDL Test Bench Created by ISE for module: top
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes:
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test. Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
ENTITY testtop IS
END testtop;
ARCHITECTURE behavior OF testtop IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT top
PORT(
CLK_50M : IN std_logic;
LED : OUT std_logic_vector(7 downto 0);
SW : IN std_logic_vector(3 downto 0);
AWAKE : OUT std_logic;
SPI_MOSI : OUT std_logic;
DAC_CS : OUT std_logic;
SPI_SCK : OUT std_logic;
DAC_CLR : OUT std_logic;
DAC_OUT : IN std_logic;
RS232_DCE_RXD : IN std_logic;
RS232_DCE_TXD : OUT std_logic
);
END COMPONENT;
 
--Inputs
signal CLK_50M : std_logic := '0';
signal SW : std_logic_vector(3 downto 0) := (others => '0');
signal DAC_OUT : std_logic := '0';
 
--Outputs
signal LED : std_logic_vector(7 downto 0);
signal AWAKE : std_logic;
signal SPI_MOSI : std_logic;
signal DAC_CS : std_logic;
signal SPI_SCK : std_logic;
signal DAC_CLR : std_logic;
signal TXD, RXD : std_logic;
constant CLK_50M_period : time := 20ns;
constant bittime : time := 8.680555us; --1s/115200;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: top PORT MAP (
CLK_50M => CLK_50M,
LED => LED,
SW => SW,
AWAKE => AWAKE,
SPI_MOSI => SPI_MOSI,
DAC_CS => DAC_CS,
SPI_SCK => SPI_SCK,
DAC_CLR => DAC_CLR,
DAC_OUT => DAC_OUT,
RS232_DCE_RXD => RXD,
RS232_DCE_TXD => TXD
);
-- No clocks detected in port list. Replace CLK_50M below with
-- appropriate port name
CLK_50M_process :process
begin
CLK_50M <= '0';
wait for CLK_50M_period/2;
CLK_50M <= '1';
wait for CLK_50M_period/2;
end process;
 
-- Stimulus process
stim_proc: process
begin
RXD <= '1';
-- hold reset state for 100ms.
wait for 10ms;
wait for 16*bittime;
-- TODO: show reply data
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime; -- first sixbit 000101
wait for 16*bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime; -- this byte is not marked as binary data and should be skipped
wait for 16*bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime; -- second sixbit 001100
wait for 16*bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime; -- third sixbit 111000
 
 
wait for CLK_50M_period*10;
 
-- insert stimulus here
 
wait;
end process;
 
END;
/rtl/vhdl/flagcross.vhd
0,0 → 1,84
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 16:16:44 03/07/2009
-- Design Name:
-- Module Name: flagcross - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description: Module to send a flag (1-cycle high pulse) from one clock domain to another.
-- Intended to work both fast to slow and slow to fast, but fast to slow may give
-- a single pulse for several incoming.
-- Extension: add a register transfer, enabled by flag.
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity flagcross is
generic ( width : integer := 0 );
Port ( ClkA : in STD_LOGIC;
ClkB : in STD_LOGIC;
FastClk : in STD_LOGIC;
A : in STD_LOGIC;
B : out STD_LOGIC := '0';
A_reg : in STD_LOGIC_VECTOR(0 to width-1) := (others => '0');
B_reg : out STD_LOGIC_VECTOR(0 to width-1));
end flagcross;
 
architecture Behavioral of flagcross is
signal toggle_a, old_a0, old_a1, seen_a, toggle_b : std_logic := '0';
signal reg : std_logic_vector(0 to width-1);
begin
process(ClkA)
begin
if rising_edge(ClkA) then
if A='1' then
toggle_a <= not toggle_a;
reg <= A_reg;
end if;
end if;
end process;
process(FastClk)
begin
if rising_edge(FastClk) then
if width>0 then
old_a0 <= toggle_a; -- make sure reg can settle
old_a1 <= old_a0;
else
old_a1 <= toggle_a;
end if;
if old_a1/=toggle_a then
seen_a <= not toggle_b;
end if;
end if;
end process;
process(ClkB)
begin
if rising_edge(ClkB) then
if seen_a/=toggle_b then
B <= '1';
B_reg <= reg;
toggle_b <= not toggle_b;
else
B <= '0';
end if;
end if;
end process;
end Behavioral;
 
/rtl/vhdl/ptr_test.vhd
0,0 → 1,166
--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 00:16:45 08/22/2009
-- Design Name:
-- Module Name: /home/yann/fpga/work/pdp1-3/ptr_test.vhd
-- Project Name: pdp1-3
-- Target Device:
-- Tool versions:
-- Description:
--
-- VHDL Test Bench Created by ISE for module: papertapereader
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes:
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test. Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
ENTITY ptr_test IS
END ptr_test;
ARCHITECTURE behavior OF ptr_test IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT papertapereader
PORT(
clk : IN std_logic;
dopulse : IN std_logic;
done : OUT std_logic;
io : OUT std_logic_vector(0 to 17);
io_loaded : IN std_logic;
ptr_rpa : IN std_logic;
ptr_rpb : IN std_logic;
ptr_rrb : IN std_logic;
rb_loaded : OUT std_logic;
RXD : IN std_logic;
TXD : OUT std_logic
);
END COMPONENT;
 
--Inputs
signal clk : std_logic := '0';
signal dopulse : std_logic := '0';
signal io_loaded : std_logic := '0';
signal ptr_rpa : std_logic := '0';
signal ptr_rpb : std_logic := '0';
signal ptr_rrb : std_logic := '0';
signal RXD : std_logic := '1';
 
--Outputs
signal done : std_logic;
signal io : std_logic_vector(0 to 17);
signal rb_loaded : std_logic;
signal TXD : std_logic;
 
-- Clock period definitions
constant clk_period : time := 20ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: papertapereader PORT MAP (
clk => clk,
dopulse => dopulse,
done => done,
io => io,
io_loaded => io_loaded,
ptr_rpa => ptr_rpa,
ptr_rpb => ptr_rpb,
ptr_rrb => ptr_rrb,
rb_loaded => rb_loaded,
RXD => RXD,
TXD => TXD
);
 
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
 
-- Stimulus process
stim_proc: process
constant bittime : time := 8.680555us;
begin
-- hold reset state for 100ms.
--wait for 100ms;
wait for 2*bittime;
ptr_rpb <= '1'; dopulse <= '1';
wait for clk_period;
ptr_rpb <= '0'; dopulse <= '0';
 
wait for 16*bittime;
-- TODO: show reply data
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime; -- first sixbit 000101
wait for 16*bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime; -- this byte is not marked as binary data and should be skipped
wait for 16*bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime; -- second sixbit 001100
wait for 16*bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '0'; wait for bittime;
RXD <= '1'; wait for bittime;
RXD <= '1'; wait for bittime; -- third sixbit 111000
 
--wait for clk_period*10;
 
-- insert stimulus here
 
wait;
end process;
 
END;
/rtl/vhdl/papertapereader.vhd
0,0 → 1,135
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 23:37:05 2009-08-20
-- Design Name: fake paper tape reader for PDP-1
-- Module Name: papertapereader - Behavioral
-- Project Name: PDP-1
-- Target Devices: Spartan 3A Starter Kit
-- Tool versions: Webpack 11.1
-- Description: RS-232 interface emulating a tape reader.
--
-- Dependencies: Minimal UART core from opencores.
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity papertapereader is
Port ( clk : in STD_LOGIC;
dopulse : in STD_LOGIC;
done : out STD_LOGIC := 'L';
io : out STD_LOGIC_VECTOR (0 to 17) := (others=>'L');
io_set : out STD_LOGIC := 'L';
ptr_rpa : in STD_LOGIC;
ptr_rpb : in STD_LOGIC;
ptr_rrb : in STD_LOGIC;
rb_loaded : out STD_LOGIC;
RXD : in std_logic;
TXD : out std_logic);
end papertapereader;
 
architecture Behavioral of papertapereader is
COMPONENT Minimal_UART_CORE
PORT(
CLOCK : IN std_logic;
RXD : IN std_logic;
INP : IN std_logic_vector(7 downto 0);
WR : IN std_logic;
OUTP : INOUT std_logic_vector(7 downto 0);
EOC : OUT std_logic;
TXD : OUT std_logic;
EOT : OUT std_logic;
READY : OUT std_logic
);
END COMPONENT;
signal rb : std_logic_vector(0 to 17);
signal received_byte, old_received_byte, tx_ready, wrote : std_logic := '0';
signal read_byte, write_byte: std_logic_vector(7 downto 0);
type task_type is (read_character, read_word0, read_word1, read_word2, done_reading, idle);
signal task : task_type := idle;
signal senddone : std_logic;
begin
Inst_Minimal_UART_CORE: Minimal_UART_CORE PORT MAP(
CLOCK => CLK,
EOC => received_byte, -- end of character; rising edge indicates valid data in OUTP
OUTP => read_byte,
RXD => RXD,
TXD => TXD,
 
EOT => open, -- end of transmit; indicates a character has been sent
INP => write_byte,
READY => tx_ready, -- indicates that we may write
WR => wrote
);
write_byte <= x"65"; --"e" --"00010010"; -- ASCII device control 2 (Ctrl+R) to request a byte from the tape.
rb_loaded <= '1' when task=done_reading else '0';
process(clk)
begin
if rising_edge(clk) then
-- default state for pulse signals
wrote<='0';
done <= '0';
io_set <= '0';
-- load edge detector
old_received_byte <= received_byte;
if received_byte='1' and old_received_byte='0' then
case task is
when idle => -- not awaiting a character, ignore it
when read_character =>
rb(0 to 17-8) <= (others=>'0');
rb(17-7 to 17) <= read_byte;
task <= done_reading;
when read_word0 =>
if read_byte(7)='1' then
rb(0 to 5) <= read_byte(5 downto 0);
task <= read_word1;
end if;
wrote<='1'; -- request another byte
when read_word1 =>
if read_byte(7)='1' then
rb(6 to 11) <= read_byte(5 downto 0);
task <= read_word2;
end if;
wrote<='1'; -- request another byte
when read_word2 =>
if read_byte(7)='1' then
rb(12 to 17) <= read_byte(5 downto 0);
task <= done_reading;
else
wrote<='1'; -- request another byte
end if;
when others =>
end case;
end if; -- received a byte
if ptr_rpa='1' then
task<=read_character;
senddone<=dopulse;
wrote<='1';
elsif ptr_rpb='1' then
task<=read_word0;
senddone<=dopulse;
wrote<='1';
elsif ptr_rrb='1' then
senddone<=dopulse;
end if;
if task=done_reading and senddone='1' then
done<='1';
IO<=rb;
io_set<='1';
task <= idle;
end if;
end if; -- rising_edge(clk)
end process;
--io(0 to 17-8) <= (others => '0');
--io(17-7 to 17) <= read_byte;
end Behavioral;
/rtl/vhdl/onecomplement_adder.vhd
0,0 → 1,47
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 04:01:09 08/19/2009
-- Design Name:
-- Module Name: onecomplement_adder - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
--use IEEE.STD_LOGIC_ARITH.ALL;
--use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity onecomplement_adder is
generic (width: Integer := 18);
Port ( A : in STD_LOGIC_VECTOR (0 to width-1);
B : in STD_LOGIC_VECTOR (0 to width-1) := (others=>'0');
CI : in STD_LOGIC := '0'; -- TODO: verify whether overflow is handled correctly with CI=1
-- it is (so far) only used for the Divide Step instruction, which does not update OV
SUM : out STD_LOGIC_VECTOR (0 to width-1);
OV : out STD_LOGIC;
CSUM : out STD_LOGIC_VECTOR (0 to width-1)); -- cleaned up sum, will not be -0 (all 1s)
end onecomplement_adder;
 
architecture Behavioral of onecomplement_adder is
signal s1, s2: unsigned(0 to width);
signal c: unsigned(0 to 0);
begin
c <= "1" when CI='1' else "0";
s1 <= unsigned('0'&A)+unsigned('0'&B)+c;
s2 <= s1+1 when s1(0)='1' else s1; -- add carry back in for one's complement - very expensive, this got us a second adder!
OV <= '1' when s2(1)/=A(0) and A(0)=B(0) else '0';
sum <= std_logic_vector(s2(1 to width));
csum <= std_logic_vector(s2(1 to width)) when s2(1 to width)/=(2**width-1) else (others=>'0');
end Behavioral;
/rtl/vhdl/debounce.vhd
0,0 → 1,66
----------------------------------------------------------------------------------
-- Company:
-- Engineer: Yann Vernier
--
-- Create Date: 23:05:04 09/08/2009
-- Design Name:
-- Module Name: debounce - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description: Debounces an input signal (for instance, a switch).
-- Output will only change after input has stayed one value between two enabled clock edges.
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity debounce is
Port ( clk : in STD_LOGIC;
clken : in STD_LOGIC;
input : in STD_LOGIC;
output : inout STD_LOGIC);
end debounce;
 
-- Concept: input values are asynchronously connected to SR latches.
-- Those are synchronously reset, so if both are set, the input is unstable.
-- On Spartan 3 FPGAs, this architecture probably requires at least three slices,
-- due to separate RS lines for flip-flops. The output register may share, though.
architecture Behavioral of debounce is
-- 00->no input value observed (reset), 10 or 01 -> steady value, 11->value changed
signal inputv : std_logic_vector(0 to 1) := "00";
signal next_output : std_logic;
begin
-- our two asynch latches must agree for an update to occur
-- the tricky part of the code was convincing the synthesizer we only need one LUT3
-- to implement this consensus function (inputv must agree to alter output).
with inputv select
next_output <= '0' when "10",
'1' when "01",
output when others;
process (clk, input)
begin
-- input='0' for asynch set of input(0), synch reset
if input='0' then
inputv(0) <= '1';
elsif clken='1' and rising_edge(clk) then
inputv(0) <= '0';
end if;
-- same for 1
if input='1' then
inputv(1) <= '1';
elsif clken='1' and rising_edge(clk) then
inputv(1) <= '0';
end if;
-- finally, on enabled clocks, update output
if clken='1' and rising_edge(clk) then
output <= next_output;
end if;
end process;
end Behavioral;
/rtl/vhdl/display.vhd
0,0 → 1,136
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 19:20:52 03/03/2009
-- Design Name:
-- Module Name: display - Behavioral
-- Project Name:
-- Target Devices: Spartan-3A starter kit SPI DAC
-- Tool versions:
-- Description: Oscilloscope output module for PDP-1.
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity display is
Port ( X : in STD_LOGIC_VECTOR (0 to 9);
Y : in STD_LOGIC_VECTOR (0 to 9);
CLK : in STD_LOGIC;
TRIG, DOPULSE : in STD_LOGIC;
DONE : out STD_LOGIC := '0';
SPI_MOSI, DAC_CS, SPI_SCK, DAC_CLR : out STD_LOGIC);
end display;
 
architecture Behavioral of display is
signal command : std_logic_vector(23 downto 6) := (others=>'1');
shared variable Xin, Yin : std_logic_vector(0 to 9) := (others=>'0');
shared variable newval, dodone : boolean := false;
begin
DAC_CLR <= '1';
SPI_SCK <= not CLK;
SPI_MOSI <= command(command'left);
process(CLK)
 
variable Xidle, Yidle : std_logic_vector(0 to 9) := (others=>'0');
variable count : integer range 0 to exposure := 0;
type direction is (left, up, right, down);
variable dir : direction := right;
begin
if rising_edge(CLK) then
if TRIG='1' then
if X(0)='1' then
Xin(1 to Xin'right) := X(1 to X'right)+1;
else
Xin(1 to Xin'right) := X(1 to X'right);
end if;
Xin(0) := not X(0);
if Y(0)='1' then
Yin(1 to Yin'right) := Y(1 to Y'right)+1;
else
Yin(1 to Yin'right) := Y(1 to Y'right);
end if;
Yin(0) := not Y(0);
newval := true;
count := 0;
dodone := DOPULSE='1';
end if;
case count is
when 0=>
DONE <= '0';
DAC_CS <= '0';
if newval then -- channel 3 does X, set without update
command <= x"03" & Xin;
else
case dir is
when right =>
Xidle := Xidle+1;
if Xidle="1111111111" then
dir:=up;
end if;
when up =>
Yidle := Yidle+1;
if Yidle="1111111111" then
dir:=left;
end if;
when left =>
Xidle := Xidle-1;
if Xidle="0000000000" then
dir:=down;
end if;
when down =>
Yidle := Yidle-1;
if Yidle="0000000000" then
dir:=right;
end if;
end case;
command <= x"03" & Xidle;
end if;
count:=count+1;
when 24=>
DAC_CS <= '1';
count:=count+1;
when 25=>
if newval then -- channel 2 is Y, update all DACs
command <= x"22" & Yin;
else
command <= x"22" & Yidle;
end if;
DAC_CS <= '0';
count:=count+1;
when 25+24=>
DAC_CS <= '1';
if newval then
count:=count+1;
else
count := 0;
end if;
when exposure =>
if dodone then
DONE <= '1';
end if;
newval := false;
count := 0;
when others => -- shift out command bits
command <= command(command'left-1 downto command'right)&'1';
count := count+1;
end case;
end if;
end process;
end Behavioral;
/rtl/vhdl/io.vhd
0,0 → 1,187
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 21:25:57 02/09/2009
-- Design Name:
-- Module Name: pdp1io - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description: I/O subsystem for PDP-1, connect to CPU. Instantiates I/O devices.
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity pdp1io is
Port (
CLK_50M : in STD_LOGIC;
CLK_PDP : in STD_LOGIC;
 
IO_SET : out STD_LOGIC;
IO_TO_CPU : out STD_LOGIC_VECTOR(0 to 17);
AC, IO_FROM_CPU : in STD_LOGIC_VECTOR(0 to 17);
IOT : in STD_LOGIC_VECTOR(0 to 63);
IO_RESTART : out STD_LOGIC;
IO_DORESTART : in STD_LOGIC;
 
-- SPI is in use for DAC outputs to oscilloscope
SPI_MOSI : OUT std_logic;
DAC_CS : OUT std_logic;
SPI_SCK : OUT std_logic;
DAC_CLR : OUT std_logic;
DAC_OUT : IN std_logic;
-- DCE serial port is used for communications with PC
RS232_DCE_RXD : IN std_logic;
RS232_DCE_TXD : OUT std_logic
);
end pdp1io;
 
architecture Behavioral of pdp1io is
subtype word is std_logic_vector(0 to 17);
 
COMPONENT flagcross
generic ( width : integer := 0 );
PORT(
ClkA, ClkB, FastClk : IN std_logic;
A : IN std_logic := '0';
B : OUT std_logic;
A_reg : in STD_LOGIC_VECTOR(0 to width-1) := (others => '0');
B_reg : out STD_LOGIC_VECTOR(0 to width-1)
);
END COMPONENT;
 
COMPONENT display
PORT(
X : IN std_logic_vector(0 to 9);
Y : IN std_logic_vector(0 to 9);
CLK : IN std_logic;
 
TRIG, DOPULSE : IN std_logic;
DONE : OUT std_logic;
SPI_MOSI : OUT std_logic;
DAC_CS : OUT std_logic;
SPI_SCK : OUT std_logic;
DAC_CLR : OUT std_logic
);
END COMPONENT;
 
COMPONENT papertapereader
PORT(
clk : IN std_logic;
dopulse : IN std_logic;
ptr_rpa : IN std_logic;
ptr_rpb : IN std_logic;
ptr_rrb : IN std_logic;
RXD : IN std_logic;
done : OUT std_logic;
io : OUT std_logic_vector(0 to 17);
io_set : out STD_LOGIC := 'L';
rb_loaded : OUT std_logic;
TXD : OUT std_logic
);
END COMPONENT;
signal ptr_rpa, ptr_rpb, ptr_rrb, ptr_done, ptr_io_set: std_logic;
signal ptr_io : word;
 
signal display_trig, display_done, combined_done: std_logic;
begin
-- no need to cross-transfer I/O because display is faster than cpu
disppulse: flagcross PORT MAP(
ClkA => CLK_PDP,
ClkB => CLK_50M,
FastCLK => CLK_50M,
A => IOT(7),
B => display_trig,
A_reg => open,
B_reg => open
);
Inst_display: display PORT MAP(
X => AC(0 to 9),
Y => IO_FROM_CPU(0 to 9),
CLK => CLK_50M,
 
TRIG => display_trig,
DONE => display_done,
DOPULSE => IO_DORESTART,
 
SPI_MOSI => SPI_MOSI,
DAC_CS => DAC_CS,
SPI_SCK => SPI_SCK,
DAC_CLR => DAC_CLR
);
 
Inst_papertapereader: papertapereader PORT MAP(
clk => CLK_50M,
dopulse => IO_DORESTART,
done => ptr_done,
io => ptr_io,
io_set => ptr_io_set,
ptr_rpa => ptr_rpa,
ptr_rpb => ptr_rpb,
ptr_rrb => ptr_rrb,
rb_loaded => open, -- for sequence break
RXD => RS232_DCE_RXD,
TXD => RS232_DCE_TXD
);
ptrio: flagcross GENERIC MAP(width=>18) PORT MAP(
ClkA => CLK_50M,
ClkB => CLK_PDP,
FastClk => CLK_50M,
A => ptr_io_set,
B => io_set,
A_reg => ptr_io,
B_reg => IO_TO_CPU
);
ptrrpa: flagcross PORT MAP(
ClkA => CLK_PDP,
ClkB => CLK_50M,
FastClk => CLK_50M,
A => iot(1),
B => ptr_rpa,
A_reg => open,
B_reg => open
);
ptrrpb: flagcross PORT MAP(
ClkA => CLK_PDP,
ClkB => CLK_50M,
FastClk => CLK_50M,
A => iot(2),
B => ptr_rpb,
A_reg => open,
B_reg => open
);
ptrrrb: flagcross PORT MAP(
ClkA => CLK_PDP,
ClkB => CLK_50M,
FastClk => CLK_50M,
A => iot(8#30#), -- I/O manual and PDP-1 manual disagree on IOT#.
B => ptr_rrb,
A_reg => open,
B_reg => open
);
 
combined_done <= display_done or ptr_done;
restart : flagcross port map (
ClkA => CLK_50M,
ClkB => CLK_PDP,
FastClk => CLK_50M,
A => combined_done,
B => IO_RESTART,
A_reg => open,
B_reg => open);
end Behavioral;
/rtl/vhdl/pdp1rotshift.vhd
0,0 → 1,101
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 15:39:56 08/10/2009
-- Design Name:
-- Module Name: pdp1rotshift - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
 
entity pdp1rotshift is
Port ( ac : in STD_LOGIC_VECTOR (0 to 17);
io : in STD_LOGIC_VECTOR (0 to 17);
right : in STD_LOGIC; -- '0' for left, '1' for right
shift : in STD_LOGIC; -- '1' for shift, '0' for rotate
words : in STD_LOGIC_VECTOR (0 to 1);
acout : out STD_LOGIC_VECTOR (0 to 17);
ioout : out STD_LOGIC_VECTOR (0 to 17));
end pdp1rotshift;
 
architecture Behavioral of pdp1rotshift is
signal input, output: std_logic_vector(0 to 35);
signal word: std_logic_vector(0 to 17);
constant use_readable_code: boolean := true;
begin
cond_gen: if use_readable_code generate
with words select
input <= AC&AC when "01",
IO&IO when "10",
AC&IO when "11",
(others=>'-') when others;
 
output <= std_logic_vector(unsigned(input) rol 1) when right='0' and shift='0' else
std_logic_vector(unsigned(input) sll 1) when right='0' and shift='1' else
std_logic_vector(unsigned(input) ror 1) when right='1' and shift='0' else
std_logic_vector(unsigned(input) srl 1) when right='1' and shift='1' else
(others=>'-');
word <= output(0 to 17) when right='1' else output(18 to 35);
 
with words select
acout <= word when "01",
output(0 to 17) when "11",
ac when others;
 
with words select
ioout <= word when "10",
output(18 to 35) when "11",
io when others;
end generate;
 
cond_explicit_rtl: if not use_readable_code generate
acout(0) <= ac(0) when words(1)='0' else -- not working on AC
ac(1) when right='0' else -- shift/rot left
'0' when shift='1' else -- shift right
ac(17) when words(0)='0' else -- rotate ac right
io(17) when words(0)='1' else -- rotate ac&io right
'-';
acout(1 to 16) <= ac(1 to 16) when words(1)='0' else -- not working on AC
ac(2 to 17) when right='0' else -- left
ac(0 to 15) when right='1' else -- right
(others=>'-');
acout(17) <= ac(17) when words(1)='0' else -- not working on ac
ac(16) when right='1' else -- shift/rot right
io(0) when words(0)='1' else -- shift/rot left ac&io
'0' when shift='1' else -- shift ac left
ac(0) when shift='0' else -- rotate ac left
'-';
 
ioout(0) <= io(0) when words(0)='0' else -- not working on IO
io(1) when right='0' else -- left
ac(17) when words(1)='1' else -- ac&io right
'0' when shift='1' else -- shift io right
io(17) when shift='0' else -- rotate io right
'-';
ioout(1 to 16) <= io(1 to 16) when words(0)='0' else
io(2 to 17) when right='0' else
io(0 to 15) when right='1' else
(others=>'-');
ioout(17) <= io(17) when words(0)='0' else
io(16) when right='1' else
'0' when shift='1' else
ac(0) when words(1)='1' else
io(0) when words(1)='0' else
'-';
end generate;
end Behavioral;
 
/rtl/vhdl/coremem.vhd
0,0 → 1,185
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 12:27:16 02/09/2009
-- Design Name:
-- Module Name: coremem - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- TODO: Convert to use Xilinx instantiation, because the 18-bit wide memory
-- gets converted to 4 1k*16 and 1 4k*2, wasting a block ram.
-- This is because Xilinx tools do not automatically use the parity bits.
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.STD_LOGIC_TEXTIO.ALL;
use STD.TEXTIO.ALL;
 
---- For instantiating Xilinx block RAMs
--library UNISIM;
--use UNISIM.VComponents.all;
 
entity coremem is
Port ( A : in STD_LOGIC_VECTOR (0 to 11);
CLK : in STD_LOGIC;
-- The PDP-1 can write to high 6 bits, low 12 bits, or both.
-- To emulate this we need a higher clock to do load-modify-store.
-- TODO: Actually, the PDP-1 rewrites after every read, giving it the
-- opportunity to read-modify-write itself, and does so for Index.
-- So the memory is simpler, runs load/store at double rate,
-- but the CPU needs a matching redesign.
WE : in STD_LOGIC;
ENABLE : in STD_LOGIC := '1';
DI : in STD_LOGIC_VECTOR (0 to 17);
-- DO defaults to jump to 0 instruction
DO : out STD_LOGIC_VECTOR (0 to 17) := o"76_4200" -- match core(0)!
);
end coremem;
 
architecture Behavioral of coremem is
constant ADDR_WIDTH : integer := 12;
constant DATA_WIDTH : integer := 18;
 
subtype word is std_logic_vector(0 to DATA_WIDTH-1);
-- important: if downto is used, the code lines must be written backwards!
type coremodule is array (0 to 2**ADDR_WIDTH-1) of word;
 
-- only works for very small initial programs.
impure function loadcore (filename : in string) return coremodule is
FILE corefile : text is in filename;
variable coreline : line;
variable core : coremodule := (others=>o"00_0000");
variable addr : integer := 0;
begin
--file_open(corefile, filename, READ_MODE);
for addr in coremodule'range loop
--while (not endfile(corefile)) and (addr<2**ADDR_WIDTH) loop
if not endfile(corefile) then
readline (corefile, coreline);
oread (coreline, core(addr));
--addr := addr+1;
end if;
end loop;
-- FIXME this isn't very robust, it breaks if there's an empty line
--file_close(corefile);
return core;
end function;
 
---- Xilinx IP generator version
--component xilinx_core
--port (
-- clka: IN std_logic;
-- wea: IN std_logic_VECTOR(0 downto 0);
-- addra: IN std_logic_VECTOR(11 downto 0);
-- dina: IN std_logic_VECTOR(17 downto 0);
-- douta: OUT std_logic_VECTOR(17 downto 0));
--end component;
--signal wea: std_logic_vector(0 to 0);
 
---- Synplicity black box declaration
--attribute syn_black_box : boolean;
--attribute syn_black_box of xilinx_core: component is true;
 
signal core: coremodule :=
--loadcore("testdpy.octal");
--loadcore("spacewar.octal");
(
-- tape reader test program
--o"73_0001", -- read paper alphanumeric with wait
--o"76_0000", -- NOP
--o"66_6777", -- shift left 9 bits
--o"66_6001", -- and 1 bit, leaving the read byte at
-- -- left edge of IO register
--o"60_0003", -- infinite loop to light AWAKE
 
-- counter test program (loads result into IO for display)
--o"60_0003", -- jump past constant
--o"00_0001", -- constant one
--o"00_0000", -- variable
--o"40_0001", -- add one to AC
--o"24_0002", -- store in memory
--o"22_0002", -- load into IO
 
--o"60_0000", -- jump back to start of program
 
-- tape read in emulation (see readin.mac)
8#0000# => o"60_7700", -- jump to program
8#7700# => o"73_0002", -- read paper binary
8#7701# => o"32_7706", -- deposit instruction just read
8#7702# => o"20_7706", -- read into AC
8#7703# => o"26_7710", -- deposit address into DIO for comparison
8#7704# => o"50_7710", -- skip read if instruction not DIO
8#7705# => o"73_0002", -- read word to be deposited
8#7706# => o"76_0400", -- overwritten instruction; initially halt
8#7707# => o"60_7700", -- repeat the loop
8#7710# => o"32_0000", -- deposit IO for comparison
others => o"60_0000"
);
-- signal unused : coremodule :=
-- (
-- o"60_0010", -- jump past constants and variables
-- o"37_7400", -- value to switch direction on
-- o"00_0000", -- unused
-- o"00_0400", -- step -- addr 0003
--
-- o"00_0000", -- variable
-- o"00_0000", -- padding
-- o"00_0000", -- padding
-- o"00_0000", -- padding
--
-- o"76_4200", -- clear AC and IO -- addr 0010 (start)
-- o"40_0003", -- add step to AC -- addr 0011 (loop)
-- o"24_0004", -- store AC to variable
-- o"22_0004", -- load count to IO
-- o"76_1000", -- complement AC
-- o"73_0007", -- display, with waiting
-- o"76_1000", -- switch AC back
-- o"52_0001", -- skip next instruction if AC=endpoint
-- o"60_0011", -- jump to beginning of loop
-- o"20_0001", -- load endpoint
-- o"76_1000", -- complement it
-- o"24_0001", -- store it back
-- o"20_0003", -- load step
-- o"76_1000", -- complement it
-- o"24_0003", -- store it back
-- o"20_0004", -- load count again
-- o"60_0011", -- jump back to loop
-- others => o"00_0000"
-- );
 
begin
process (CLK)
begin
if (CLK'event and CLK = '1') then
if (enable = '1') then
if (WE = '1') then
core(conv_integer(A)) <= DI;
end if;
DO <= core(conv_integer(A));
end if;
end if;
end process;
--wea(0)<=we;
--xil_core : xilinx_core
-- port map (
-- clka => clk,
-- wea => wea,
-- addra => a,
-- dina => di,
-- douta => do);
end Behavioral;
 
/rtl/vhdl/pdp1cpu.vhd
0,0 → 1,544
----------------------------------------------------------------------------------
-- Company: None
-- Engineer: Yann Vernier
--
-- Create Date: 13:29:13 02/09/2009
-- Design Name:
-- Module Name: pdp1cpu - Behavioral
-- Project Name: PDP-1
-- Target Devices: Xilinx Spartan 3A
-- Tool versions: WebPack 10.1
-- Description: PDP-1 CPU (main logic) module, executes instructions.
--
-- Dependencies: Requires a RAM and a clock source. RAM is accessed in alternating read and write.
-- Original clock is 200kHz memory cycle, where each cycle both
-- reads and writes (core memory). CPU itself must be clocked 10
-- times faster (original logic modules could keep up with 4MHz).
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
-- Aim is currently a PDP-1B level.
-- B version had multiply and divide Step to accelerate the subroutines,
-- and the first had pure software subroutines. C had full hardware multiply(?).
-- PDP-1D implements several more instructions not included here.
-- Extensions (including sequence break and extended memory) are not implemented.
--
-- Goal: Run Spacewar! in hardware. Initial target version is that used by Java
-- emulator, which is a PDP-1B, with multiply and divide steps.
-- That emulator doesn't have DIP.
-- PDP-1C had full multiply and divide instructions of variable time.
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
 
entity pdp1cpu is
Port (
-- memory interface
M_DI : out STD_LOGIC_VECTOR(0 to 17) := (others=>'0');
M_DO : in STD_LOGIC_VECTOR(0 to 17);
MW : inout STD_LOGIC := '0';
MA : out std_logic_vector(0 to 11) := (others=>'0');
CLK : in STD_LOGIC; -- in progress: adapt to 10x clock
 
-- CPU status
AWAKE : out STD_LOGIC;
 
-- user visible registers
AC : inout STD_LOGIC_VECTOR(0 to 17) := (others=>'0'); -- accumulator
IO : inout STD_LOGIC_VECTOR(0 to 17) := (others=>'0'); -- I/O
PC : inout unsigned(0 to 11) := (others=>'0'); -- program counter
PF : inout STD_LOGIC_VECTOR(1 to 6) := (others=>'0'); -- program flags
OV : inout STD_LOGIC := '0'; -- overflow flag
 
-- user settable switches
SW_TESTA : in std_logic_vector(0 to 11) := (others => '0'); -- test address
SW_TESTW : in std_logic_vector(0 to 17) := (others => '0'); -- test word
SW_SENSE : in std_logic_vector(1 to 6) := (others => '0'); -- sense switches
-- I/O interface
IOT : out STD_LOGIC_VECTOR(0 to 63) := (others=>'0'); -- I/O transfer pulse lines
IODOPULSE : out STD_LOGIC := '0'; -- signal to I/O device to send a
-- pulse when done
IODONE : in STD_LOGIC := '0'; -- I/O device done signal
IO_SET : in STD_ULOGIC := '0'; -- used to set I/O register to IO_IN value (synchronous!)
IO_IN : in STD_LOGIC_VECTOR(0 to 17) := o"000000"; -- bus for I/O devices to report values
RESET : in STD_LOGIC
);
end pdp1cpu;
 
architecture Behavioral of pdp1cpu is
subtype word is STD_LOGIC_VECTOR(0 to 17);
subtype opcode is std_logic_vector(0 to 5);
-- Formally the opcode is 5 bits; I've included the indirection bit.
 
signal MB: word; -- memory buffer
signal op: opcode := o"00"; -- current operation (user visible originally)
 
signal IOWAIT, HALT : boolean := false;
 
alias ib : std_logic is op(5); -- indirection bit
alias y : std_logic_vector(0 to 11) is MB(6 to 17); -- address/operand
 
-- operations - note that "load" here is OR, for some reason.
alias cli : std_logic is MB(6); -- clear IO
alias lat : std_logic is MB(7); -- load AC with Test.Switches
alias cma : std_logic is MB(8); -- complement AC
alias hlt : std_logic is MB(9); -- halt
alias cla : std_logic is MB(10); -- clear AC
alias lap : std_logic is MB(11); -- load AC from PC
alias flag_setto : std_logic is MB(14); -- set program flag(s) - value
alias flag_which : std_logic_vector(2 downto 0) is MB(15 to 17);
-- skip conditions
alias spi : std_logic is MB(7); -- Skip if Positive IO
alias szo : std_logic is MB(8); -- skip if zero OV
alias sza : std_logic is MB(9); -- skip if zero AC
alias spa : std_logic is MB(10); -- skip if positive AC
alias sma : std_logic is MB(11); -- skip if negative AC
alias szs : std_logic_vector(0 to 2) is MB(12 to 14); -- skip if Zero Switches
alias szf : std_logic_vector(0 to 2) is MB(15 to 17); -- skip if Zero Flags
-- Opcodes -- loading group
constant op_and : opcode := o"02"; -- AC&=M
constant op_ior : opcode := o"04"; -- AC|=M
constant op_xor : opcode := o"06"; -- AC^=M
constant op_add : opcode := o"40"; -- AC+=M
constant op_sub : opcode := o"42"; -- AC-=M
constant op_lac : opcode := o"20"; -- load AC
constant op_lio : opcode := o"22"; -- load IO
constant op_sad : opcode := o"50"; -- skip if AC/=M(y)
constant op_sas : opcode := o"52"; -- skip if AC=M(y)
-- storing group
constant op_dac : opcode := o"24"; -- store AC
constant op_dap : opcode := o"26"; -- deposit address part of AC
constant op_dip : opcode := o"30"; -- deposit instruction part -- missing in Java emulator
constant op_dio : opcode := o"32"; -- deposit IO
constant op_dzm : opcode := o"34"; -- deposit zero
-- jumping group
constant op_skip: opcode := o"64"; -- adds 1 to IP; SAD and SAS, load group, also do this
constant op_skipi: opcode := o"65"; -- as above, but inverts condition
constant op_jmp : opcode := o"60"; -- jump
constant op_jsp : opcode := o"62"; -- jump and save PC
constant op_cal : opcode := o"16"; -- call subroutine
constant op_jda : opcode := o"17"; -- jump and deposit AC
-- immediate group
constant op_rotshiftl: opcode := o"66"; -- rotate/shift (IB is direction)
constant op_rotshiftr: opcode := o"67";
constant op_law : opcode := o"70"; -- load accumulator immediate
constant op_lawm: opcode := o"71";
constant op_opr : opcode := o"76"; -- operate group
-- miscellaneous
constant op_idx : opcode := o"44"; -- index - AC=++M[y]
constant op_isp : opcode := o"46"; -- same, and skip if positive
-- constant op_mul : opcode := o"54"; -- full multiply (PDP-1C)
-- constant op_div : opcode := o"56"; -- full divide (PDP-1C)
constant op_mus : opcode := o"54"; -- multiply step (PDP-1B)
constant op_dis : opcode := o"56"; -- divide step (PDP-1B)
constant op_xct : opcode := o"10"; -- execute
constant op_iot : opcode := o"73"; -- I/O transfer group, ib is wait for completion
constant op_iot_nw : opcode := o"72";
 
-- cycletype tracks the memory cycle reason
type cycle_type is (load_instruction, load_indirect, load_data, store_data);
signal cycletype : cycle_type;
signal cycle : integer range 0 to 9 := 0; -- 10 cycles per memory access cycle
-- NOTE: rotshift relies on this range!
constant cycle_setup_read: integer := 0;
constant cycle_read: integer := 2; -- memory is over-registered
constant cycle_execute: integer := 3;
constant cycle_setup_write: integer := 5;
constant cycle_wrote: integer := 6; -- not actually used
constant cycle_skip: integer := 9;
 
COMPONENT onecomplement_adder
PORT(
A : IN std_logic_vector(0 to 17);
B : IN std_logic_vector(0 to 17);
CI : IN std_logic;
SUM : OUT std_logic_vector(0 to 17);
OV : OUT std_logic;
CSUM : OUT std_logic_vector(0 to 17)
);
END COMPONENT;
 
COMPONENT pdp1rotshift
PORT(
ac : IN std_logic_vector(0 to 17);
io : IN std_logic_vector(0 to 17);
right : IN std_logic;
shift : IN std_logic;
words : IN std_logic_vector(0 to 1);
acout : OUT std_logic_vector(0 to 17);
ioout : OUT std_logic_vector(0 to 17)
);
END COMPONENT;
signal rotshift_ac, rotshift_io: word;
signal rotshift_right, rotshift_shift: std_logic;
signal rotshift_words: std_logic_vector(0 to 1);
signal add_a, add_b, add_sum, add_csum, dis_term: word;
signal add_ci, add_ov: std_logic;
signal skipcond: std_logic; -- skip condition for op_skip
signal ac_eq_mb : boolean;
-- purpose: value of a sense switch if n valid, else '1'
function sense_or_one (
n : integer; -- which sense flag
sense_sw : std_logic_vector(1 to 6)) -- sense switches
return std_logic is
begin -- sense_or_one
for i in 1 to 6 loop
if n=i then
return sense_sw(n);
end if;
end loop; -- i
return '1';
end sense_or_one;
begin
AWAKE <= '0' when IOWAIT or RESET='1' or HALT else '1';
 
Inst_pdp1rotshift: pdp1rotshift PORT MAP(
ac => AC, -- shift operation is read from memory
io => IO,
right => rotshift_right,
shift => rotshift_shift,
words => rotshift_words,
acout => rotshift_ac,
ioout => rotshift_io
);
with op select
rotshift_right <= '1' when op_mus,
'0' when op_dis,
M_DO(5) when others;
with op select
rotshift_shift <= '1' when op_mus,
'-' when op_dis,
M_DO(6) when others;
with op select
rotshift_words <= "11" when op_mus,
"11" when op_dis,
M_DO(7 to 8) when others;
 
Inst_onecomplement_adder: onecomplement_adder PORT MAP(
A => add_a,
B => add_b,
CI => add_ci,
SUM => add_sum,
OV => add_ov,
CSUM => add_csum
);
-- we use this same adder for addition, subtraction, indexing and multiply/divide step
with io(17) select
dis_term <= not MB when '1',
MB when '0',
(others=>'-') when others;
with op select
add_a <= o"000001" when op_idx | op_isp,
AC when op_add|op_mus|op_dis,
(others=>'-') when others;
with op select
add_b <= MB when op_add|op_idx|op_isp|op_mus,
not MB when op_sub,
dis_term when op_dis,
(others=>'-') when others;
add_ci <= '1' when op=op_dis and io(17)='0' else
'0';
 
M_DI <= MB;
ac_eq_mb <= AC=MB;
 
skipcond <= '1' when (
(sza='1' and AC=o"00_0000") or -- accumulator zero
(spa='1' and AC(0)='0') or -- accumulator positive
(sma='1' and AC(0)='1') or -- accumulator negative
(szo='1' and OV='0') or -- zero overflow
(spi='1' and IO(0)='0') or -- positive IO register
(MB(12 to 14)=o"7" and sw_sense=o"00") or -- all sense switches 0
(sense_or_one(to_integer(unsigned(MB(12 to 14))),sw_sense)='0') or
false -- so all lines above end with or
) else '0';
 
process (CLK, RESET)
variable idx: unsigned(0 to 17);
variable tmp_w: word;
begin
if RESET='1' then -- asynchronous reset
AC <= (others => '0');
IO <= (others => '0');
PC <= o"0000";
OV <= '0';
PF <= (others => '0');
-- memory control
MW <= '0';
MA <= o"0000";
-- reset our internal state
op <= o"00";
IOWAIT <= false;
IOT <= (others => '0');
cycletype <= load_instruction;
cycle <= cycle_setup_read;
elsif rising_edge(CLK) then
if IO_set='1' then
IO <= IO_in;
end if;
IOT <= (others => '0'); -- ordinarily no io trigger pulse
-- Advance the cycle, unless we're halted
if IOWAIT then
if IODONE='1' then
IOWAIT <= false;
end if;
end if;
-- pause during setup_read cycle for halt or iowait
if not ((IOWAIT or HALT) and (cycle=cycle_setup_read)) then
if cycle=9 then
cycle <= 0;
else
cycle <= cycle+1;
end if;
-- common logic for signals
if cycle=cycle_setup_write then
MW <= '1';
else
MW <= '0';
end if;
if (op=op_rotshiftr or op=op_rotshiftl) then
case cycle is
when 9 => -- don't shift on cycle 9
when others =>
if MB(9+cycle)='1' then
AC <= rotshift_ac; -- perform rotate/shift instructions
if IO_set/='1' then
IO <= rotshift_io;
end if;
end if;
end case;
end if;
case cycle is
when cycle_read => -- have read something from memory
MB <= M_DO;
case cycletype is
when load_instruction => -- it's our next instruction
op <= M_DO(0 to 5);
if op/=op_xct then -- indirect execution
PC<=PC+1;
end if;
when load_indirect => -- completing an indirect instruction
ib <= M_DO(5); -- update indirection bit
when others => -- data access cycle
end case;
when cycle_skip =>
if ((op=op_skip or op=op_skipi) and (skipcond xor ib)='1') or
(op=op_isp and cycletype=store_data and AC(0)='0') or
(op=op_sas and cycletype=load_data and ac_eq_mb) or
(op=op_sad and cycletype=load_data and not ac_eq_mb) or
FALSE then -- increase PC an extra time
PC <= PC+1;
end if;
if (op=op_skip or op=op_skipi) and szo='1' then
OV <= '0'; -- clear overflow after checking it
end if;
when cycle_setup_read => -- set up the memory address
case cycletype is
when load_instruction|load_indirect =>
case (op) is
-- memory loading instructions - will execute after loading data
when op_sas|op_sad|op_lac|op_lio|op_and|op_xor|op_ior|op_add|
op_sub|op_idx|op_isp|op_mus|op_dis =>
cycletype <= load_data;
MA <= y;
when op_xct => -- load specified instruction, do not change PC
cycletype <= load_instruction;
MA <= y;
when op_dac|op_dap|op_dip|op_dio|op_dzm => -- deposit instructions
cycletype <= store_data;
MA <= y;
when op_jmp|op_jsp|op_cal|op_jda => -- jumping instructions
if op/=op_jmp then
AC(0) <= OV;
AC(1 to 5) <= (others => '0'); -- extended PC
AC(6 to 17) <= std_logic_vector(PC);
end if;
if op=op_cal or op=op_jda then
if op=op_cal then
PC <= o"0101";
MA <= o"0100";
else
PC <= unsigned(y)+1;
MA <= y;
end if;
cycletype <= store_data;
else
MA <= y;
PC <= unsigned(y);
cycletype <= load_instruction;
end if;
when op_skipi|op_rotshiftr|op_lawm|op_iot_nw =>
-- instructions with IB set, yet are immediate
MA <= std_logic_vector(PC);
cycletype <= load_instruction;
when others => -- most instructions are followed by the next instruction
if ib='1' then -- handle indirection bit
MA <= y;
cycletype <= load_indirect;
else
MA <= std_logic_vector(PC);
cycletype <= load_instruction;
end if;
end case; -- end of by-instruction memory setup
when others => -- have done data load/store
MA <= std_logic_vector(PC);
cycletype <= load_instruction;
end case;
when cycle_execute =>
-- execute common instructions - instr or operand has been read
case cycletype is
when load_instruction|load_indirect => -- new instr,
case op is
when op_law => -- load accumulator immediate
AC(0 to 5) <= (others => '0');
AC(6 to 17) <= y;
when op_lawm => -- load accumulator immediate negative
AC(0 to 5) <= (others => '1');
AC(6 to 17) <= not y;
when op_opr => -- operate group
if cli='1' and IO_set/='1' then IO <= o"00_0000"; end if;
if hlt='1' then HALT <= TRUE; end if; -- HALT
if cla='1' then
tmp_w := (others => '0');
else
tmp_w := AC;
end if;
if lat='1' then tmp_w := tmp_w or sw_testw; end if;
if lap='1' then -- or AC with PC and OV
tmp_w(6 to 17) := tmp_w(6 to 17) or std_logic_vector(PC);
tmp_w(0) := tmp_w(0) or OV;
end if;
if cma='1' then tmp_w := not tmp_w; end if;
AC <= tmp_w;
for j in 1 to 6 loop
if unsigned(flag_which)=j or unsigned(flag_which)=7 then
PF(j) <= flag_setto; -- set or clear program flags
end if;
end loop;
when op_rotshiftl|op_rotshiftr =>
-- handled in a separate block
when op_skip|op_skipi =>
-- inverted skip is not documented in 1960 manual.
-- it does occur in PDP-1B emulator and 1963 manual.
-- all skips are handled in skip phase, for no
-- real reason
when op_iot|op_iot_nw => -- I/O transfer
-- Java emulator Spacewar! binary supports:
-- typewriter sequence break input,
-- display on ordinary display (7),
-- reading of controls using undocumented device 11,
-- should load 4 bits of button controls in low and
-- high ends of the word
-- and does display 3 display commands (disabled point?).
-- It uses nowait+pulse, nowait, and wait+noop modes, so waiting
-- has to be implemented.
IODOPULSE <= MB(5) xor MB(6); -- generate an IODONE for this event
IOWAIT <= IB='1';
IOT(to_integer(unsigned(MB(12 to 17)))) <= '1';
when others =>
if ib='1' then -- likely turns into a valid op once IB is cleared
cycletype <= load_indirect;
end if;
end case; -- end of instruction check in execute phase
when load_data => -- loaded data for loading instruction
case (op) is
when op_sas|op_sad => -- handled in skip phase
when op_lac =>
AC <= M_DO;
when op_idx|op_isp =>
AC <= add_sum;
MB <= add_sum;
when op_lio =>
if IO_set/='1' then
IO <= MB;
end if;
when op_and =>
AC <= AC and MB;
when op_xor =>
AC <= AC xor MB;
when op_ior =>
AC <= AC or MB;
when op_add =>
AC <= add_csum; -- no negative 0
OV <= OV or add_ov;
when op_sub =>
AC <= add_sum;
OV <= OV or add_ov;
-- Multiply Step and Divide Step are the same opcode as Multiply and Divide.
-- There's no reasonable way for the CPU to determine which a program wants.
-- when op_mul => -- multiply originally takes 3-5 cycles. this one takes 2.
-- tmp_w := AC;
-- tmp_w2 := M_DO;
-- if tmp_w(0)='1' then tmp_w:=not tmp_w; end if;
-- if tmp_w2(0)='1' then tmp_w2:=not tmp_w2; end if;
-- product := tmp_w(1 to 17)*tmp_w2(1 to 17);
-- if AC(0)/=M_DO(0) then
-- product:=not product; -- preserve sign
-- AC(0)<='1';
-- IO(0)<='1';
-- else
-- AC(0)<='0';
-- IO(0)<='0';
-- end if;
-- AC(1 to 17)<=product(0 to 16);
-- IO(1 to 17)<=product(17 to 33);
when op_mus => -- PDP-1B multiply step
if IO(17)='1' then
AC <= add_csum;
end if;
-- continued in next cycle
when op_dis => -- PDP-1B divide step
AC <= rotshift_ac;
IO(0 to 16) <= rotshift_io(0 to 16);
IO(17) <= not AC(0);
-- continued in next cycle
when others =>
-- can't happen, see cases leading to load_data.
end case; -- end of load ops, execute cycle
when store_data =>
case op is
when op_dac =>
MB <= AC;
when op_dap =>
--MB(0 to 5) <= MB(0 to 5);
MB(6 to 17) <= AC(6 to 17);
when op_dip =>
MB(0 to 5) <= AC(0 to 5);
--MB(6 to 17) <= MB(6 to 17);
when op_dio =>
MB <= IO;
when op_dzm =>
MB <= o"00_0000";
when others => -- others should not occur
end case;
end case; -- end of cycletype cases for execute cycle
-- FIXME more to fix here
when cycle_execute+1 =>
case op is -- multiply, divide and I/O use two stages
when op_mus =>
AC <= rotshift_ac;
if IO_set/='1' then
IO <= rotshift_io;
end if;
when op_dis =>
AC <= add_csum;
when others => -- note: rotshift uses 9 cycles
end case;
when others =>
end case;
end if;
end if;
end process;
end Behavioral;
 
/rtl/vhdl/vgatest.vhd
0,0 → 1,112
--------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 20:11:59 02/13/2011
-- Design Name:
-- Module Name: /home/yann/fpga/work/pdp1/vgatest.vhd
-- Project Name: pdp1-3
-- Target Device:
-- Tool versions:
-- Description:
--
-- VHDL Test Bench Created by ISE for module: vga
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes:
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test. Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
ENTITY vgatest IS
END vgatest;
ARCHITECTURE behavior OF vgatest IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT vga
PORT(
VGA_R : OUT std_logic_vector(3 downto 0);
VGA_G : OUT std_logic_vector(3 downto 0);
VGA_B : OUT std_logic_vector(3 downto 0);
VGA_HSYNC : OUT std_logic;
VGA_VSYNC : OUT std_logic;
CLK_50M : IN std_logic;
CLK_133M33 : IN std_logic
);
END COMPONENT;
 
--Inputs
signal CLK_50M : std_logic := '0';
signal CLK_133M33 : std_logic := '0';
 
--Outputs
signal VGA_R : std_logic_vector(3 downto 0);
signal VGA_G : std_logic_vector(3 downto 0);
signal VGA_B : std_logic_vector(3 downto 0);
signal VGA_HSYNC : std_logic;
signal VGA_VSYNC : std_logic;
 
-- Clock period definitions
constant CLK_50M_period : time := 20ns;
constant CLK_133M33_period : time := 7.5ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: vga PORT MAP (
VGA_R => VGA_R,
VGA_G => VGA_G,
VGA_B => VGA_B,
VGA_HSYNC => VGA_HSYNC,
VGA_VSYNC => VGA_VSYNC,
CLK_50M => CLK_50M,
CLK_133M33 => CLK_133M33
);
 
-- Clock process definitions
CLK_50M_process :process
begin
CLK_50M <= '0';
wait for CLK_50M_period/2;
CLK_50M <= '1';
wait for CLK_50M_period/2;
end process;
CLK_133M33_process :process
begin
CLK_133M33 <= '0';
wait for CLK_133M33_period/2;
CLK_133M33 <= '1';
wait for CLK_133M33_period/2;
end process;
 
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100ms.
wait for 100ms;
 
wait for CLK_50M_period*10;
 
-- insert stimulus here
 
wait;
end process;
 
END;
/rtl/vhdl/vga.vhd
0,0 → 1,283
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 22:05:52 11/22/2009
-- Design Name:
-- Module Name: top - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;
 
entity vga is
Port ( VGA_R : out STD_LOGIC_VECTOR (3 downto 0);
VGA_G : out STD_LOGIC_VECTOR (3 downto 0);
VGA_B : out STD_LOGIC_VECTOR (3 downto 0);
VGA_HSYNC : out STD_LOGIC := '0';
VGA_VSYNC : out STD_LOGIC := '0';
CLK_50M : in STD_LOGIC;
CLK_133M33 : in STD_LOGIC);
end vga;
 
architecture Behavioral of vga is
signal VGA_CLK : std_logic;
 
-- displayed stuff
signal cell : std_logic := '1';
signal fbwa, fbra : integer range 0 to 2048-1;
signal fbwe : boolean := false;
signal fbwd, fbrd : std_logic;
type linebuffer is array (0 to 2048-1) of std_logic;
signal pixels : linebuffer;
 
type modeline is record
pixelclock : real; -- calculations for the DCM need to be done by hand
hdisp : positive;
hsyncstart : positive;
hsyncend : positive;
htotal : positive;
vdisp : positive;
vsyncstart : positive;
vsyncend : positive;
vtotal : positive;
hpulse : std_logic; -- pulse level (i.e. '0' for -hsync, or '1' for +hsync)
vpulse : std_logic;
end record modeline;
 
-- Modelines taken from http://www.mythtv.org/wiki/Modeline_Database
 
-- 640x480 VGA -- all -vsync -hsync
constant VGA60: modeline := (25.18, 640, 656, 752, 800, 480, 490, 492, 525, '0', '0'); -- pitifully, 25 is as close as I get.
constant VGA75: modeline := (31.50, 640, 656, 720, 840, 480, 481, 484, 500, '0', '0'); -- 50/27*17 ~ 31.48
-- from VESA modepool
constant SXGA60: modeline := (108.00, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, '1', '1'); -- 108 ~ 50/6*13 ~ 133.33/21*17
-- 1920x1200@60Hz nvidia mode pool
constant WUXGA60: modeline := (193.16, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, '1', '1'); -- 193.16 ~ 50/7*27 ~ 133.33/11*16
 
constant mode: modeline := SXGA60;
alias pixclksrc is CLK_133M33;
constant pixclkperiod: real := 7.5;
constant pixclkdiv: positive := 21;
constant pixclkmul: positive := 17;
 
-- constant mode: modeline := VGA60;
-- alias pixclksrc is CLK_50M;
-- constant pixclkperiod: real := 20.0;
-- constant pixclkdiv: positive := 4;
-- constant pixclkmul: positive := 2;
 
signal column: integer range 0 to mode.htotal-1 := 0;
signal row: integer range 0 to mode.vtotal-1 := 0;
signal vblank, hblank, linestart, framestart : boolean := false;
begin
DCM_1 : DCM_SP
generic map ( -- synthesize 193.33MHz; we're a bit off.
--CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
-- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
CLKFX_DIVIDE => pixclkdiv, -- Can be any interger from 1 to 32
CLKFX_MULTIPLY => pixclkmul, -- Can be any integer from 1 to 32
--CLKIN_DIVIDE_BY_2 => FALSE, -- TRUE/FALSE to enable CLKIN divide by two feature
CLKIN_PERIOD => pixclkperiod,--20.0, -- Specify period of input clock
--CLKOUT_PHASE_SHIFT => "NONE", -- Specify phase shift of "NONE", "FIXED" or "VARIABLE"
CLK_FEEDBACK => "NONE", -- Specify clock feedback of "NONE", "1X" or "2X"
--DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- "SOURCE_SYNCHRONOUS", "SYSTEM_SYNCHRONOUS" or
-- an integer from 0 to 15
--DLL_FREQUENCY_MODE => "LOW", -- "HIGH" or "LOW" frequency mode for DLL
DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE
PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255
STARTUP_WAIT => TRUE) -- Delay configuration DONE until DCM_SP LOCK, TRUE/FALSE
port map (
--CLK0 => open, -- 0 degree DCM CLK ouptput
--CLK180 => open, -- 180 degree DCM CLK output
--CLK270 => open, -- 270 degree DCM CLK output
--CLK2X => open, -- 2X DCM CLK output
--CLK2X180 => open, -- 2X, 180 degree DCM CLK out
--CLK90 => open, -- 90 degree DCM CLK output
--CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE)
CLKFX => VGA_CLK, -- DCM CLK synthesis out (M/D)
--CLKFX180 => open, -- 180 degree CLK synthesis out
--LOCKED => AWAKE, -- DCM LOCK status output
--PSDONE => open, -- Dynamic phase adjust done output
--STATUS => open, -- 8-bit DCM status bits output
--CLKFB => open, -- DCM clock feedback
CLKIN => pixclksrc, -- Clock input (from IBUFG, BUFG or DCM)
--PSCLK => open, -- Dynamic phase adjust clock input
--PSEN => open, -- Dynamic phase adjust enable input
--PSINCDEC => open, -- Dynamic phase adjust increment/decrement
RST => '0' -- DCM asynchronous reset input
);
 
sync: process (VGA_CLK)
begin
if rising_edge(VGA_CLK) then
linestart <= false;
if column=mode.htotal-1 then
column <= 0;
else
column <= column+1;
end if;
case column is
when mode.hdisp-1 =>
hblank <= true;
when mode.hsyncstart =>
VGA_HSYNC <= mode.hpulse;
framestart <= false;
case row is
when mode.vsyncstart =>
VGA_VSYNC <= mode.vpulse;
when mode.vsyncend =>
VGA_VSYNC <= not mode.vpulse;
when mode.vdisp-1 =>
vblank <= true;
when mode.vtotal-1 =>
vblank <= false;
framestart <= true;
when others =>
null;
end case;
if row=mode.vtotal-1 then
row <= 0;
else
row <= row+1;
end if;
when mode.hsyncend =>
VGA_HSYNC <= not mode.hpulse;
when mode.htotal-1 =>
linestart <= true;
hblank <= false;
when others =>
null;
end case;
end if;
end process;
memwr: process (VGA_CLK)
begin -- process memwr
if VGA_CLK'event and VGA_CLK = '1' then -- rising clock edge
if fbwe then
pixels(fbwa) <= fbwd;
end if;
end if;
end process memwr;
memrd: process (VGA_CLK)
begin
if rising_edge(VGA_CLK) then
fbrd <= pixels(fbra);
end if;
end process memrd;
 
-- purpose: calculates upcoming pixels
-- type : sequential
-- inputs : VGA_CLK, vblank, newline
-- outputs: cell
wolfram: process (VGA_CLK)
variable rule : unsigned(7 downto 0) := to_unsigned(30,8);
variable x : integer range 0 to 2048-1 := 0;
variable x0 : integer range 0 to 4 := 0;
constant init : unsigned(0 to 4) := "00101";
variable prev : unsigned(0 to 2) := "000";
begin -- process
if rising_edge(VGA_CLK) then
fbwe<=true;
if linestart then
x:=0;
x0:=0;
elsif x/=2048-1 then
x:=x+1;
end if;
fbwa<=x;
fbra<=x+4;
if framestart then
-- Wolfram rules:
-- the three prior cells (left, self, right) are read as a binary number
-- the rule number is converted to binary; each bit position corresponds
-- to a configuration. thus, rule 34 is
-- 00100010 - only configuration 1 and 5 lead to state 1.
-- that's 001 and 101, so the rule can only grow in one diagonal direction
cell <= '0';
fbwd <= '0';
-- initial conditions for different rules
case to_integer(rule) is
when 34 =>
fbwd<=init(x0);
cell <= init(x0);
when others =>
if x=mode.hdisp/2 then
fbwd <= '1';
cell <= '1';
end if;
end case;
if x0=4 then
x0:=0;
else
x0:=x0+1;
end if;
prev:="0"&init(0 to 1); -- first two pixels will be strange :/
else
fbwd<=rule(to_integer(prev));
cell<=rule(to_integer(prev));
prev(0 to 1):=prev(1 to 2);
if x<mode.hdisp-1 then
prev(2):=fbrd;
else
prev(2):='1';
end if;
end if;
end if;
end process wolfram;
-- purpose: output a signal to the VGA port
-- type : sequential
-- inputs : VGA_CLK
-- outputs: VGA_R, VGA_G, VGA_B, VGA_HSYNC, VGA_VSYNC
vgaout: process (VGA_CLK)
variable vdisparea : boolean := false;
begin -- process vgaout
if rising_edge(VGA_CLK) then
-- pixel value output
if not (hblank or vblank) then
case column is
when 0|mode.hdisp-1 =>
VGA_R <= (others => '1');
VGA_G <= (others => '1');
VGA_B <= (others => '1');
when others =>
case row is
when 0|mode.vdisp-1 =>
VGA_R <= (others => '1');
VGA_G <= (others => '1');
VGA_B <= (others => '1');
when others =>
VGA_R <= (others => cell);
VGA_G <= (others => cell);
VGA_B <= (others => cell);
end case;
end case;
else
VGA_R <= (others => '0');
VGA_G <= (others => '0');
VGA_B <= (others => '0');
end if;
end if;
end process vgaout;
 
end Behavioral;
 
/rtl/vhdl/clockdiv.vhd
0,0 → 1,98
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 11:53:58 02/09/2009
-- Design Name:
-- Module Name: clockdiv - Behavioral
-- Project Name:
-- Target Devices:
-- Tool versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
 
---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;
 
entity clockdiv is
Port ( CLK_50M : in STD_LOGIC;
CLK : out STD_LOGIC; -- 2MHz
-- CLK_180 : out std_logic;
LOCKED : out STD_LOGIC);
end clockdiv;
 
architecture Behavioral of clockdiv is
signal CLK_out : std_logic := '0';
begin
LOCKED <= '1';
process (CLK_50M)
-- 50M/25=2M.. should use DCM.
constant top : integer := 25/2-1;
variable count : integer range 0 to top := 0;
begin
if rising_edge(CLK_50M) then
if count=top then
CLK_out <= not CLK_out;
count := 0;
else
count := count+1;
end if;
end if;
end process;
 
CLK <= CLK_out;
 
-- DCM_SP: Digital Clock Manager Circuit
-- Spartan-3E/3A (Spartan 3 can't output this low frequency)
-- Xilinx HDL Language Template, version 10.1.3
 
-- DCM_SP_inst : DCM_SP
-- generic map (
-- CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
-- -- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
-- CLKFX_DIVIDE => 25, -- Can be any interger from 1 to 32
-- CLKFX_MULTIPLY => 4, -- Can be any integer from 2 to 32
-- CLKIN_DIVIDE_BY_2 => false, -- TRUE/FALSE to enable CLKIN divide by two feature
-- CLKIN_PERIOD => 200.0, -- Specify period of input clock in ns
-- CLKOUT_PHASE_SHIFT => "NONE", -- Specify phase shift of "NONE", "FIXED" or "VARIABLE"
-- CLK_FEEDBACK => "NONE", -- Specify clock feedback of "NONE", "1X" or "2X"
-- DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- "SOURCE_SYNCHRONOUS", "SYSTEM_SYNCHRONOUS" or
-- -- an integer from 0 to 15
-- DLL_FREQUENCY_MODE => "LOW", -- "HIGH" or "LOW" frequency mode for DLL
-- DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE
-- PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 255
-- STARTUP_WAIT => TRUE) -- Delay configuration DONE until DCM_SP LOCK, TRUE/FALSE
-- port map (
---- CLK0 => CLK_2X, -- 0 degree DCM CLK ouptput
---- CLK180 => CLK180, -- 180 degree DCM CLK output
---- CLK270 => CLK270, -- 270 degree DCM CLK output
---- CLK2X => CLK_400k, -- 2X DCM CLK output
---- CLK2X180 => CLK2X180, -- 2X, 180 degree DCM CLK out
---- CLK90 => CLK90, -- 90 degree DCM CLK output
---- CLKDV => CLK_2X, -- Divided DCM CLK out (CLKDV_DIVIDE)
-- CLKFX => CLK, -- DCM CLK synthesis out (M/D)
---- CLKFX180 => CLK_180, -- 180 degree CLK synthesis out
-- LOCKED => LOCKED, -- DCM LOCK status output
---- PSDONE => PSDONE, -- Dynamic phase adjust done output
---- STATUS => STATUS, -- 8-bit DCM status bits output
---- CLKFB => CLK, -- DCM clock feedback
-- CLKIN => CLK_out -- Clock input (from IBUFG, BUFG or DCM)
---- PSCLK => PSCLK, -- Dynamic phase adjust clock input
---- PSEN => PSEN, -- Dynamic phase adjust enable input
---- PSINCDEC => PSINCDEC, -- Dynamic phase adjust increment/decrement
---- RST => RST -- DCM asynchronous reset input
-- );
end Behavioral;
/sw/readin.mac
0,0 → 1,14
READIN
0/
jmp loop
7700/
loop, rpb
dio instr
lac instr
dap diow
sad diow
rpb
instr, hlt
jmp loop
diow, dio
start loop
/sw/loader-code.txt
0,0 → 1,51
loader as read in papertapeImages/20060517/musicPlayingProgram.bin
 
origin 7751
7751 73_0002 rpb read paper binary
7752 32_7760 dio 7760 deposit IO in 7760
7753 10_7760 xct 7760 execute recently read instruction
7754 32_7776 dio 7776
7755 73_0002 rpb
7756 32_7777 dio 7777
7757 73_0002 rpb
7760 60_1411 jmp 1411 jump to 1411 (overwritten by 7752!) -- holds DIO/write pointer
7761 21_7760 lac [7760] load ac from wherever 7760 points \
7762 40_7776 add 7776 add value from 7776 to AC } *7776 += *7760
7763 24_7776 dac 7776 save AC there /
7764 44_7760 idx 7760 AC <- ++*7760
7765 52_7777 sas 7777 skip if AC=*7777
7766 60_7757 jmp 7757 jump back to 7757 if *7760!=*7777
7767 20_7776 lac 7776 AC <- *7776
7770 40_7777 add 7777 AC += *7777
7771 73_0002 rpb
7772 32_7776 dio 7776
7773 52_7776 sas 7776 skip if AC=*7776
7774 76_0400 hlt halt if checksums didn't match?
7775 60_7751 jmp 7751 restart loader (executing the next tape instruction)
jumps to entry point 7751 after loading that code
 
from this we gather:
first word will be DIO origin, where origin is the first address the program is loaded to
this instruction will be stored at write pointer (7760), 7776 (checksum in progress) and origin
second word is deposited in 7777; this is DIO to the end address (first address NOT written)
third word etc is written at origin and added to checksum 7776 until write pointer=end address
we've now reached 7767
AC is loaded with end address plus checksum thus far, another word is read and deposited as checksum
if calculated checksum in AC does not match this newly read checksum at end, halt
otherwise, start loading all over again
 
this allows a block format, where each block is:
DIO start
DIO end
end-start data words
checksum
 
Finally, as the first word always executes, a jump instruction can start the program.
So, in papertapeImages/20060517/musicPlayingProgram.bin the program blocks are:
0003-0100 checksum 716574
0100-0200 checksum 623702 (assuming from here on 000000s are block boundaries)
0200-0300
0300-0400
0400-0500
0500-0546
jump to 0404, the entry point of the program

powered by: WebSVN 2.1.0

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