diff --git a/cpu/pdp8.v b/cpu/pdp8.v index 9072579..f5a4e60 100644 --- a/cpu/pdp8.v +++ b/cpu/pdp8.v @@ -6,6 +6,8 @@ // cleaned up a little; now runs focal to prompt // moved i/o out to pdp8_io.v // added IF, DF, user mode +// Apr 2009 +// major revamp for synthesis, removed latches, added muxes, new top // // TODO: @@ -57,55 +59,67 @@ // // -/* - cpu states - - F0 fetch - F1 incr pc - F2 write - F3 dispatch - - E0 read - E1 decode - E2 write - E3 load - -or - - D0 read - D1 wait - D2 write - D3 load - - ------ - - F0 fetch - check for interrupt - F1 incr pc - if opr - group 1 processing - group 2 processing - - if iot - - incr pc or skip (incr pc by 2) - - F2 write - ma <= pc - - F3 dispatch - if opr - group1 processing - - if !opr && !iot - possible defer - - - D0 - mb <= memory - D1 -*/ +// +// cpu states +// +// F0 fetch +// F1 incr pc +// F2 write +// F3 dispatch +// +// E0 read +// E1 decode +// E2 write +// E3 load +// +// or +// +// D0 read +// D1 wait +// D2 write +// D3 load +// +// H0 halted +// +// ------ +// +// F0 fetch +// check for interrupt +// +// F1 incr pc +// if opr +// group 1 processing +// group 2 processing +// +// if iot +// +// incr pc or skip (incr pc by 2) +// +// F2 write +// ma <= pc +// +// F3 dispatch +// if opr +// group1 processing +// +// if !opr && !iot +// possible defer +// +// +// D0 +// mb <= memory +// D1 +// D2 +// D3 +// +// E0 +// mb <= memory +// E1 +// E2 write isz value +// E3 +// +// // extended memory // // 62n1 cdf change data field; df <= mb[5:3] @@ -117,612 +131,569 @@ or // (remember that on interrupt, sf <= {if,df}) // -`include "pdp8_io.v" +module pdp8(clk, reset, + ram_addr, ram_data_out, ram_data_in, ram_rd, ram_wr, + io_select, io_data_out, io_data_in, + io_data_avail, io_interrupt, io_skip, + switches, iot, state, mb); -module pdp8(clk, reset_n, switches); + input clk, reset; + input [11:0] ram_data_in; + output ram_rd; + output ram_wr; + output [11:0] ram_data_out; + output [14:0] ram_addr; -input clk, reset_n; -input[11:0] switches; + output [5:0] io_select; + input [11:0] io_data_in; + output [11:0] io_data_out; -// memory buffer, holds data, instructions -reg[11:0] mb; + input io_data_avail; + input io_interrupt; + input io_skip; -// hold address of work in memory being accessed -reg[14:0] ma; - -// accumulator & link -reg[11:0] ac; -reg l; - -// MQ -reg [11:0] mq; + output iot; + output [3:0] state; + output [11:0] mb; -// program counter -reg[11:0] pc; -wire pc_incr, pc_skip; + input [11:0] switches; -// instruction register -reg[2:0] ir; + // memory buffer, holds data, instructions + reg [11:0] mb; -// extended memory - instruction field & data field -reg [2:0] IF; -reg [2:0] DF; -reg [2:0] IB; -reg [5:0] SF; -reg ib_pending; + // generate address of work in memory being accessed + wire [14:0] ma; + + // accumulator & link + reg [11:0] ac; + reg l; + + // MQ + reg [11:0] mq; -// user mode -reg UB; -reg UF; + // program counter + reg [11:0] pc; + wire pc_incr, pc_skip; + + // instruction register + reg [2:0] ir; + + // extended memory - instruction field & data field + reg [2:0] IF; + reg [2:0] DF; + reg [2:0] IB; + reg [5:0] SF; + reg ib_pending; -// -wire[11:0] memory_bus; -reg ram_we_n; + // user mode + reg UB; + reg UF; + + // processor state + reg [3:0] state; + wire [3:0] next_state; -// processor state -reg[3:0] state, next_state; + reg run; + reg interrupt_enable; + reg interrupt_cycle; + reg interrupt_inhibit; + reg interrupt_skip; -reg run; -reg interrupt_enable; -reg interrupt_cycle; -reg interrupt_inhibit; -reg interrupt_skip; + reg interrupt; + reg user_interrupt; -reg interrupt; -reg user_interrupt; + wire skip_condition; + + wire fetch; // memory cycle to fetch instruction + wire deferred;// memory cycle to get address of operand + wire execute;// memory cycle to getch (store) operand and execute isn -reg io_pulse_1, io_pulse_2, io_pulse_4; + assign {fetch, deferred, execute} = + (state[3:2] == 2'b00) ? 3'b100 : + (state[3:2] == 2'b01) ? 3'b010 : + (state[3:2] == 2'b10) ? 3'b001 : + 3'b000 ; -wire [11:0] io_data; -wire io_data_avail; -wire io_interrupt; -wire io_skip; + // instruction op decode + wire i_and,tad,isz,dca,jms,jmp,iot,opr; -wire[5:0] io_select; -assign io_select = mb[8:3]; - -wire skip_condition; - -wire fetch; // memory cycle to fetch instruction -wire deferred; // memory cycle to get address of operand -wire execute; // memory cycle to getch (store) operand and execute isn - -assign {fetch, deferred, execute} = - (state[3:2] == 2'b00) ? 3'b100 : - (state[3:2] == 2'b01) ? 3'b010 : - (state[3:2] == 2'b10) ? 3'b001 : - 3'b000 ; - -wire and,tad,isz,dca,jms,jmp,iot,opr; - -assign {and,tad,isz,dca,jms,jmp,iot,opr} = - (ir == 3'b000) ? 8'b10000000 : - (ir == 3'b001) ? 8'b01000000 : - (ir == 3'b010) ? 8'b00100000 : - (ir == 3'b011) ? 8'b00010000 : - (ir == 3'b100) ? 8'b00001000 : - (ir == 3'b101) ? 8'b00000100 : - (ir == 3'b110) ? 8'b00000010 : - 8'b00000001 ; + assign {i_and,tad,isz,dca,jms,jmp,iot,opr} = + (ir == 3'b000) ? 8'b10000000 : + (ir == 3'b001) ? 8'b01000000 : + (ir == 3'b010) ? 8'b00100000 : + (ir == 3'b011) ? 8'b00010000 : + (ir == 3'b100) ? 8'b00001000 : + (ir == 3'b101) ? 8'b00000100 : + (ir == 3'b110) ? 8'b00000010 : + 8'b00000001 ; -//------------- + //------------- -parameter F0 = 4'b0000; -parameter F1 = 4'b0001; -parameter F2 = 4'b0010; -parameter F3 = 4'b0011; + /* + * note: bit numbering is opposite that used in "Computer Engineering" + * + * F1 + * if opr + * if MB[8] and !MB[0] + * begin + * if skip.conditions ^ MB[3] + * pc <= pc + 2 + * if skip.conditions == MB[3] + * pc <= pc + 1 next + * if MB[7] + * ac <= 0 + */ + assign skip_condition = (mb[6] && ac[11]) || + (mb[5] && ac == 0) || + (mb[4] && l == 1); -parameter D0 = 4'b0100; -parameter D1 = 4'b0101; -parameter D2 = 4'b0110; -parameter D3 = 4'b0111; + assign pc_incr = + (opr & !mb[8]) || + (opr && (mb[8] && !mb[0]) && (skip_condition == mb[3])) || + iot || + (!(opr || iot) && !interrupt_cycle); -parameter E0 = 4'b1000; -parameter E1 = 4'b1001; -parameter E2 = 4'b1010; -parameter E3 = 4'b1011; - -ram_4kx12 ram( - .A(ma), - .DI(mb), - .DO(memory_bus), - .CE_N(1'b0), - .WE_N(ram_we_n)); - -/* - * note: bit numbering is opposite that used in "Computer Engineering" - * - * F1 - * if opr - * if MB[8] and !MB[0] - * begin - * if skip.conditions ^ MB[3] - * pc <= pc + 2 - * if skip.conditions == MB[3] - * pc <= pc + 1 next - * if MB[7] - * ac <= 0 - */ -assign skip_condition = - (mb[6] && ac[11]) || - (mb[5] && ac == 0) || - (mb[4] && l == 1); - -assign pc_incr = - (opr & !mb[8]) || - (opr && (mb[8] && !mb[0]) && (skip_condition == mb[3])) || - iot || - (!(opr || iot) && !interrupt_cycle); - -assign pc_skip = - (opr && (mb[8] && !mb[0]) && (skip_condition ^ mb[3])) || - (iot && (io_skip || interrupt_skip)); -// (iot && mb[0] && io_skip); + assign pc_skip = + (opr && (mb[8] && !mb[0]) && (skip_condition ^ mb[3])) || + (iot && (io_skip || interrupt_skip)); + // (iot && mb[0] && io_skip); -pdp8_io io(.clk(clk), .reset_n(reset_n), - .iot(iot), .state(state), .pc(pc), .ac(ac), .mb(mb), - .io_select(io_select), - .io_data_out(io_data), - .io_data_avail(io_data_avail), - .io_interrupt(io_interrupt), - .io_skip(io_skip)); + // cpu states + parameter F0 = 4'b0000; + parameter F1 = 4'b0001; + parameter F2 = 4'b0010; + parameter F3 = 4'b0011; -always @(reset_n) - if (reset_n == 0) - begin - pc <= 0; - ma <= 0; - mb <= 0; - ac <= 0; - mq <= 0; - l <= 0; - ir <= 0; - ram_we_n <= 1; + 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 H0 = 4'b1100; + + // + // cpu state state machine + // + // clock next cpu state at rising edge of clock + // + + always @(posedge clk) + if (reset) state <= 0; - next_state <= 0; - run <= 1; - interrupt_enable <= 0; - interrupt_cycle <= 0; - interrupt_inhibit <= 0; - interrupt_skip <= 0; - interrupt <= 0; - user_interrupt <= 0; - io_pulse_1 <= 0; - io_pulse_2 <= 0; - io_pulse_4 <= 0; - IF <= 0; - DF <= 0; - IB <= 0; - SF <= 0; - UF <= 0; - UB <= 0; - ib_pending <= 0; - end + else + state <= next_state; -initial - begin - ram_we_n = 1; - end + wire next_is_F0; + wire next_is_E0; + + assign next_is_F0 = opr | iot | (!mb[8] & jmp); + assign next_is_E0 = !mb[8] & !jmp; + + assign next_state = state == F0 ? F1 : + state == F1 && (~iot | (iot & io_data_avail)) ? F2 : + state == F2 ? F3 : + state == F3 ? (~run ? H0 : + next_is_F0 ? F0 : + next_is_E0 ? E0 : + D0) : + state == D0 ? D1 : + state == D1 ? D2 : + state == D2 ? D3 : + state == D3 ? (jmp ? F0 : E0) : + state == E0 ? E1 : + state == E1 ? E2 : + state == E2 ? E3 : + state == E3 ? F0 : + state == H0 ? H0 : + F0; -/* - * cpu state state machine - * - * clock next cpu state at rising edge of clock - */ + // + // pc + // + wire [11:0] pc_mux; -always @(posedge clk) - state <= #1 next_state; + always @(posedge clk) + if (reset) + pc <= 0; + else + begin + //if (state == F1 || state == D3 || state == E3) + //$display(" pc <- %o", pc_mux); + pc <= pc_mux; + end -always @(state) - begin - case (state) + assign pc_mux = (state == F1 && pc_skip) ? (pc + 12'd2) : + (state == F1 && pc_incr) ? (pc + 12'd1) : + (state == F3 && !(opr || iot) && (!mb[8] & jmp)) ? ma : + (state == D3 && jmp) ? mb : + (state == E3 && jms) ? ma : + (state == E3 && isz && mb == 12'b0) ? (pc + 12'd1) : + pc; - // FETCH - F0: - begin - interrupt_skip <= 0; - - if (interrupt && interrupt_enable && - !interrupt_inhibit && !interrupt_cycle) - begin - $display("interrupt; %b %b %b", - interrupt, interrupt_enable, interrupt_cycle); - interrupt_cycle <= 1; - interrupt <= 0; - mb <= 12'o4000; - ir <= 3'o4; - SF <= {IF,DF}; - IF <= #1 3'b000; - DF <= #1 3'b000; - end + // + // ram + // + assign ram_rd = (state == F0) || + (state == D0) || + (state == E0); + + assign ram_wr = (state == D2 && is_index_reg) || + (state == E2 && (isz || dca || jms)); + + assign ram_addr = ma; + assign ram_data_out = mb; + + assign io_select = mb[8:3]; + assign io_data_out = ac; + + // + // ea calculation + // + reg [14:0] ea; + + always @(posedge clk) + if (reset) + ea <= 0; + else + if (state == F1) + ea <= {DF, mb[7] ? pc[11:7] : 5'b0, mb[6:0]}; else - begin - interrupt_cycle <= 0; - mb <= memory_bus; - ir <= memory_bus[11:9]; - end + if (state == D3) + ea <= mb; - next_state <= F1; - end + wire is_index_reg; + assign is_index_reg = ea[11:3] == 8'h01; + + // + // ma + // + assign ma = (state == F0) ? {IF, pc} : + (state == F2 && (opr || iot)) ? {IF,pc} : + ((state == F3 || state == D0 || state == E0) && + (!opr && !iot)) ? ea : + (state == D2) ? (is_index_reg ? ea : {DF,mb}) : + (state == E2 ) ? ea : + (state == E3 && jms) ? {ea[14:12], ea[11:0] + 12'b1} : + 15'b0; + + // + // registers + // + always @(posedge clk) + if (reset) + begin + mb <= 0; + ac <= 0; + mq <= 0; + l <= 0; + ir <= 0; + run <= 1; + interrupt_enable <= 0; + interrupt_cycle <= 0; + interrupt_inhibit <= 0; + interrupt_skip <= 0; + interrupt <= 0; + user_interrupt <= 0; + IF <= 0; + DF <= 0; + IB <= 0; + SF <= 0; + UF <= 0; + UB <= 0; + ib_pending <= 0; + end + else + case (state) + // FETCH + F0: + begin + interrupt_skip <= 0; + + if (interrupt && interrupt_enable && + !interrupt_inhibit && !interrupt_cycle) + begin + $display("interrupt; %b %b %b", + interrupt, interrupt_enable, interrupt_cycle); + interrupt_cycle <= 1; + interrupt <= 0; - F1: - begin -//$display("f1: io_skip %b", io_skip); -//$display("f1 - ma %o, mb %o, ir %o", ma, mb, ir); - if (opr) - begin - // group 1 - if (!mb[8]) - begin -// $display("f1/g1 - ma %o, mb %o, ac %o l %o", ma, mb, ac,l); + // simulate a jsr to 0 + mb <= 12'o4000; + ir <= 3'o4; + SF <= {IF,DF}; + IF <= 3'b000; + DF <= 3'b000; + end + else + begin + interrupt_cycle <= 0; +//?? interrupt_inhibit <= 0; +//?? ib_pending <= 0; + $display(" read ram %o -> %o", ram_addr, ram_data_in); + mb <= ram_data_in; + ir <= ram_data_in[11:9]; + end + end - if (mb[7]) ac <= 0; - if (mb[6]) l <= 0; - if (mb[5]) ac <= ~ac; - if (mb[4]) l <= ~l; - end + F1: + begin + if (opr) + case ({mb[8],mb[0]}) + 2'b0x: // group 1 + begin + if (mb[7]) ac <= 0; + if (mb[6]) l <= 0; + if (mb[5]) ac <= ~ac; + if (mb[4]) l <= ~l; + end - // group 2 - if (mb[8] & !mb[0]) - begin -// $display("f1/g2 - ma %o, mb %o, sc %o, i %o s %o, ac %o l %o", -// ma, mb, skip_condition, pc_incr, pc_skip, ac, l); + 2'b10: // group 2 + begin + if (mb[7]) + ac <= 0; + end - if (mb[7]) - ac <= 0; - end + 2'b11: // group 3 + begin + if (mb[7]) + ac <= 0; + end - // group 3 - if (mb[8] & mb[0]) - begin - if (mb[7]) ac <= 0; - end - end + default: + ; + endcase - if (iot) - begin + if (iot) + begin + case (io_select) + 6'b000000: // ION, IOF + case (mb[2:0]) + 3'b001: interrupt_enable <= 1; + 3'b010: interrupt_enable <= 0; + 3'b011: if (interrupt_enable) + interrupt_skip <= 1; + endcase - $display("iot %t, run %b, state %b, pc %o, ir %o, mb %o, io_select %o", - $time, run, state, pc, ir, mb, io_select); + 6'b010xxx: // CDF..RMF + begin + case (mb[2:0]) + 3'b001: DF <= mb[5:3]; // CDF + 3'b010: // CIF + begin + IB <= mb[5:3]; + ib_pending <= 1; + interrupt_inhibit <= 1; + end + 3'b100: + case (io_select[2:0]) + 3'b001: ac <= { 6'b0, DF, 3'b0 }; // RDF + 3'b010: ac <= { 6'b0, IF, 3'b0 }; // RIF + 3'b011: ac <= { 6'b0, SF }; // RIB + 3'b100: begin // RMF + IB <= SF[5:3]; + DF <= SF[2:0]; + end + endcase + endcase + end + endcase // case(io_select) - if (mb[0]) io_pulse_1 <= 1; - if (mb[1]) io_pulse_2 <= 1; - if (mb[2]) io_pulse_4 <= 1; + if (io_data_avail) + begin + //$display("io_data clock %o", io_data_in); + ac <= io_data_in; + end + end // if (iot) + + if (io_interrupt) + interrupt <= 1; - case (io_select) - 6'b000000: // ION, IOF - case (mb[2:0]) - 3'b001: interrupt_enable <= 1; - 3'b010: interrupt_enable <= 0; - 3'b011: if (interrupt_enable) interrupt_skip <= 1; - endcase // case(mb[2:0]) + end // case: F1 - 6'b010xxx: // CDF..RMF - begin - case (mb[2:0]) - 3'b001: DF <= mb[5:3]; // CDF - 3'b010: // CIF - begin - IB <= mb[5:3]; - ib_pending <= 1; - interrupt_inhibit <= 1; - end - 3'b100: - case (io_select[2:0]) - 3'b001: ac <= { 6'b0, DF, 3'b0 }; // RDF - 3'b010: ac <= { 6'b0, IF, 3'b0 }; // RIF - 3'b011: ac <= { 6'b0, SF }; // RIB - 3'b100: begin // RMF - IB <= SF[5:3]; - DF <= SF[2:0]; - end - endcase // case(io_select[2:0]) - endcase // case(mb[2:0]) - end - endcase - - if (io_data_avail) - begin - ac <= io_data; - end - end - - if (io_interrupt) - interrupt <= 1; - - //$display("f1 io_skip %b skip %b, incr %b", io_skip, pc_skip, pc_incr); - if (pc_skip) - pc <= pc + 2; - else - if (pc_incr) - pc <= pc + 1; - - next_state <= F2; - end - - F2: - begin - io_pulse_1 <= 0; - io_pulse_2 <= 0; - io_pulse_4 <= 0; - - if (opr) - begin - ma <= {IF,pc}; - - // group 3 - if (mb[8] & mb[0]) - begin - $display("f2/g3 - ma %o, mb %o, ac %o l %o", ma, mb, ac,l); - + F2: + begin + if (opr) + begin + // group 3 + if (mb[8] & mb[0]) case ({mb[6:4]}) 3'b001: mq <= ac; 3'b100: ac <= ac | mq; -// 3'b101: tmq <= mq; + //3'b101: tmq <= mq; 3'b100: ac <= mq; 3'b101: ac <= mq; - endcase // case({mb[6:4]}) - end // if (mb[8] & mb[0]) - end // if (opr) - - if (iot) - ma <= {IF,pc}; + endcase + end + end - if (!(opr || iot)) - begin - ma[6:0] <= mb[6:0]; - if (!mb[7]) - ma[11:7] <= 0; - end + F3: + begin + if (opr) + begin + // group 1 + if (!mb[8]) + begin + if (mb[0]) // IAC + {l,ac} <= {l,ac} + 1'b1; + if (mb[3:1] == 3'b001) // BSW + {l,ac} <= {l,ac[5:0],ac[11:6]}; + if (mb[3] && !mb[1]) // RAR + {l,ac} <= {ac[0],l,ac[11:1]}; + if (mb[3] && mb[1]) // RTR + {l,ac} <= {ac[1:0],l,ac[11:2]}; + if (mb[2] && !mb[1]) // RAL + {l,ac} <= {ac[11:0],l}; + if (mb[2] && mb[1]) // RTL + {l,ac} <= {ac[10:0],l,ac[11]}; + end - next_state <= F3; - end + if (!UF) + begin + // group 2 + if (mb[8] & !mb[0]) + begin + if (mb[2]) + ac <= ac | switches; + if (mb[1]) + run <= 0; + end + end - F3: - begin - if (opr) - begin - // group 1 - if (!mb[8]) - begin - if (mb[0]) // IAC - {l,ac} <= {l,ac} + 1'b1; - if (mb[3:1] == 3'b001) // BSW - {l,ac} <= {l,ac[5:0],ac[11:6]}; - if (mb[3] && !mb[1]) // RAR - {l,ac} <= {ac[0],l,ac[11:1]}; - if (mb[3] && mb[1]) // RTR - {l,ac} <= {ac[1:0],l,ac[11:2]}; - if (mb[2] && !mb[1]) // RAL - {l,ac} <= {ac[11:0],l}; - if (mb[2] && mb[1]) // RTL - {l,ac} <= {ac[10:0],l,ac[11]}; - end + if (UF) + begin + // group 2 - user mode (halt & osr) + if (mb[8] & !mb[0]) + begin + if (mb[2]) + user_interrupt <= 1; + if (mb[1]) + user_interrupt <= 1; + end + end - if (!UF) - begin - // group 2 - if (mb[8] & !mb[0]) - if (mb[2]) - ac <= ac | switches; - if (mb[1]) - run <= 0; - end + // group 3 + if (mb[8] & mb[0]) + begin + if (mb[7:4] == 4'b1101) + mq <= 0; + end + +// ir <= 0; +// mb <= 0; + end // if (opr) - if (UF) - begin - // group 2 - user mode (halt & osr) - if (mb[8] & !mb[0]) - if (mb[2]) - user_interrupt <= 1; - if (mb[1]) - user_interrupt <= 1; - end +// if (iot) +// begin +// ir <= 0; +// mb <= 0; +// end - // group 3 - if (mb[8] & mb[0]) - begin - if (mb[7:4] == 4'b1101) mq <= 0; - end - - ir <= 0; - mb <= 0; - next_state <= F0; - end +// if (!(opr || iot)) +// begin +// if (!mb[8] & jmp) +// begin +// //pc <= ma; +// ir <= 0; +// mb <= 0; +// end +// +// if (mb[8]) +// mb <= 0; +// +// if (!mb[8] & !jmp) +// mb <= 0; +// end + end // case: F3 + - if (iot) - begin - ir <= 0; - mb <= 0; - next_state <= F0; - end + // DEFER - if (!(opr || iot)) - begin - if (!mb[8] & jmp) - begin - pc <= ma; - ir <= 0; - mb <= 0; - next_state <= F0; - end - - if (mb[8]) - begin - mb <= 0; - next_state <= D0; /* defer */ - end + D0: + begin + $display(" read ram %o -> %o", ram_addr, ram_data_in); + mb <= ram_data_in; + end - if (!mb[8] & !jmp) - begin - mb <= 0; - next_state <= E0; - end - end - end + D1: + begin + // auto increment locations + if (is_index_reg) + mb <= mb + 1; + end - // DEFER + D2: + begin + // write ram + $display(" write ram %o <- %o", ram_addr, ram_data_out); + end + + D3: + begin +// if (jmp) +// begin +// //pc <= mb; +// ir <= 0; +// mb <= 0; +// end +// +// if (!jmp) +// begin +// mb <= 0; +// end + end - D0: - begin - mb <= memory_bus; - next_state <= D1; - end + // EXECUTE - D1: - begin - // auto increment regs - if (ma[11:3] == 8'h01) - mb <= mb + 1; + E0: + begin + $display(" read ram %o -> %o", ram_addr, ram_data_in); + mb <= ram_data_in; + end - next_state <= D2; - end + E1: + begin + if (i_and) + begin + end - D2: - begin - // write back - if (ma[11:3] == 8'h01) - ram_we_n <= 0; + if (isz) + mb <= mb + 1; + else + if (dca) + mb <= ac; + else + if (jms) + mb <= pc; + end - ma <= #1 {DF,mb}; - next_state <= D3; - end + E2: + begin + // write ram + $display(" write ram %o <- %o", ram_addr, ram_data_out); + end + + E3: + begin + if (i_and) + ac <= ac & mb; + else + if (tad) + {l,ac} <= ac + mb; + else + if (dca) + ac <= 0; - D3: - begin - ram_we_n <= 1; - - if (jmp) - begin - pc <= mb; - ir <= 0; - mb <= 0; - next_state <= F0; - end - - if (!jmp) - begin - mb <= 0; - next_state <= E0; - end - end - - // EXECUTE - - E0: - begin - mb <= memory_bus; - next_state <= E1; - end - - E1: - begin - if (and) - ; - - if (isz) - begin - mb <= mb + 1; - if (mb == 12'b111111111111) - pc <= pc + 1; - end - - if (dca) - mb <= ac; - - if (jms) - mb <= pc; - - next_state <= E2; - end - - E2: - begin - if (isz || dca || jms) - ram_we_n <= 0; - - if (~jms) - ma <= #1 {IF,pc}; - - if (jms) - ma <= #1 {ma[14:12], ma[11:0] + 1}; - - next_state <= E3; - end - - E3: - begin - ram_we_n <= 1; - - if (and) - ac <= ac & mb; - - if (tad) - {l,ac} <= ac + mb; - - //if (tad) $display("tad - mb %o, ac %o l %o", mb, ac, l); - - if (dca) - ac <= 0; - - if (jms) - pc <= ma; - - ir <= 0; - next_state <= F0; - end - endcase - end - -endmodule - -/* 4kx12 static ram */ -module ram_4kx12(A, DI, DO, CE_N, WE_N); - - input[14:0] A; - input[11:0] DI; - input CE_N, WE_N; - output[11:0] DO; - - reg[11:0] ram [0:32767]; - integer i; - - initial - begin - for (i = 0; i < 32768; i=i+1) - ram[i] = 12'b0; - - ram[15'o0000] = 12'o5177; - ram[15'o0200] = 12'o7300; - ram[15'o0201] = 12'o1300; - ram[15'o0202] = 12'o1301; - ram[15'o0203] = 12'o3302; - ram[15'o0204] = 12'o7402; - ram[15'o0205] = 12'o5200; - -`include "focal.v" - ram[15'o0000] = 12'o5404; - ram[15'o0004] = 12'o0200; - end - - always @(negedge WE_N) - begin - if (CE_N == 0) - begin - $display("ram: write [%o] <- %o", A, DI); - ram[ A ] = DI; - end - end - -//always @(A) -// begin -// $display("ram: ce %b, we %b [%o] -> %o", CE_N, WE_N, A, ram[A]); -// end - -// assign DO = ram[ A ]; -assign DO = (^A === 1'bX || A === 1'bz) ? ram[0] : ram[A]; + // pc <- ma +// ir <= 0; + end + endcase // case(state) endmodule diff --git a/cpu/pdp8_io.v b/cpu/pdp8_io.v index 186a4e7..99526e3 100644 --- a/cpu/pdp8_io.v +++ b/cpu/pdp8_io.v @@ -1,7 +1,7 @@ // 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 @@ -184,13 +184,12 @@ will process the information. */ -module pdp8_io(clk, reset_n, iot, state, pc, ac, mb, - io_select, - io_data_out, io_data_avail, io_interrupt, io_skip, io_clear_ac); +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_n, iot; - input [11:0] pc; - input [11:0] ac; + input clk, reset, iot; + input [11:0] io_data_in; input [11:0] mb; input [3:0] state; input [5:0] io_select; @@ -199,7 +198,6 @@ module pdp8_io(clk, reset_n, iot, state, pc, ac, mb, output reg io_data_avail; output reg io_interrupt; output reg io_skip; - output reg io_clear_ac; reg rx_int, tx_int; @@ -223,89 +221,143 @@ module pdp8_io(clk, reset_n, iot, state, pc, ac, mb, parameter E3 = 4'b1011; - parameter PCA = 12'o4000; // photocell status - parameter DRE = 12'o2000; // data req enable - parameter WLS = 12'o1000; // write lock status - parameter EIE = 12'o0400; // error int enable - parameter PIE = 12'o0200; // photocell int enb - parameter CIE = 12'o0100; // done int enable - parameter MEX = 12'o0070; // memory extension - parameter DRL = 12'o0004; // data late error - parameter NXD = 12'o0002; // non-existent disk - parameter PER = 12'o0001; // parity error + 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; - always @(state) + // combinatorial + always @(state or + rx_int or tx_int or + ADC or DRL or PER or WLS or NXD or DCF) begin - case (state) + // sampled during f1 + io_skip = 0; + io_data_out = io_data_in; + io_data_avail = 1; + + if (state == F0 && 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]) + io_skip = tx_int; + + 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_skip <= 0; io_data_avail <= 0; - io_clear_ac <= 0; if (iot) case (io_select) - 6'o03: - if (mb[0]) - io_skip <= rx_int; - - 6'o04: - if (mb[0]) - begin - $display("tsf; tx_int %b, pc %o", tx_int, pc); - io_skip <= tx_int; - end - 6'o60: // DCMA if (mb[2:0] == 3'b001) begin DMA <= 0; - PEF < = 0; + PEF <= 0; DRL <= 0; end 6'o61: case (mb[2:0]) -n 3'o1: // DCIM + 3'o1: // DCIM begin CIE <= 0; EMA <= 0; end 3'o2: // DSAC -// xxx -assign ADC = DMA == DWA; - begin - if (ADC) - begin - io_skip <= 1; - io_clear_ac <= 1; - end end 3'o5: // DIML begin - CIE <= AC[8]; - EMA <= AC[7:0]; - end - 3'o6: // DIMA - begin - AC <= { PCA,DRE,WLS,EIE,PIE,CIE, MEX, DRL,NXD,PER }; + CIE <= io_data_in[8]; + EMA <= io_data_in[7:0]; end endcase // case(mb[2:0]) - - 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; - endcase endcase end @@ -320,11 +372,6 @@ assign ADC = DMA == DWA; begin if (mb[1]) rx_int <= 0; - if (mb[2]) - begin - io_data_out <= rx_data; - io_data_avail <= 1; - end end 6'o04: @@ -333,8 +380,7 @@ assign ADC = DMA == DWA; tx_int <= 0; if (mb[2]) begin - $display("tls; %o", ac); - tx_data <= ac; + tx_data <= io_data_in; tx_int <= 1; tx_delaying <= 1; tx_delay <= 4'b1111; @@ -346,43 +392,28 @@ assign ADC = DMA == DWA; case (mb[2:0]) 3'o03: // DMAR begin - DMA <= AC; - io_clear_ac <= 0; + // clear ac + DMA <= io_data_in; rf08_start_io <= 1; rf08_rw <= 0; end 3'o03: // DMAW begin - DMA <= AC; - io_clear_ac <= 0; + // clear ac + DMA <= io_data_in; rf08_start_io <= 1; rf08_rw <= 1; end endcase // case(mb[2:0]) - 6'o62: - case (mb[2:0]) - 6: // DMAC - begin -// io_clear_ac <= 1; - io_ac <= DMA; - end - endcase - 6'o64: case (mb[2:0]) 1: // DCXA EMA <= 0; 3: // DXAL - begin - EMA <= AC; - io_clean_ac <= 1; - end - 5: // DXAC - begin - AC <= EMA; - end + // clear ac + EMA <= io_data_in; endcase endcase @@ -412,8 +443,6 @@ assign ADC = DMA == DWA; end end - - endcase // case(state) - end - + endcase // case(state) + endmodule diff --git a/cpu/pdp8_ram.v b/cpu/pdp8_ram.v new file mode 100644 index 0000000..b5c5404 --- /dev/null +++ b/cpu/pdp8_ram.v @@ -0,0 +1,22 @@ +// + +`include "ram_32kx12.v" + +module pdp8_ram(clk, reset, addr, data_in, data_out, rd, wr); + + input clk; + input reset; + input [14:0] addr; + input [11:0] data_in; + output [11:0] data_out; + input rd; + input wr; + + + ram_32kx12 ram(.A(addr), + .DI(data_in), + .DO(data_out), + .CE_N(1'b0), + .WE_N(~wr)); + +endmodule diff --git a/cpu/ram_32kx12.v b/cpu/ram_32kx12.v new file mode 100644 index 0000000..3bf42f0 --- /dev/null +++ b/cpu/ram_32kx12.v @@ -0,0 +1,49 @@ + +/* 32kx12 static ram */ +module ram_32kx12(A, DI, DO, CE_N, WE_N); + + input[14:0] A; + input[11:0] DI; + input CE_N, WE_N; + output[11:0] DO; + + reg[11:0] ram [0:32767]; + integer i; + + initial + begin + for (i = 0; i < 32768; i=i+1) + ram[i] = 12'b0; + + ram[15'o0000] = 12'o5177; + ram[15'o0200] = 12'o7300; + ram[15'o0201] = 12'o1300; + ram[15'o0202] = 12'o1301; + ram[15'o0203] = 12'o3302; + ram[15'o0204] = 12'o7402; + ram[15'o0205] = 12'o5200; + +`include "focal.v" + ram[15'o0000] = 12'o5404; + ram[15'o0004] = 12'o0200; + end + + always @(WE_N or CE_N or A or DI) + begin + if (WE_N == 0 && CE_N == 0) + begin + $display("ram: write [%o] <- %o", A, DI); + ram[ A ] = DI; + end + end + +//always @(A) +// begin +// $display("ram: ce %b, we %b [%o] -> %o", CE_N, WE_N, A, ram[A]); +// end + +// assign DO = ram[ A ]; +assign DO = (^A === 1'bX || A === 1'bz) ? ram[0] : ram[A]; + +endmodule + diff --git a/cpu/run.v b/cpu/run.v index 888599c..f6014dd 100644 --- a/cpu/run.v +++ b/cpu/run.v @@ -1,14 +1,73 @@ +// run.v +// testing top end for pdp8.v +// `include "pdp8.v" +`include "pdp8_io.v" +`include "pdp8_ram.v" `timescale 1ns / 1ns module test; - reg clk, reset_n; - reg[11:0] switches; + reg clk, reset; + reg [11:0] switches; + + wire [11:0] ram_data_in; + wire ram_rd; + wire ram_wr; + wire [11:0] ram_data_out; + wire [14:0] ram_addr; + wire [11:0] io_data_in; + wire [11:0] io_data_out; + wire [11:0] io_addr; + wire io_data_avail; + wire io_interrupt; + wire io_skip; + wire [5:0] io_select; + + wire iot; + wire [3:0] state; + wire [11:0] mb; + + pdp8 cpu(.clk(clk), + .reset(reset), + .ram_addr(ram_addr), + .ram_data_in(ram_data_out), + .ram_data_out(ram_data_in), + .ram_rd(ram_rd), + .ram_wr(ram_wr), + .state(state), + .io_select(io_select), + .io_data_in(io_data_in), + .io_data_out(io_data_out), + .io_data_avail(io_data_avail), + .io_interrupt(io_interrupt), + .io_skip(io_skip), + .iot(iot), + .mb(mb), + .switches(switches)); + + pdp8_io io(.clk(clk), + .reset(reset), + .iot(iot), + .state(state), + .mb(mb), + .io_data_in(io_data_out), + .io_data_out(io_data_in), + .io_select(io_select), + .io_data_avail(io_data_avail), + .io_interrupt(io_interrupt), + .io_skip(io_skip)); + + pdp8_ram ram(.clk(clk), + .reset(reset), + .addr(ram_addr), + .data_in(ram_data_in), + .data_out(ram_data_out), + .rd(ram_rd), + .wr(ram_wr)); - pdp8 cpu(clk, reset_n, switches); initial begin @@ -21,24 +80,23 @@ module test; initial begin clk = 0; - reset_n = 1; + reset = 0; #1 begin - reset_n = 0; + reset = 1; end - #100 begin - reset_n = 1; + #50 begin + reset = 0; end -// #1500000 $finish; #3000000 $finish; end always begin - #100 clk = 0; - #100 clk = 1; + #10 clk = 0; + #10 clk = 1; end //---- @@ -48,21 +106,19 @@ module test; cycle = 0; always @(posedge cpu.clk) - if (cpu.state == 4'b0000) +// if (cpu.state == 4'b0000) begin cycle = cycle + 1; - #1 $display("cycle %d, r%b, pc %o, ir%o, ma %o, mb %o, jmp %b, l%b ac %o, i%b/%b", - cycle, cpu.run, cpu.pc, + #1 $display("#%d, r%b s%d, pc %o ir%o ma %o mb %o j%b l%b ac %o, i%b/%b", + cycle, cpu.run, cpu.state, cpu.pc, cpu.ir, cpu.ma, cpu.mb, cpu.jmp, cpu.l, cpu.ac, cpu.interrupt_enable, cpu.interrupt); - end + //#1 $display(" io_data_in %o, io_data_out %o", + //io_data_in, io_data_out); -// always @(posedge cpu.clk) -// begin -// #1 $display("state %b, runs %b, pc %o, ir %o, ma %o mb %o, jmp %b, l %b ac %o", -// cpu.state, cpu.run, cpu.pc, -// cpu.ir, cpu.ma, cpu.mb, cpu.jmp, cpu.l, cpu.ac); -// end + if (state == 4'b1100) + $finish; + end endmodule