1
0
mirror of synced 2026-03-28 10:42:59 +00:00
This commit is contained in:
brad
2010-04-02 12:30:59 +00:00
parent 0d637dea36
commit 70280dcf1b
3 changed files with 1081 additions and 0 deletions

459
rtl/pdp8_io.v Normal file
View File

@@ -0,0 +1,459 @@
// PDP-8 i/o
// Based on descriptions in "Computer Engineering"
// Dev 2006 Brad Parker brad@heeltoe.com
// Revamp 2009 Brad Parker brad@heeltoe.com
/*
iot's touched by focal
6022 PCF
6203 CDF CIF 00
6402 PT08
6412
6422
6432
6442
6452
6462
6472
6764 DECTAPE
6772
*/
/*
RF08
7750 word count
7751 current address
2048 words/track
660x
661x
662x
664x
6601 DCMA Generates System Clear Pulse (SCLP) at IOP time 1.
Clears disk memory eaddress(DMA), Parity Eror Flag (PEF),
Data Request Late Flag (DRL), and sets logic to
initial state for read or write. Does not clear
interrupt enable or extended address register.
6603 DMAR Generate SCLP at IOP time 1. At IOP time 2, loads DMA
with AC and clears AC. Read continues for number words
in WC register (7750)
6605 DMAW Generate SCLP at IOP time 1. At IOP time 4, loads DMA
with AC and clears AC. When the disk word address is located
writing begins, disk address is incremented for each
word written
6611 DCIM clears disk interrupt enable and the extended address
registers at IOP time 1.
6612 DSAC At IOP time 2, skip if Address Confirmed (ADC) set indicating
the DMA address and disk word address compare. AC is then
cleared.
6615 DIML At IOP time 1, clear interrupt enable and memory address
extension registers. At IOP time 4, load interrupt enable
and memory address extension register with AC, clear AC.
6616 DIMA Clear ??? at IOP time 2. At IOP time 4 load AC with status
register.
6621 DFSE skip on error skip if DRL, PER WLS or NXD set
6622 ??? skip if data completion DCF set
6623 DISK skip on error or data completion; enabled at IOP 2
6626 DMAC clear ac at IOP time 2 load AC from DMA at IOP time 4.
6641 DCXA Clears EMA
6643 DXAL Clears and loads EMA from AC. At IOP time 1, clear EMA, at
IOP time 2, load EMA with AC. Clear AC
6645 DXAC Clears AC and loads EMA into AC
6646 DMMT Maintenance
uses 3 cycle data break
ac 7:0, ac 11:0 => 20 bit {EMA,DMA}
20 bit {EMA,DMA} = { disk-select, track-select 6:0, word-select 11:0 }
status
*/
// EIE = WLS | DRL | NXD | PER
/*
3 cycle data break
1. An address is read from the device to indicate the location of the
word count register. This location specifies the number of words in
the block yet to be transferred. The address is always the same for a
given device.
2. The content of the specficified word count register is read from
memory and incremented by one. To transfer a block of n words, the
word count is set to -n during the programmed initialization of the
device. When this register is incremented to 0, a pulse is sent to
the device to terminate the transfer.
3. The location after the word count register contains the current
address register for the device transfer. The content of thise
register is set to 1 less than the location to be affected by the next
transfer. To transfer a block beginning at location A, the register is
originally set to A-1.
4. The content of the current address register is incremented by 1
and then used to specify the location affected by the transfer.
After the transfer of information has been accomplished through the
data break factility, input data (or new output data) is processed,
usually through the program interrupt facility. An interrupt is
requested when the data transfer is completed and the service routine
will process the information.
xxx:
if (databreak_req)
begin
databreak_done <= 0;
next_state <= DB0;
end
// read word count
DB0:
ma <= wc-address;
next_state <= DB1;
// write word count - 1
DB1:
mb <= memory_bus - 1;
ram_we_n <= 0;
if (mb == 0) databreak_done <= 1;
next_state <= DB2;
// finish write
DB2:
ram_we_n <= 1;
next_state <= DB3;
// read current address
DB3:
ma <= ma | 1;
next_state <= DB4;
// write current address - 1
DB4:
mb <= memory_bus + 1;
ram_we_n <= 0;
next_state <= DB5;
// finish write
DB5:
ram_we_n <= 1;
next_state <= DB6;
// set up read/write address
DB6:
ma <= mb;
next_state <= DB7;
// do read or start write
DB7:
if (databreak_write)
begin
data <= memory_bus;
next_state <= F0;
end
else
begin
mb <= data;
ram_we_n <= 0;
next_state <= DB8;
end
// finish write
DB8:
ram_we_n < = 1;
next_state <= F0;
*/
module pdp8_io(clk, reset, iot, state, mb,
io_data_in, io_data_out, io_select,
io_data_avail, io_interrupt, io_skip);
input clk, reset, iot;
input [11:0] io_data_in;
input [11:0] mb;
input [3:0] state;
input [5:0] io_select;
output reg [11:0] io_data_out;
output reg io_data_avail;
output reg io_interrupt;
output reg io_skip;
reg rx_int, tx_int;
reg [12:0] rx_data, tx_data;
reg tx_delaying;
integer tx_delay;
parameter F0 = 4'b0000;
parameter F1 = 4'b0001;
parameter F2 = 4'b0010;
parameter F3 = 4'b0011;
parameter D0 = 4'b0100;
parameter D1 = 4'b0101;
parameter D2 = 4'b0110;
parameter D3 = 4'b0111;
parameter E0 = 4'b1000;
parameter E1 = 4'b1001;
parameter E2 = 4'b1010;
parameter E3 = 4'b1011;
parameter PCA_bit = 12'o4000; // photocell status
parameter DRE_bit = 12'o2000; // data req enable
parameter WLS_bit = 12'o1000; // write lock status
parameter EIE_bit = 12'o0400; // error int enable
parameter PIE_bit = 12'o0200; // photocell int enb
parameter CIE_bit = 12'o0100; // done int enable
parameter MEX_bit = 12'o0070; // memory extension
parameter DRL_bit = 12'o0004; // data late error
parameter NXD_bit = 12'o0002; // non-existent disk
parameter PER_bit = 12'o0001; // parity error
wire ADC;
wire DCF;
reg [11:0] DMA;
reg [7:0] EMA;
reg PEF;
reg rf08_rw;
reg rf08_start_io;
reg CIE, DRE, DRL, EIE, MEX, NXD, PCA, PER, PIE, WLS;
assign DCF = 1'b0;
assign ADC = DMA == /*DWA??*/0;
// combinatorial
always @(state or
rx_int or tx_int or
ADC or DRL or PER or WLS or NXD or DCF)
begin
// sampled during f1
io_skip = 0;
io_data_out = io_data_in;
io_data_avail = 1;
if (state == F1 && iot)
case (io_select)
6'o03:
begin
if (mb[0])
io_skip = rx_int;
if (mb[2])
io_data_out = rx_data;
end
6'o04:
if (mb[0])
begin
io_skip = tx_int;
$display("xxx io_skip %b", tx_int);
end
6'o60:
case (mb[2:0])
3'o03: // DMAR
io_data_out = 0;
3'o03: // DMAW
io_data_out = 0;
endcase
6'o61:
case (mb[2:0])
3'o2: // DSAC
if (ADC)
begin
io_skip = 1;
io_data_out = 0;
end
3'o6: // DIMA
io_data_out = { PCA, DRE,WLS,EIE, PIE,CIE,MEX, DRL,NXD,PER };
3'o5: // DIML
io_data_out = 0;
endcase
6'o62:
case (mb[2:0])
3'o1: // DFSE
if (DRL | PER | WLS | NXD)
io_skip = 1;
3'o2: // ???
if (DCF)
io_skip = 1;
3'o3: // DISK
if (DRL | PER | WLS | NXD | DCF)
io_skip = 1;
3'o6: // DMAC
io_data_out = DMA;
endcase
6'o64:
case (mb[2:0])
3: // DXAL
io_data_out = 0;
5: // DXAC
io_data_out = EMA;
endcase
endcase // case(io_select)
end
//
// registers
//
always @(posedge clk)
if (reset)
begin
end
else
case (state)
F0:
begin
// sampled during f1
io_data_avail <= 0;
if (iot)
case (io_select)
6'o60: // DCMA
if (mb[2:0] == 3'b001)
begin
DMA <= 0;
PEF <= 0;
DRL <= 0;
end
6'o61:
case (mb[2:0])
3'o1: // DCIM
begin
CIE <= 0;
EMA <= 0;
end
3'o2: // DSAC
begin
end
3'o5: // DIML
begin
CIE <= io_data_in[8];
EMA <= io_data_in[7:0];
end
endcase // case(mb[2:0])
endcase
end
F1:
if (iot)
begin
$display("iot2 %t, state %b, mb %o, io_select %o",
$time, state, mb, io_select);
case (io_select)
6'o03:
begin
if (mb[1])
rx_int <= 0;
end
6'o04:
begin
if (mb[0])
begin
end
if (mb[1])
begin
tx_int <= 0;
$display("xxx reset tx_int");
end
if (mb[2])
begin
tx_data <= io_data_in;
$display("xxx tx_data %o", io_data_in);
tx_int <= 1;
tx_delaying <= 1;
tx_delay <= 98;
$display("xxx set tx_int");
end
end // case: 6'o04
6'o60:
case (mb[2:0])
3'o03: // DMAR
begin
// clear ac
DMA <= io_data_in;
rf08_start_io <= 1;
rf08_rw <= 0;
end
3'o03: // DMAW
begin
// clear ac
DMA <= io_data_in;
rf08_start_io <= 1;
rf08_rw <= 1;
end
endcase // case(mb[2:0])
6'o64:
case (mb[2:0])
1: // DCXA
EMA <= 0;
3: // DXAL
// clear ac
EMA <= io_data_in;
endcase
endcase
end // if (iot)
F2:
begin
if (io_interrupt)
$display("iot2 %t, reset io_interrupt", $time);
// sampled during f0
io_interrupt <= 0;
end
F3:
begin
if (tx_delaying)
begin
tx_delay <= tx_delay - 1;
//$display("xxx delay %d", tx_delay);
if (tx_delay == 0)
begin
$display("iot2 %t, xxx set io_interrupt", $time);
tx_delaying <= 0;
io_interrupt <= 1;
end
end
end
endcase // case(state)
endmodule

484
rtl/pdp8_rf.v Normal file
View File

@@ -0,0 +1,484 @@
/*
RF08
2048 words/track
128 tracks
mapped to IDE drive;
2048 x 12 bits -> 2048 x 16 bits = 8 blocks of 512 bytes
each track is 8 blocks
each disk is (128 * 8) = 1024 blocks
ide_block = (track * 8) + (word / 256)
ide_block_index = word % 256
ema bits 7 & 8 select which rs08 disk
ema bits 6 - 0 select disk head (track #)
dma contains lower disk word address
writes to dma trigger; adc is asserted after match w/disk
1 111
98765432109876543210
wwwwwwwwwww
-------------
memory:
7750 word count
7751 current address
iot:
660x
661x
662x
664x
6601 DCMA Generates System Clear Pulse (SCLP) at IOP time 1.
Clears disk memory eaddress(DMA), Parity Eror Flag (PEF),
Data Request Late Flag (DRL), and sets logic to
initial state for read or write. Does not clear
interrupt enable or extended address register.
6603 DMAR Generate SCLP at IOP time 1. At IOP time 2, loads DMA
with AC and clears AC. Read continues for number words
in WC register (7750)
6605 DMAW Generate SCLP at IOP time 1. At IOP time 4, loads DMA
with AC and clears AC. When the disk word address is located
writing begins, disk address is incremented for each
word written
6611 DCIM clears disk interrupt enable and the extended address
registers at IOP time 1.
6612 DSAC At IOP time 2, skip if Address Confirmed (ADC) set indicating
the DMA address and disk word address compare. AC is then
cleared.
6615 DIML At IOP time 1, clear interrupt enable and memory address
extension registers. At IOP time 4, load interrupt enable
and memory address extension register with AC, clear AC.
6616 DIMA Clear ??? at IOP time 2. At IOP time 4 load AC with status
register.
6621 DFSE skip on error skip if DRL, PER WLS or NXD set
6622 ??? skip if data completion DCF set
6623 DISK skip on error or data completion; enabled at IOP 2
6626 DMAC clear ac at IOP time 2 load AC from DMA at IOP time 4.
6641 DCXA Clears EMA
6643 DXAL Clears and loads EMA from AC. At IOP time 1, clear EMA, at
IOP time 2, load EMA with AC. Clear AC
6645 DXAC Clears AC and loads EMA into AC
6646 DMMT Maintenance
uses 3 cycle data break
ac 7:0, ac 11:0 => 20 bit {EMA,DMA}
20 bit {EMA,DMA} = { disk-select, track-select 6:0, word-select 11:0 }
status
*/
// EIE = WLS | DRL | NXD | PER
/*
3 cycle data break
1. An address is read from the device to indicate the location of the
word count register. This location specifies the number of words in
the block yet to be transferred. The address is always the same for a
given device.
2. The content of the specficified word count register is read from
memory and incremented by one. To transfer a block of n words, the
word count is set to -n during the programmed initialization of the
device. When this register is incremented to 0, a pulse is sent to
the device to terminate the transfer.
3. The location after the word count register contains the current
address register for the device transfer. The content of this
register is set to 1 less than the location to be affected by the next
transfer. To transfer a block beginning at location A, the register is
originally set to A-1.
4. The content of the current address register is incremented by 1
and then used to specify the location affected by the transfer.
After the transfer of information has been accomplished through the
data break factility, input data (or new output data) is processed,
usually through the program interrupt facility. An interrupt is
requested when the data transfer is completed and the service routine
will process the information.
xxx:
if (databreak_req)
begin
databreak_done <= 0;
next_state <= DB0;
end
----------- ----------- ----------- -----------
DISK STATE MACHINE:
// setup
wire [8:0] track;
wire [11:0] ide_block;
wire [7:0] ide_block_index;
track = {ema[7:0], dma[11]};
ide_block = {1'b0, track, 3'b0} + {8'b0, dma[11:8]}
ide_block_index = dma[7:0];
read_block:
read block
start dma
write block
if dma-stopped-at-end-of-block
goto read_block
// read block into buffer
DR0:
read[
if (db_eob)
dr_next_state =
----------- ----------- ----------- -----------
DMA STATE MACHINE:
wire [7:0] disk_buffer_index;
wire databreak_done_req;
wire databreak_notdone_req;
reg databreak_done;
always @(posedge clk)
if (databreak_done_req)
databreak_done <= 1;
else
if (databreak_notdone_req)
databreak_done <= 0;
always @(posedge clk)
if (db_state == DB9)
begin
ema <= new_da[18:11];
dma <= new_da[10:0];
end
db_done = 0;
db_eob = 0;
ram_write = 0;
databreak_done_req = 0;
databreak_notdone_req = 0;
// idle
DB0:
// read word count
DB1:
ma_out = wc-address;
databreak_notdone_req = 1;
db_next_state = DB2;
// write word count + 1
DB2:
mb_out = mb_in + 1;
ram_write = 1;
if (mb_in == 12'o7777)
databreak_done_req = 1;
db_next_state = DB3;
// finish write
DB3:
db_next_state = DB4;
// read current address
DB4:
ma_out = wc-address | 1;
db_next_state = DB5;
// write current address + 1
DB5:
mb_out = mb_in + 1;
ram_write = 1;
db_next_state = DB6;
// finish write
DB6:
db_next_state = DB7;
// set up read/write address
DB7:
ma_out = mb_in;
db_next_state = DB8;
// do read or start write
DB8:
if (databreak_write)
disk_buffer[disk_buffer_index] = memory_bus;
else
begin
mb_out = disk_buffer[disk_buffer_index];
ram_write = 1;
end
db_next_state = DB9;
// finish read/write
DB9:
disk_buffer_index = disk_buffer_index + 1;
new_da = {ema, dma} + 19'b1;
if (databreak_done)
begin
db_done = 1;
db_next_state = DB0;
end
else
if (disk_buffer_index == 8'b0)
begin
db_next_state = DB0;
db_eob = 1;
end
else
db_next_state = DB1;
*/
module pdp8_rf(clk, reset, iot, state, mb,
io_data_in, io_data_out, io_select,
io_data_avail, io_interrupt, io_skip);
input clk, reset, iot;
input [11:0] io_data_in;
input [11:0] mb;
input [3:0] state;
input [5:0] io_select;
output reg [11:0] io_data_out;
output reg io_data_avail;
output reg io_interrupt;
output reg io_skip;
parameter F0 = 4'b0000;
parameter F1 = 4'b0001;
parameter F2 = 4'b0010;
parameter F3 = 4'b0011;
parameter PCA_bit = 12'o4000; // photocell status
parameter DRE_bit = 12'o2000; // data req enable
parameter WLS_bit = 12'o1000; // write lock status
parameter EIE_bit = 12'o0400; // error int enable
parameter PIE_bit = 12'o0200; // photocell int enb
parameter CIE_bit = 12'o0100; // done int enable
parameter MEX_bit = 12'o0070; // memory extension
parameter DRL_bit = 12'o0004; // data late error
parameter NXD_bit = 12'o0002; // non-existent disk
parameter PER_bit = 12'o0001; // parity error
wire ADC;
wire DCF;
reg [11:0] DMA;
reg [7:0] EMA;
reg PEF;
reg rf08_rw;
reg rf08_start_io;
reg CIE, DRE, DRL, EIE, MEX, NXD, PCA, PER, PIE, WLS;
assign DCF = 1'b0;
assign ADC = DMA == /*DWA??*/0;
// combinatorial
always @(state or
ADC or DRL or PER or WLS or NXD or DCF)
begin
// sampled during f1
io_skip = 0;
io_data_out = io_data_in;
io_data_avail = 1;
dma_start = 0;
if (state == F1 && iot)
case (io_select)
6'o60:
case (mb[2:0])
3'o03: // DMAR
begin
io_data_out = 0;
dma_start = 1;
end
3'o03: // DMAW
begin
io_data_out = 0;
dma_start = 1;
end
endcase
6'o61:
case (mb[2:0])
3'o2: // DSAC
if (ADC)
begin
io_skip = 1;
io_data_out = 0;
end
3'o6: // DIMA
io_data_out = { PCA, DRE,WLS,EIE, PIE,CIE,MEX, DRL,NXD,PER };
3'o5: // DIML
io_data_out = 0;
endcase
6'o62:
case (mb[2:0])
3'o1: // DFSE
if (DRL | PER | WLS | NXD)
io_skip = 1;
3'o2: // ???
if (DCF)
io_skip = 1;
3'o3: // DISK
if (DRL | PER | WLS | NXD | DCF)
io_skip = 1;
3'o6: // DMAC
io_data_out = DMA;
endcase
6'o64:
case (mb[2:0])
3: // DXAL
io_data_out = 0;
5: // DXAC
io_data_out = EMA;
endcase
endcase // case(io_select)
end
//
// registers
//
always @(posedge clk)
if (reset)
begin
end
else
case (state)
F0:
begin
// sampled during f1
io_data_avail <= 0;
if (iot)
case (io_select)
6'o60: // DCMA
if (mb[2:0] == 3'b001)
begin
DMA <= 0;
PEF <= 0;
DRL <= 0;
end
6'o61:
case (mb[2:0])
3'o1: // DCIM
begin
CIE <= 0;
EMA <= 0;
end
3'o2: // DSAC
begin
end
3'o5: // DIML
begin
CIE <= io_data_in[8];
EMA <= io_data_in[7:0];
end
endcase // case(mb[2:0])
endcase
end
F1:
if (iot)
begin
$display("iot2 %t, state %b, mb %o, io_select %o",
$time, state, mb, io_select);
case (io_select)
6'o60:
case (mb[2:0])
3'o03: // DMAR
begin
// clear ac
DMA <= io_data_in;
rf08_start_io <= 1;
rf08_rw <= 0;
end
3'o03: // DMAW
begin
// clear ac
DMA <= io_data_in;
rf08_start_io <= 1;
rf08_rw <= 1;
end
endcase // case(mb[2:0])
6'o64:
case (mb[2:0])
1: // DCXA
EMA <= 0;
3: // DXAL
// clear ac
EMA <= io_data_in;
endcase
endcase
end // if (iot)
F2:
begin
if (io_interrupt)
$display("iot2 %t, reset io_interrupt", $time);
// sampled during f0
io_interrupt <= 0;
end
endcase // case(state)
always @(*)
begin
db_next_state = IDLE;
if (dma_start)
db_next_state = DB0;
end
always @(posedge clk)
if (reset)
state <= IDLE;
else
state <= db_next_state;
endmodule

138
rtl/pdp8_tt.v Normal file
View File

@@ -0,0 +1,138 @@
module pdp8_tt(clk, reset, iot, state, mb,
io_data_in, io_data_out, io_select,
io_data_avail, io_interrupt, io_skip);
input clk, reset, iot;
input [11:0] io_data_in;
input [11:0] mb;
input [3:0] state;
input [5:0] io_select;
output reg [11:0] io_data_out;
output reg io_data_avail;
output reg io_interrupt;
output reg io_skip;
reg rx_int, tx_int;
reg [12:0] rx_data, tx_data;
reg tx_delaying;
integer tx_delay;
parameter F0 = 4'b0000;
parameter F1 = 4'b0001;
parameter F2 = 4'b0010;
parameter F3 = 4'b0011;
// combinatorial
always @(state or
rx_int or tx_int)
begin
// sampled during f1
io_skip = 0;
io_data_out = io_data_in;
io_data_avail = 1;
if (state == F1 && iot)
case (io_select)
6'o03:
begin
if (mb[0])
io_skip = rx_int;
if (mb[2])
io_data_out = rx_data;
end
6'o04:
if (mb[0])
begin
io_skip = tx_int;
$display("xxx io_skip %b", tx_int);
end
endcase // case(io_select)
end
//
// registers
//
always @(posedge clk)
if (reset)
begin
end
else
case (state)
F0:
begin
// sampled during f1
io_data_avail <= 0;
end
F1:
if (iot)
begin
$display("iot2 %t, state %b, mb %o, io_select %o",
$time, state, mb, io_select);
case (io_select)
6'o03:
begin
if (mb[1])
rx_int <= 0;
end
6'o04:
begin
if (mb[0])
begin
end
if (mb[1])
begin
tx_int <= 0;
$display("xxx reset tx_int");
end
if (mb[2])
begin
tx_data <= io_data_in;
$display("xxx tx_data %o", io_data_in);
tx_int <= 1;
tx_delaying <= 1;
tx_delay <= 98;
$display("xxx set tx_int");
end
end // case: 6'o04
endcase
end // if (iot)
F2:
begin
if (io_interrupt)
$display("iot2 %t, reset io_interrupt", $time);
// sampled during f0
io_interrupt <= 0;
end
F3:
begin
if (tx_delaying)
begin
tx_delay <= tx_delay - 1;
//$display("xxx delay %d", tx_delay);
if (tx_delay == 0)
begin
$display("iot2 %t, xxx set io_interrupt", $time);
tx_delaying <= 0;
io_interrupt <= 1;
end
end
end
endcase // case(state)
endmodule