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 |