// Implements: // - X16 CPU with the RTC option, and since version 02, Extend Mode + 32K. // - Control Units for the TTY, PTR and PTP // // // Name : X16_Cpu_04.v // Version: 04 // Date : 05-10-2011 // Author : Theo Engel // Contact: Info@theoengel.nl // // Version 02 (published 15-01-2010: LDR-APM working) // - adds extended addressing mode + support of a 32k word memory // - solved error: -delay DXA until next JMP // - solved error: -JST store 14 or 15 bit in EA; bit 1,2 or 1 not changed // Version 021 (published 17-01-2010) // - extended addressing test: error in line 1010, in EXE_EXT code (typo) // Version 022 // - ALS and LLS changed (setting C-Bit) // Version 023 // - shift instruction reorganized // Version 03 (023=>03) // - oPtrTry signal added to inform FPTR that byte is transferrred to Areg // Version 031 // - solved error: overflow logic ACA instruction (line 1391: 1'b1 changed into oC) // Version 04 (031=>04) // - version 031 was compiled with Quartus 9.2sp2. When compiled with 10.1sp1, IR sometimes got a // wrong value (time critical?) To make the design of the cpu less time critical, // some additional states are added in the fetch/decode stages. // No wrong IR values anymore. // // Note: The Mode-state of the CPU (Normal or Extend) is represented by the EXT flipflop. // EXT is one when in extended mode or zero when in normal mode. // The PME flipflop represents the "previous" mode, and is set in this implementation // only with an interrupt. Other mode changes (like doing an EXA or DXA) do not // change the value of PME (in this implementation). Whether this is as in the // origional 316/516 is unknown at this moment. // The consequence of this implementation is that the instruction INK only provides // a valid previous mode directly after an interrupt! // module X16_CPU (iClk, iA,oA,iB,oB,oC,oX,iPC,oPC,oIR,iSense, oPC_WR,oPC_INC1,oPC_INC2,oA_WR, oB_WR, /// Memory iMbr,oMbr,oM_we_n,oM_oe_n,oMaddr, /// Control iRun,iStep,iStop,iMC_n,oRunning,oEnb,oPil,oError,if_SWS,iPR,oExt, /// TTY TtyCharIn, oTtyInReq, iTtyIChar, oTty, oTtyCharO, iTtyOutReady, /// PTR oPtrInReq, iPtrIChar, PtrCharIn, oPtrTry, /// PTP oPtp, oPtpChar, iPtpOutReady); input wire [15:0] iA, iB, iPC, iMbr, iPR; output reg oPC_WR, oPC_INC1, oPC_INC2, oA_WR, oB_WR; output reg [15:0] oA, oB, oPC, oMbr; output wire [15:0] oIR, oX, oMaddr; output wire oC; input [3:0] iSense; input iClk, iRun, iStep, iStop, iMC_n; output reg oM_we_n, oM_oe_n; output wire oRunning; output reg oError; output wire oEnb, oExt; input wire if_SWS; output wire oPil; /////////////////////////////////////////////// // IO Control Unit interfaces and Control Units /////////////////////////////////////////////// // TTY input [7:0] TtyCharIn; // PC=>cu output reg oTtyInReq; // signals input mode to the TTY/PC input iTtyIChar; // TTY/PC signals that an input char is available output wire [7:0] oTty; // cu=>PC output reg oTtyCharO; // output signal: if 1, char for output is available input iTtyOutReady; // signals that the character is sent to the TTY/PC // PTR output reg oPtrInReq; // signals input mode from the cu to PTR/PC input iPtrIChar; // PTR/PC signals that an input char is available input [7:0] PtrCharIn; // PC=>cu output reg oPtrTry; // cu=>FPTR: tranfer to Areg ready // PTP output wire [7:0] oPtp; // cu=>PC output reg oPtpChar; // output signal to PTP/PC: if 1, char for output is available input iPtpOutReady; // PTP/PC signals that the character is output ////////////////////////////////// // Paper Tape Puncher Control Unit ////////////////////////////////// reg [1:0] mPtpCuSt; // Control unit state reg mPtpOutReq; // Set by OTA when character is ready for output reg mPtpReady; // Ready flipflop reg mPtp_Power; // power state reg Ptp_Power_On; // power on pulse (ocp) reg Ptp_Power_Off; // power off pulse (ocp) reg mPtp_WR; // Load PTP Register reg [7:0] iPtp; // PTP Register in always @(posedge iClk or negedge iMC_n) begin if(! iMC_n) begin mPtp_Power <= 1'b0; oPtpChar <= 1'b0; mPtpReady <= 1'b0; //not ready mPtpCuSt <= 2'b00; end else begin case(mPtpCuSt) 2'b00: begin mPtp_Power <= 1'b0; oPtpChar <= 1'b0; mPtpReady <= 1'b0; mPtpCuSt <= 2'b00; if(Ptp_Power_On) begin mPtp_Power <= 1'b1; oPtpChar <= 1'b0; mPtpReady <= 1'b0; mPtpCuSt <= 2'b01; end end 2'b01: // power is on and ready: OTA generates mPtpOutReq when char output begin mPtp_Power <= 1'b1; oPtpChar <= 1'b0; mPtpReady <= 1'b1; // wait for ota mPtpCuSt <= 2'b01; if(mPtpOutReq) // yes => char in output buffer by OTA begin mPtp_Power <= 1'b1; oPtpChar <= 1'b1; // inform SWITCHES (and OTA) mPtpReady <= 1'b0; // not ready; character being transmitted to Puncher mPtpCuSt <= 2'b10; end else if(Ptp_Power_Off) mPtpCuSt <= 2'b00; end 2'b10: // character being transferred to and over JTAG // oPtpChar signals the puncher interface that a char is available for punching // the puncher interface responds with iPtpOutReady when the char is sent to the puncher begin mPtp_Power <= 1'b1; oPtpChar <= 1'b1; mPtpReady <= 1'b0; mPtpCuSt <= 2'b10; if(iPtpOutReady) // sent / punched begin mPtp_Power <= 1'b1; oPtpChar <= 1'b0; mPtpReady <= 1'b0; mPtpCuSt <= 2'b11; end else if(Ptp_Power_Off) mPtpCuSt <= 2'b00; end 2'b11: // wait for JTAG message complete begin mPtp_Power <= 1'b1; oPtpChar <= 1'b0; mPtpReady <= 1'b0; mPtpCuSt <= 2'b11; if(~ if_SWS) begin mPtpCuSt <= 2'b01; end else if(Ptp_Power_Off) mPtpCuSt <= 2'b00; end endcase end end ///////////////////////////////////////////////////////////////// ////////////////////////////////// // TTY Control Unit ////////////////////////////////// reg [2:0] mTtyCuSt; // Control unit state reg mTtyOutReq; // Set by OTA when character is ready for output to TTY/PC reg mTtyInaRy; // Set by INA that input to A-Reg is ready reg mTtyReady; // Ready flipflop reg mTtyBusy; // Busy flipflop reg Tty_In_Mode; // Set input mode pulse (ocp) reg Tty_Out_Mode; // Set output mode pulse (ocp) reg mTty_WR; // Load TTY Register reg [7:0] iTty; // TTY Register in // CU controller always @(posedge iClk or negedge iMC_n) begin if(! iMC_n) begin oTtyInReq <= 1'b0; oTtyCharO <= 1'b0; mTtyBusy <= 1'b0; //not busy mTtyReady <= 1'b0; //not ready mTtyCuSt <= 3'b000; end else begin case(mTtyCuSt) 3'b000: begin oTtyInReq <= 1'b0; oTtyCharO <= 1'b0; mTtyBusy <= 1'b0; //not busy mTtyReady <= 1'b0; //not ready mTtyCuSt <= 3'b000; if(Tty_In_Mode) mTtyCuSt <= 3'b001; // input mode else if(Tty_Out_Mode) mTtyCuSt <= 3'b010; // output mode end 3'b001: // input mode begin oTtyInReq <= 1'b1; // signal input mode to TTY/PC oTtyCharO <= 1'b0; mTtyBusy <= 1'b0; // not busy mTtyReady <= 1'b0; // not ready mTtyCuSt <= 3'b001; if(iTtyIChar) // character available ? begin // yes oTtyInReq <= 1'b0; mTtyBusy <= 1'b1; //busy mTtyReady <= 1'b0; //ready mTtyCuSt <= 3'b101; // wait for INA ready end else if(Tty_Out_Mode) // ocp out; switch to output mode begin oTtyInReq <= 1'b0; mTtyCuSt <= 3'b010; end end 3'b010: // outputmode, wait for OTA (OTA generates mTtyOutReq when a char is available) begin oTtyInReq <= 1'b0; oTtyCharO <= 1'b0; mTtyReady <= 1'b1; //ready, wait for OTA mTtyBusy <= 1'b0; //not busy mTtyCuSt <= 3'b010; if(mTtyOutReq) // from executed OTA; character in output buffer begin oTtyCharO <= 1'b1; // signal TTY/PC that a char is available mTtyReady <= 1'b0; // not ready; character being transmitted to tty mTtyBusy <= 1'b1; // busy mTtyCuSt <= 3'b011; end else if(Tty_In_Mode) // not busy; ocp in; switch to input node begin mTtyReady <= 1'b0; //not ready mTtyCuSt <= 3'b001; end end 3'b011: // out char being tranfered to tty; wait for accepted signal from TTY/PC begin oTtyInReq <= 1'b0; oTtyCharO <= 1'b1; mTtyReady <= 1'b0; //not ready mTtyBusy <= 1'b1; //busy mTtyCuSt <= 3'b011; if(iTtyOutReady) begin oTtyCharO <= 1'b0; mTtyReady <= 1'b0; mTtyCuSt <= 3'b100; end end 3'b100: // wait for JTAG output message complete begin oTtyInReq <= 1'b0; oTtyCharO <= 1'b0; mTtyReady <= 1'b0; //not ready mTtyBusy <= 1'b1; //busy mTtyCuSt <= 3'b100; if(~ if_SWS) begin mTtyCuSt <= 3'b010; end end 3'b101: // wait for a signal from INA that input char is transfered to A-reg begin oTtyInReq <= 1'b0; // signal input mode to TTY/PC oTtyCharO <= 1'b0; mTtyBusy <= 1'b1; // busy mTtyReady <= 1'b1; // ready mTtyCuSt <= 3'b101; if(mTtyInaRy) begin mTtyReady <= 1'b0; // not ready mTtyBusy <= 1'b0; // not busy mTtyCuSt <= 3'b001; end end endcase end end ///////////////////////////////////////////////////////////////// ////////////////////////////////// // PTR Control Unit ////////////////////////////////// reg [2:0] mPtrCuSt; // Control unit state reg Ptr_Start; // Set start pulse (ocp) reg Ptr_Stop; // Set stop pulse (ocp) reg mPtrInaRy; // Set by INA that input to A-Reg is ready reg mPtrReady; // Ready flipflop // CU controller always @(posedge iClk or negedge iMC_n) begin if(! iMC_n) begin oPtrInReq <= 1'b0; mPtrReady <= 1'b0; //not ready mPtrCuSt <= 3'b000; oPtrTry <= 1'b0; //tranfer to Areg not ready end else begin case(mPtrCuSt) 3'b000: begin oPtrInReq <= 1'b0; mPtrReady <= 1'b0; //not ready oPtrTry <= 1'b0; //tranfer to Areg not ready if(Ptr_Start) mPtrCuSt <= 3'b001; if(Ptr_Stop) mPtrCuSt <= 3'b000; end 3'b001: //start begin oPtrInReq <= 1'b1; // signal to SWITCHES/JTAG: request character mPtrReady <= 1'b0; // not ready oPtrTry <= 1'b0; //tranfer to Areg not ready if(Ptr_Stop && iPtrIChar) // character in buffer and stop (wait for INA) begin oPtrInReq <= 1'b0; mPtrCuSt <= 3'b011; end else if(Ptr_Stop) // stop? begin oPtrInReq <= 1'b0; mPtrCuSt <= 3'b000; end else if(iPtrIChar) // signal from SWITCHES/JTAG: begin //character read and in buffer (if Stop too late, throughput error) oPtrInReq <= 1'b0; mPtrCuSt <= 3'b010; end end 3'b010: //character read and in buffer; wait for INA ready begin oPtrInReq <= 1'b0; mPtrReady <= 1'b1; //set ready oPtrTry <= 1'b0; //tranfer to Areg not ready if(Ptr_Stop) // stop? mPtrCuSt <= 3'b011; else if(mPtrInaRy) // <= from INA when character is transferred to A-reg begin oPtrInReq <= 1'b0; mPtrReady <= 1'b0; mPtrCuSt <= 3'b100; oPtrTry <= 1'b1; //tranfer ready (pulse to FPTR) end end 3'b011: // stop received and character in buffer: wait for INA begin oPtrInReq <= 1'b0; mPtrReady <= 1'b1; //set ready oPtrTry <= 1'b0; //tranfer to Areg not ready if(mPtrInaRy) // <= from INA when character is transferred to A-reg begin mPtrReady <= 1'b0; mPtrCuSt <= 3'b000; oPtrTry <= 1'b1; //tranfer ready (pulse to FPTR) end end 3'b100: //delay an instruction before setting the next input request (trace) begin oPtrInReq <= 1'b0; mPtrReady <= 1'b0; //not ready oPtrTry <= 1'b0; if(Ptr_Stop) // stop? begin oPtrInReq <= 1'b0; mPtrCuSt <= 3'b000; end else if(state==FETCH) begin oPtrInReq <= 1'b0; mPtrCuSt <= 3'b101; end end 3'b101: begin oPtrInReq <= 1'b0; mPtrReady <= 1'b0; //not ready oPtrTry <= 1'b0; //tranfer to Areg not ready if(Ptr_Stop) // stop? begin oPtrInReq <= 1'b0; mPtrCuSt <= 3'b000; end else if(state==FETCH) begin oPtrInReq <= 1'b0; mPtrCuSt <= 3'b001;// proceed end end endcase end end ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ///////////////////////////////////// // RTC Control Unit (Real Time Clock) ///////////////////////////////////// // signals to the CPU-RTC option reg mRtcReady; // Ready flipflop reg mRtcTick; // 20 msec pulse // input signals from CPU-RTC option reg mRtcTickAck; // 20 msec pulse accepted: reset Tick reg mRtcRun; // pulse generated by OCP '20 reg mRtcStop; // pulse generated by OCP '220 reg mRtcRy; // pulse generated by location '61 overflow // RTC internal reg [1:0] mRtcSt; // RTC state register reg [19:0] mRtcCnt; // counter to generate 20 msec pulse (20 bit counter for 24 MHz clock) //reg [20:0] mRtcCnt; // counter to generate 20 msec pulse (21 bit counter for 27 MHz clock) // running with a 24Mhz clock, 20 msec uses 20*24_000 = 480_000 pulses // 480000 decimal is 75300 hexadecimal // 0111 0101 0011 0000 0000 // 1000 1010 1100 1111 1111 // 1+ // 1000 1010 1101 0000 0000 = -75300 = 8ad00 (20 bit counter) // running with a 27Mhz clock, 20 msec uses 20*27_000 = 540_000 pulses // 540000 decimal is 83d60 hexadecimal // 0 1000 0011 1101 0110 0000 // 1 0111 1100 0010 1001 1111 // 1+ // 1 0111 1100 0010 1010 0000 = -83d60 = 17c2a0 (21 bit counter) // RTC states parameter RTC_IDLE = 2'b00; parameter RTC_RUN = 2'b01; parameter RTC_TICK = 2'b10; parameter RTC_RDY = 2'b11; always @(posedge iClk or negedge iMC_n) begin if(! iMC_n) begin mRtcReady <= 0; mRtcTick <= 0; mRtcSt <= 0; mRtcCnt <= 0; end else begin mRtcCnt <= mRtcCnt + 1'b1; mRtcReady <= 0; mRtcTick <= 0; case(mRtcSt) RTC_IDLE: if(mRtcRun) begin mRtcCnt <= 20'h8AD00; // reset 20msec timer (24 MHz clock) //mRtcCnt <= 21'h17C2A0; // reset 20msec timer (27 MHz clock) mRtcSt <= RTC_RUN; end RTC_RUN: begin if(mRtcStop) mRtcSt <= RTC_IDLE; else if(mRtcRy) mRtcSt <= RTC_RDY; else if(! mRtcCnt) // 0 ? begin mRtcCnt <= 20'h8AD00; // reset 20msec timer (24 MHz clock) //mRtcCnt <= 21'h17C2A0; // reset 20msec timer (27 MHz clock) mRtcSt <= RTC_TICK; end end RTC_TICK: // wait for tick accepted to be processd begin mRtcTick <= 1; if(mRtcTickAck) mRtcSt <= RTC_RUN; end RTC_RDY: // wait for reset ready (OCP '20 or OCP '220) begin mRtcReady <= 1; if(mRtcStop) mRtcSt <= RTC_IDLE; if(mRtcRun) begin mRtcCnt <= 20'h8AD00; // reset 20msec timer (24 MHz clock) //mRtcCnt <= 21'h17C2A0; // reset 20msec timer (27 MHz clock) mRtcSt <= RTC_RUN; end end endcase end end ///////////////////////////////////////////////////////////////// // RAM, Memory Address Register(Y), Instruction Register(IR) and the Index Register(X) // iMbr,oMbr,oMaddr,oM_we_n,oM_oe_n: SRAM interface reg mMB_WR; // load MB (Memory Buffer) reg mIR_WR; // load IR (Instruction Register) reg mY_WR; // load Y (Memory Address Register) reg mX_WR; // load X (X register (copy of Mem[0])) reg mC_WR; // load C (C-Bit) reg mEnb_WR; // load ENB (Interrupt Enable Flipflop) reg mSc_WR; // load Sc (Shift Count Register) reg mMsk_WR; // load Msk (Interrupt Mask Register) reg mPme_WR; // load Previous Mode Flipflop reg mExt_WR; // load Extended Mode Flipflop wire [15:0] oMB; wire [15:0] oY; reg [15:0] iY; wire [15:0] oMsk; reg [15:0] iMsk; wire [5:0] oSc; reg [5:0] iSc; reg iC; reg iEnb; reg iExt; wire oPme; wire [15:0] iMbIr; // During IDLE_0 and DECODE oMaddr = 0 to address Xm in order to read Xm and load Xr; // During RTC_0 and RTC_1 oMaddr = '61 to address the RTC location '61; // During the other states, the Y Register is used to address the memory. assign oMaddr = (state == IDLE_0 || state == DECODE) ? 16'h0000 : (state == RTC_0 || state == RTC_1 ) ? 16'h0031 : oY; // Memory Address // During INT state, JST* 63 is loaded into MB and IR; // During the other states, MB and IR are loaded from memory. assign iMbIr = state == INT ? 16'hA033 : iMbr; register #(16) MB (.iClk(iClk), .oQ(oMB), .iD(iMbIr), .iLoad(mMB_WR),.iReset_n(iMC_n)); // Memory Buffer register #(16) IR (.iClk(iClk), .oQ(oIR), .iD(iMbIr), .iLoad(mIR_WR),.iReset_n(iMC_n)); // Instruction Register register #(16) Y (.iClk(iClk), .oQ(oY) , .iD(iY) , .iLoad(mY_WR), .iReset_n(iMC_n)); // Memory Address Register register #(16) X (.iClk(iClk), .oQ(oX) , .iD(iMbr), .iLoad(mX_WR), .iReset_n(iMC_n)); // X register (copy of Mem[0]) register #(1) C (.iClk(iClk), .oQ(oC) , .iD(iC) , .iLoad(mC_WR), .iReset_n(iMC_n)); // C Bit register #(1) ENB (.iClk(iClk), .oQ(oEnb),.iD(iEnb), .iLoad(mEnb_WR),.iReset_n(iMC_n)); // Interrupt Enable FF (1 if enabled) register #(1) EXT (.iClk(iClk), .oQ(oExt),.iD(iExt), .iLoad(mExt_WR),.iReset_n(iMC_n)); // Extended Mode FF (1 if extended) register #(1) PME (.iClk(iClk), .oQ(oPme),.iD(oExt), .iLoad(mPme_WR),.iReset_n(iMC_n)); // Previous Mode FF (1 if extended) register #(6) SC (.iClk(iClk), .oQ(oSc), .iD(iSc) , .iLoad(mSc_WR), .iReset_n(iMC_n)); // Shift Count register #(16) MSK (.iClk(iClk), .oQ(oMsk),.iD(iMsk), .iLoad(mMsk_WR),.iReset_n(iMC_n)); // Mask Register register #(8) TTY (.iClk(iClk), .oQ(oTty),.iD(iTty), .iLoad(mTty_WR),.iReset_n(iMC_n)); // TTY Register register #(8) PTP (.iClk(iClk), .oQ(oPtp),.iD(iPtp), .iLoad(mPtp_WR),.iReset_n(iMC_n)); // PTP Register // Processor sequencer states parameter IDLE_0 = 6'b000000; parameter IDLE = 6'b000001; parameter FETCH = 6'b000010; parameter FETCH1 = 6'b000011; parameter DECODE = 6'b000100; parameter DECODE1 = 6'b000101; parameter DECODE2 = 6'b000110; parameter DECODE3 = 6'b000111; parameter EXE_G00 = 6'b001000; parameter EXE_SH_0 = 6'b001001; parameter EXE_SH_1 = 6'b001010; parameter EXE_G20 = 6'b001011; parameter EXE_G21 = 6'b001100; parameter EXE_G30 = 6'b001101; parameter EXE_G31 = 6'b001110; parameter EXE_OCP = 6'b001111; parameter EXE_SKS = 6'b010000; parameter EXE_INA = 6'b010001; parameter EXE_OTA = 6'b010010; parameter EXE_EAX = 6'b010011; parameter EXE_EAI_0= 6'b010100; parameter EXE_EAI_1= 6'b010101; parameter EXE_EXT = 6'b010110; parameter EXE_EXT_0= 6'b010111; parameter EXE_EXT_1= 6'b011000; parameter EXE_MR_0 = 6'b011001; parameter EXE_MR_1 = 6'b011010; parameter EXE_MR_2 = 6'b011011; parameter INT = 6'b011100; parameter RTC_0 = 6'b011101; parameter RTC_1 = 6'b011110; parameter TYO_POST = 6'b011111; parameter PTP_POST = 6'b100000; parameter EXE_POST = 6'b100001; parameter ERROR = 6'b100011; reg mStop; // set to 1 if the CPU has stop at the end of the execution of an instruction reg [5:0] state, nextstate; // latch to stop exection at the end of the current instruction // the request to stop can come in at any stage of the execution of an instruction always @(*) begin if(iStep || iStop) mStop = 1; if(state == IDLE_0) mStop = 0; end assign oRunning = (state == IDLE || state == ERROR) ? 1'b0 : 1'b1; // note: when resetting the CPU with MC, state is pushed in IDLE_0 to load Xr from M[0]. // => running led switches on for a moment. // next, the CPU state machine pushed the CPU in state IDLE, waiting // for a run or step pulse. /////////////////////////////////////////////////////////////////////////////////////// // Interrupt Enable logic // When ENB is executed, the interrupt must be enabled with a delay of one instruction reg [1:0] mEnbSt; //state reg mEnb; //Enable signal from ENB instruction reg mInh; //Inhibit signal from INH instruction and from Interrupt accept // Mask bit assignment parameter MSK_PTR = 16'b0000000010000000; // PTR bit 9 (oMsk[7]) parameter MSK_PTP = 16'b0000000001000000; // PTP bit 10 (oMsk[6]) parameter MSK_TTY = 16'b0000000000100000; // TTY bit 11 (oMsk[5]) parameter MSK_CLK = 16'b0000000000000001; // CLK bit 16 (oMsk[0]) always @(posedge iClk or negedge iMC_n) begin if(! iMC_n) begin iEnb <= 1'b0; mEnb_WR <= 1'b0; mEnbSt <= 2'b00; end else begin case(mEnbSt) 2'b00: begin iEnb <= 1'b0; mEnb_WR <= 1'b0; mEnbSt <= 2'b00; if(mInh) mEnb_WR <= 1'b1; if(mEnb) mEnbSt <= 2'b01; end 2'b01:// ENB being executed; wait for next instruction begin iEnb <= 1'b0; mEnb_WR <= 1'b0; if(state == FETCH) mEnbSt <= 2'b10; end 2'b10:// instruction after ENB is being executed // next check for interrupt at next instruction, so ENB can be set // in case the instr after ENB is not an INH (that signal might not be // there yet, but then it is captured at state 00) begin iEnb <= 1'b0; mEnb_WR <= 1'b1; mEnbSt <= 2'b00; if(! mInh) iEnb <= 1'b1; end endcase end end // Standard Interrupt Line assign oPil = oEnb & ( (mTtyReady & oMsk[5]) | (mPtrReady & oMsk[7]) | (mPtpReady & oMsk[6]) | (mRtcReady & oMsk[0]) ); /////////////////////////////////////////////////////////////////////////////////////// // Extended Addressing mode logic // When EXA, an interrupt or a Mode restore from OTK, => mode is extended // DXA or a Mode restore from OTK, resets to normal mode. //iExt; //Set extended mode (from EXA instruction or from OTK of with an interrupt) reg mExa; //Request to set extended mode (from EXA instruction or from OTK of with an interrupt) //The Ext FF is set. reg mDxa; //Request to disable extended mode (from DXA instruction or from OTK) //After the 1st JMP after a mDxa signal the Ext FF is reset. reg [1:0] mExtSt; //state always @(posedge iClk or negedge iMC_n) begin if(! iMC_n) begin iExt <= 1'b0; mExt_WR <= 1'b0; mExtSt <= 2'b00; end else begin case(mExtSt) // Set Normal mode 2'b00: begin iExt <= 1'b0; mExt_WR <= 1'b1; mExtSt <= 2'b01; end 2'b01: begin // Normal Mode iExt <= 1'b0; mExt_WR <= 1'b0; mExtSt <= 2'b01; if(mExa) begin // set Exted Mode iExt <= 1'b1; mExt_WR <= 1'b1; mExtSt <= 2'b10; end end 2'b10: begin // Extended Mode iExt <= 1'b0; mExt_WR <= 1'b0; mExtSt <= 2'b10; if(mDxa) begin // request to reset Exted Mode mExtSt <= 2'b11; end end 2'b11: begin // Reset to Normal mode after JMP iExt <= 1'b0; mExt_WR <= 1'b0; mExtSt <= 2'b11; if(opcode == MR_JMP) // EA for JMp is already calculated! begin mExt_WR <= 1'b1; mExtSt <= 2'b01; end end endcase end end /////////////////////////////////////////////////////////////////////////////////////// // OpCode Decoder // Instruction Classes (toplevel) parameter GENERIC = 4'b0000; parameter MR_JMP = 4'b0001; parameter MR_LDA = 4'b0010; parameter MR_ANA = 4'b0011; parameter MR_STA = 4'b0100; parameter MR_ERA = 4'b0101; parameter MR_ADD = 4'b0110; parameter MR_SUB = 4'b0111; parameter MR_JST = 4'b1000; parameter MR_CAS = 4'b1001; parameter MR_IRS = 4'b1010; parameter MR_IMA = 4'b1011; parameter IOP = 4'b1100; parameter MR_XXX = 4'b1101; // LDX, STX // Generic instruction classes parameter G00 = 3'b000; parameter G01 = 3'b001; parameter SHR = 3'b010; parameter SHL = 3'b011; parameter G20 = 3'b100; parameter G21 = 3'b101; parameter G30 = 3'b110; parameter G31 = 3'b111; // Shift Functions (mShift) parameter LLogL = 4'b1000; //Left Logical Long (LLL) parameter RLogL = 4'b0000; //Right Logical Long (LRL) parameter LAriL = 4'b1001; //Left Aritmetic Long (LLS) parameter RAriL = 4'b0001; //Right Arithmetic Long (LRS) parameter LRotL = 4'b1010; //Left Rotate Long (LLR) parameter RRotL = 4'b0010; //Right Rotate Long (LRR) parameter LLogS = 4'b1100; //Left Logical Short (LGL) parameter RLogS = 4'b0100; //Right Logical Short (LGR) parameter LAriS = 4'b1101; //Left Aritmetic Short (ALS) parameter RAriS = 4'b0101; //Right Aritmetic Short (ARS) parameter LRotS = 4'b1110; //Left Rotate Short (ALR) parameter RRotS = 4'b0110; //Right Rotate Short (ARR) wire [3:0] opcode = oIR[13:10]; // toplevel instruction classes wire [2:0] gcode = {oIR[15:14],oIR[9]}; // generic instruction classes wire [3:0] mShift = oIR[9:6]; // shift function wire flag = oMB[15]; // flag bit in MR instruction (bit 15, asking for indirect addressing) wire tag = oMB[14]; // tag bit in MR instruction (bit 14, asking for indexing) always @(*) begin oM_we_n = 1; oM_oe_n = 1; oMbr = 0; oError = 0; mMB_WR=0; mIR_WR=0; oPC = 0; oPC_WR = 0; oPC_INC1 = 0; oPC_INC2 = 0; mX_WR = 0; iY = iPC; mY_WR=0; oA=0; oA_WR=0; oB=0; oB_WR=0; iC=0; mC_WR=0; mPme_WR=0; mInh=0; mEnb=0; mExa=0; mDxa=0; mSc_WR=0; iSc = 0; mMsk_WR=0; iMsk=0; // TTY Tty_In_Mode = 0; Tty_Out_Mode = 0; mTtyInaRy=0; mTtyOutReq=0; iTty=0; mTty_WR=0; // Papertape puncher Ptp_Power_On=0; Ptp_Power_Off=0; iPtp=0 ; mPtpOutReq=0; mPtp_WR=0; // Papertape reader Ptr_Start=0; Ptr_Stop=0; mPtrInaRy=0; // RTC mRtcTickAck=0; mRtcRun=0; mRtcStop=0; mRtcRy=0; //////////////////// nextstate=state; case (state) IDLE_0: begin // start IDLING, but first set X (to allow showing X via the Console). // oRunning still 1 in order to be connected with RAM oM_oe_n = 0; // oMaddr set to 0 by multiplexer; read Mem address 0 mX_WR = 1; // and load into X-Register nextstate = IDLE; end IDLE: begin if(iStep || iRun) begin iY=iPC; mY_WR = 1; // Set Y register; pointing to instruction to execute nextstate = FETCH; end else nextstate = IDLE; end FETCH: begin if(oPil) nextstate = INT; else if (mRtcTick) begin mRtcTickAck=1; // Clock tick accepted nextstate=RTC_0; end else nextstate = FETCH1; end FETCH1: begin oM_oe_n = 0; // read memory word, addressed by Y (Y is set in IDLE or EXE_POST) mMB_WR = 1; // put in Memory Buffer => flag/tag mIR_WR = 1; // and put in Instruction Register oPC_INC1 = 1; // PC=PC+1 nextstate = DECODE; end INT: begin // interrupt accepted: execute INH, JST* '63 mInh=1; // Interrupt accepted; deactivate Interupt Enable mMB_WR = 1; // JST* 63 into MB (input set by multiplexer) mIR_WR = 1; // JST* 63 into IR (input set by multiplexer) mPme_WR = 1; // Ext => Pme (save mode) mExa = 1; // request to set exteded mode nextstate = DECODE; end RTC_0: begin // process an RTC 20 msec Tick mMB_WR=1; // read memory word '61 into MB oM_oe_n = 0; nextstate = RTC_1; end RTC_1: begin oM_we_n = 0; // write memory word enable oMbr=oMB+1'b1; // increment MB and write back to word '61 in memory if(! oMbr) mRtcRy=1; // signal word '61 overflow nextstate = FETCH; // and continue end DECODE: begin mX_WR = 1; // load Xr register with word 0 (Xm); oM_oe_n = 0; // oMaddr set to addr 0 (Xm) by multiplexer mY_WR = 1; // load Y Register with operand address iY = { ((oIR[9]) ? oY[15:9] : 7'b0000000) , oIR[8:0]}; // operand address case(opcode) GENERIC: // 0 nextstate = DECODE1; // generic/shift instruction classes MR_JMP, MR_LDA, MR_ANA, MR_STA, MR_ERA, MR_ADD, MR_SUB, MR_JST, MR_CAS, MR_IRS, MR_IMA: nextstate = DECODE2; // Memory Reference Instructions IOP: //14 nextstate = DECODE3; // IO Instructions MR_XXX: //15 ldx stx (no tag bit, LDX: tag bit is 1; STX: tag bit is 0) begin if(flag) // indirect addressing requested nextstate = EXE_EAI_0; else nextstate = EXE_MR_0; //Y register is operand address; exe the instruction end default: // error nextstate = ERROR; endcase end DECODE1: begin case(gcode) // generic/shift instruction classes G00: nextstate = EXE_G00; G01: begin if(oIR[8:0] == 9'o001) begin // INH mInh=1; // deactivate Interupt Enable nextstate = EXE_POST; end else nextstate = ERROR; end SHR: nextstate = EXE_SH_0; SHL: nextstate = EXE_SH_0; G20: nextstate = EXE_G20; G21: nextstate = EXE_G21; G30: nextstate = EXE_G30; G31: nextstate = EXE_G31; default: nextstate = ERROR; endcase end DECODE2: begin // Memory Reference Instructions (calculate effective address) if(oExt) // Extended Mode ? nextstate = EXE_EXT; else if(tag) // Normal mode: tag and flag from MB nextstate = EXE_EAX; // normal indexing requested else if(flag) // normal indirect addressing requested nextstate = EXE_EAI_0; else nextstate = EXE_MR_0; //Y register is operand address; exe the instruction end DECODE3: begin // IO Instructions case(oIR[15:14]) 2'b00://OCP nextstate = EXE_OCP; 2'b01://SKS nextstate = EXE_SKS; 2'b10://INA nextstate = EXE_INA; 2'b11://OTA,SMK,OTK begin if(oIR[9:0] == 10'o1020) begin // OTK // note: because shift instructions are not // interrupted, SC is not save by INK, and // not restored by OTK mC_WR = 1; //mSc_WR = 1; iC = iA[15]; // restore C-bit //iSc = {1'b1, iA[4:0]}; if(iA[13]) mExa=1; // request to set extended mode else mDxa=1; // request reset of EXT FF nextstate = EXE_POST; end else if(oIR[9:0] == 10'o0020) begin // SMK: set Mask register from Register A // A bit set in this register enables the // interrupt for the device using that bit // Standard bit allocation is as follows: // bit 9 : papertape reader (A[7]) // bit 10 : papertape puncher (A[6]) // bit 11 : tty (A[5]) // bit 16 : real time clock (A[0]) mMsk_WR = 1; iMsk = iA; // set Mask register nextstate = EXE_POST; end else nextstate = EXE_OTA; end endcase end // EXE_EAX: // index the address as available in the Y Register (X set in DECODE) begin mY_WR = 1; iY = {2'b00, oY[13:0] + oX[13:0]}; // execute index operation if(flag) // indirect addressing requested as well nextstate = EXE_EAI_0; else nextstate= EXE_MR_0; //Y register is operand address; exe the instruction end EXE_EAI_0: // indirect addressing step 1: get word addressed by Y in MB begin // set the new tag and flag mMB_WR = 1; // put into MB oM_oe_n = 0; // the read memory word nextstate = EXE_EAI_1; end EXE_EAI_1: // indirect addressing step 2: put word in Y; new tag/flag set begin mY_WR = 1; iY = {2'b00, oMB[13:0]}; // flag=MB[15], tag=MB[14] set by assign if(tag) nextstate=EXE_EAX; // indexing requested else if(flag) // indirect addressing requested nextstate = EXE_EAI_0; else nextstate= EXE_MR_0; //Y register is operand address; exe the instruction end EXE_EXT: // Extended Mode (no tag) begin if(flag) // Extended Mode indirect addressing requested nextstate = EXE_EXT_0; else begin if(oIR[14]) // Extended Mode indexing (original tag in instruction (post indexing)) begin mY_WR = 1; iY = {1'b0, oY[14:0] + oX[14:0]}; // execute index operation end nextstate= EXE_MR_0; //Y register is operand address; exe the instruction end end EXE_EXT_0: // Extended Mode indirect addressing step 1 begin // read content of indirect address into MB and set the new flag mMB_WR = 1; // put into MB oM_oe_n = 0; // the read memory word nextstate = EXE_EXT_1; end EXE_EXT_1: // Extended Mode indirect addressing step 2: put word in Y; new flag set begin mY_WR = 1; iY = {1'b0, oMB[14:0]}; // flag=MB[15], set by assign nextstate = EXE_EXT; end EXE_G00: // Generic 00 begin case(oIR[8:0]) 9'O000: // HLT nextstate = IDLE_0; 9'O011: // DXA, disable extended addressing begin mDxa=1; // request disable Extended Mode (activated after next JMP) nextstate = EXE_POST; end 9'O013: // EXA, enable extended addressing begin mExa=1; // request to activate Extended Mode nextstate = EXE_POST; end 9'O043: // INK // Note: SC is not save because the shift instructions // are not interrupted begin oA_WR = 1; // oA={oC,1'b0,oPme,8'b0000000000,oSc[4:0]}; oA = {oC,1'b0,oPme,13'b000000000000000}; nextstate = EXE_POST; end 9'O201: // IAB begin oB_WR = 1; oA_WR = 1; oB = iA; oA = iB; nextstate = EXE_POST; end 9'O401: // ENB begin mEnb = 1; // activate Interrupt Enable nextstate = EXE_POST; end default: nextstate = ERROR; endcase end EXE_SH_0: // Shift/rotate //speed optimalisation is possible with additional logic f.i. : // 100 000 is 32 or -32 or 0 for rotates // so LLL 32 or LRL 32 will make A=0, and B=0 and LRL 32 or LRR 32 do not change A an B, etc. // these optimisations are not implemented, and the shift operation are also not interrupted. // So for INK/OTK it does not make sense to save/restore SC begin // prepare shift if(oIR[5:0] != 6'b000000) begin iSc = oIR[5:0]; mSc_WR = 1; // load shift count register iC = 1'b0; mC_WR = 1; // reset C Bit nextstate = EXE_SH_1; end else nextstate = EXE_POST; end EXE_SH_1: // shift 1 bit; stop shifting when Shift Count == 0 begin oA_WR = 1; mSc_WR = 1; iSc=oSc+1'b1; case(mShift) //long shifts LLogL: begin //LLL Long Logical Left Shift oB_WR=1; mC_WR=1; iC=iA[15]; oA[15:0] = {iA[14:0],iB[15]}; oB[15:0] = {iB[14:0],1'b0}; end RLogL: begin //LRL Long Logical Right Shift oB_WR=1; mC_WR=1; iC=iB[0]; oB[15:0] = {iA[0],iB[15:1]}; oA[15:0] = {1'b0,iA[15:1]}; end LAriL: begin //LLS Long Arithmetic Left Shift oB_WR=1; if(iA[15] ^ iA[14]) begin mC_WR=1; iC=1'b1; end oA[15:0]= {iA[14:0],iB[14]}; oB[15:0]= {iB[15],iB[13:0],1'b0}; end RAriL: begin //LRS Long Arithmetic Right Shift oB_WR=1; mC_WR=1; iC = iB[0]; oB[15:0] = {iB[15],iA[0],iB[14:1]}; oA[15:0] = {iA[15],iA[15:1]}; end LRotL: begin // LLR Long Left Rotate oB_WR=1; mC_WR=1; iC = iA[15]; oA[15:0] = {iA[14:0],iB[15]}; oB[15:0] = {iB[14:0],iA[15]}; end RRotL: begin // LRR Long Right Rotate oB_WR=1; mC_WR=1; iC = iB[0]; oB[15:0] = {iA[0],iB[15:1]}; oA[15:0] = {iB[0],iA[15:1]}; end // short shifts LLogS: begin //LGL Logical Left Shift mC_WR=1; iC=iA[15]; oA[15:0] = {iA[14:0],1'b0}; end RLogS: begin //LGR Logical Right Shift mC_WR=1; iC=iA[0]; oA[15:0] = {1'b0,iA[15:1]}; end LAriS: begin //ALS Arithmetic Left Shift (start with C=0!!) if(iA[15] ^ iA[14]) begin mC_WR=1; iC=1'b1; end oA[15:0] = {iA[14:0],1'b0}; end RAriS: begin //ARS Arithmetic Right Shift mC_WR=1; iC = iA[0]; oA[15:0] = {iA[15],iA[15:1]}; end LRotS: begin //ALR Logical Left Rotate mC_WR=1; iC = iA[15]; oA[15:0] = {iA[14:0],iA[15]}; end RRotS: begin //ARR Logical Right Rotate mC_WR=1; iC = iA[0]; oA[15:0] = {iA[0],iA[15:1]}; end default: nextstate = ERROR; endcase if(iSc == 5'b00000) nextstate = EXE_POST; // shift ready else nextstate = EXE_SH_1; // repeat end EXE_G20: // Generaic 20 begin case(oIR[8:0]) 9'O000: begin // SKP oPC_INC1=1; nextstate = EXE_POST;; end 9'O001: begin// SRC (skip if C==0) if(! oC) oPC_INC1=1; nextstate = EXE_POST; end 9'O002: begin // SR4 if(! iSense[0]) oPC_INC1=1; nextstate = EXE_POST; end 9'O004: begin // SR3 if(! iSense[1]) oPC_INC1=1; nextstate = EXE_POST; end 9'O010: begin // SR2 if(! iSense[2]) oPC_INC1=1; nextstate = EXE_POST; end 9'O020: begin // SR1 if(! iSense[3]) oPC_INC1=1; nextstate = EXE_POST; end 9'O036: begin // SSR (all reset) if(! iSense[3:0]) oPC_INC1=1; nextstate = EXE_POST; end 9'O040: begin // SZE if(! iA[15:0]) oPC_INC1=1; nextstate = EXE_POST; end 9'O100: begin // SLZ if(! iA[0]) oPC_INC1=1; nextstate = EXE_POST; end 9'O400: begin // SPL if(! iA[15]) oPC_INC1=1; nextstate = EXE_POST; end default: nextstate = ERROR; endcase end EXE_G21: // Generic 21 begin case(oIR[8:0]) 9'O000: begin // NOP nextstate = EXE_POST; end 9'O001: begin // SSC (skip if C==1) if(oC) oPC_INC1=1; nextstate = EXE_POST; end 9'O002: begin // SS4 if(iSense[0]) oPC_INC1=1; nextstate = EXE_POST; end 9'O004: begin // SS3 if(iSense[1]) oPC_INC1=1; nextstate = EXE_POST; end 9'O010: begin // SS2 if(iSense[2]) oPC_INC1=1; nextstate = EXE_POST; end 9'O020: begin // SS1 if(iSense[3]) oPC_INC1=1; nextstate = EXE_POST; end 9'O036: begin // SSS (any set) if(iSense[3:0]) oPC_INC1=1; nextstate = EXE_POST; end 9'O040: begin // SNZ if(iA[15:0]) oPC_INC1=1; nextstate = EXE_POST; end 9'O100: begin // SLN if(iA[0]) oPC_INC1=1; nextstate = EXE_POST; end 9'O400: begin // SMI if(iA[15]) oPC_INC1=1; nextstate = EXE_POST; end default: nextstate = ERROR; endcase end EXE_G30: // Generic 30 begin case(oIR[8:0]) 9'o024: begin // CHS (complement sign A) oA_WR = 1; oA = { (~ iA[15]), iA[14:0]}; nextstate = EXE_POST; end 9'o040: begin // CRA (clear A) oA_WR = 1; oA[15:0] = 16'h0000; nextstate = EXE_POST; end 9'o100: begin // SSP (set sign A plus) oA_WR = 1; oA = { 1'b0, iA[14:0]}; nextstate = EXE_POST; end 9'o200: begin // RCB (reset C) iC = 1'b0; mC_WR = 1; nextstate = EXE_POST; end 9'o320: begin // CSA oA_WR = 1; mC_WR = 1; iC = iA[15]; oA = { 1'b0, iA[14:0]}; nextstate = EXE_POST; end 9'o401: begin // CMA oA_WR = 1; oA[15:0] = ~ iA[15:0]; nextstate = EXE_POST; end 9'o407: begin // TCA (140407 iso 141407) oA_WR = 1; oA = (~ iA) + 1'b1; nextstate = EXE_POST; end 9'o500: begin // SSM oA_WR = 1; oA = {1'b1, iA[14:0]}; nextstate = EXE_POST; end 9'o600: begin // SCB mC_WR = 1; iC = 1'b1; nextstate = EXE_POST; end default: nextstate = ERROR; endcase end EXE_G31: // Generic 31 begin case(oIR[8:0]) 9'o044: begin // CAR oA_WR = 1; oA[15:0] = {iA[15:8],8'h00}; nextstate = EXE_POST; end 9'o050: begin // CAL oA_WR = 1; oA[15:0] = {8'h00,iA[7:0]}; nextstate = EXE_POST; end 9'o140: begin // ICL oA_WR = 1; oA[15:0] = {8'h00,iA[15:8]}; nextstate = EXE_POST; end 9'o206: begin // AOA oA_WR = 1; mC_WR = 1; oA=iA + 1'b1; iC= (iA[15] ^ 1'b1) & (iA[15] ^ oA[15]); nextstate = EXE_POST; end 9'o216: begin // ACA oA_WR = 1; mC_WR = 1; oA = iA+oC; iC= (iA[15] ^ oC) & (iA[15] ^ oA[15]); nextstate = EXE_POST; end 9'o240: begin // ICR oA_WR = 1; oA[15:0] = {iA[7:0],8'h00}; nextstate = EXE_POST; end 9'o340: begin // ICA oA_WR = 1; oA[15:0] = {iA[7:0],iA[15:8]}; nextstate = EXE_POST; end default: nextstate = ERROR; endcase end EXE_OCP: begin case(oIR[9:0]) // for the TTY only keyboard/printer support is implemented !! 10'o0004://Enable TTY in Input mode begin Tty_In_Mode = 1; // Set input mode nextstate = EXE_POST; end 10'o0104://Enable TTY in Output mode begin Tty_Out_Mode = 1; // Set output mode nextstate = EXE_POST; end 10'o0001://Start Papertape reader begin Ptr_Start=1; nextstate = EXE_POST; end 10'o0101://Stop Papertape reader begin Ptr_Stop=1; nextstate = EXE_POST; end 10'o0002://Enable Papertape puncher (power on) begin Ptp_Power_On=1; nextstate = EXE_POST; end 10'o0102://Papertape puncher power off begin Ptp_Power_Off=1; nextstate = EXE_POST; end 10'o0020://Reset RTClock interrupt and run clock begin mRtcRun = 1; nextstate = EXE_POST; end 10'o0220://Reset RTClock interrupt and stop clock begin mRtcStop = 1; nextstate = EXE_POST; end default: nextstate = ERROR; endcase end EXE_SKS: begin case(oIR[9:0]) // for the TTY only keyboard/printer support is implemented !! 10'o0004://Skip if TTY is ready begin if(mTtyReady) oPC_INC1=1; nextstate = EXE_POST; end 10'o0104://Skip if TTY is not busy begin if(~ mTtyBusy) oPC_INC1=1; nextstate = EXE_POST; end 10'o0404://Skip if TTY is not interrupting begin if(! (mTtyReady & oMsk[5])) oPC_INC1=1; nextstate = EXE_POST; end 10'o0001://Skip if Papertape reader is ready begin if(mPtrReady) oPC_INC1=1; nextstate = EXE_POST; end 10'o0401://Skip if Papertape reader is not interrupting begin if(! (mPtrReady & oMsk[7])) oPC_INC1=1; nextstate = EXE_POST; end 10'o0002://Skip if Papertape puncher is ready begin if(mPtpReady) oPC_INC1=1; nextstate = EXE_POST; end 10'o0102://Skip if Papertape puncher power is on begin if(mPtp_Power) oPC_INC1=1; nextstate = EXE_POST; end 10'o0402://Skip if Papertape puncher is not interrupting begin if(! (mPtpReady & oMsk[6])) oPC_INC1=1; nextstate = EXE_POST; end 10'o020://skip if RTC is not interrupting begin if(! (mRtcReady & oMsk[0])) oPC_INC1=1; nextstate = EXE_POST; end default: nextstate = ERROR; endcase end EXE_INA: begin case(oIR[9:0]) // for the TTY only keyboard/printer support is implemented !! 10'o0004://Input to A if TTY is ready (OR to bits 7:0) begin if(mTtyReady) begin oA_WR=1; oA[15:0] = {iA[15:8],1'b1, (iA[6:0] | TtyCharIn[6:0])}; oPC_INC1=1; mTtyInaRy =1; end nextstate = EXE_POST; end 10'o1004://Clear A and input to A if TTY is ready begin if(mTtyReady) begin oA_WR=1; oA[15:0] = {8'h00,1'b1,TtyCharIn[6:0]}; oPC_INC1=1; mTtyInaRy =1; end nextstate = EXE_POST; end 10'o0001://Input to A if Papertape reader is ready (OR to bits 7:0) begin if(mPtrReady) begin oA_WR=1; oA[15:0] = {iA[15:8],(iA[7:0] | PtrCharIn[7:0])}; oPC_INC1=1; mPtrInaRy =1; end nextstate = EXE_POST; end 10'o1001://Input to A if Papertape reader is ready (OR to bits 7:0) begin if(mPtrReady) begin oA_WR=1; oA[15:0] = {8'h00,PtrCharIn[7:0]}; oPC_INC1=1; mPtrInaRy =1; end nextstate = EXE_POST; end default: nextstate = ERROR; endcase end EXE_OTA: begin case(oIR[9:0]) // for the TTY only keyboard/printer support is implemented !! 10'o0004://Output A to TTY if ready begin if(mTtyReady) begin mTty_WR = 1; iTty = iA[7:0]; // load TTY Register mTtyOutReq=1; // signal char output oPC_INC1=1; nextstate = TYO_POST; // superfluous ? <<<<<<<<<<<<<<<<<< end else nextstate = EXE_POST; end 10'o0002://Output A to Papertape puncher if ready begin if(mPtpReady) begin mPtp_WR = 1; iPtp = iA[7:0]; // load PTP Register mPtpOutReq=1; // signal char output oPC_INC1=1; // skip nextstate = PTP_POST; // superfluous ? <<<<<<<<<<<<<<<<<< end else nextstate = EXE_POST; end default: nextstate = ERROR; endcase end EXE_MR_0: // Memory Reference Instructions begin case(opcode) MR_JMP: begin oPC = oY; // route effective address to the PC oPC_WR = 1; // and set the PC nextstate = EXE_POST; end MR_LDA: begin // Y Register contains effective address oM_oe_n = 0; // read memory word oA = iMbr; oA_WR = 1; // and put into A nextstate = EXE_POST; end MR_STA: begin // Y Register contains effective address oM_we_n = 0; // write memory word enable oMbr = iA; nextstate = EXE_POST; end MR_ADD: begin oM_oe_n = 0; // read memory word oA_WR = 1; // set A mC_WR = 1; // set C oA=iA+iMbr; iC= (iA[15] ^ (~ iMbr[15])) & (iA[15] ^ oA[15]); nextstate = EXE_POST; end MR_SUB: begin oM_oe_n = 0; // read memory word oA_WR = 1; // set A mC_WR = 1; // set C oA=iA-iMbr; iC= (iA[15] ^ iMbr[15]) & (( ~ iMbr[15]) ^ oA[15]); nextstate = EXE_POST; end MR_ANA: begin oM_oe_n = 0; // read memory word oA_WR = 1; // set A oA=iA & iMbr; nextstate = EXE_POST; end MR_ERA: begin oM_oe_n = 0; // read memory word oA_WR = 1; // set A oA=iA ^ iMbr; nextstate = EXE_POST; end MR_JST, MR_CAS, MR_IRS, MR_IMA: begin mMB_WR=1; oM_oe_n = 0; // read memory word into MB nextstate = EXE_MR_1; end MR_XXX: begin if(oIR[14]) begin // LDX mMB_WR=1; oM_oe_n = 0; // read memory word from EA into MB nextstate = EXE_MR_1; end else begin // STX oM_we_n = 0; // write memory word enable oMbr = oX; nextstate = EXE_POST; end end default: nextstate = ERROR; endcase end EXE_MR_1: // Memory Reference Instructions begin case(opcode) MR_CAS: begin oA = iA - oMB; if(iA[15] ^ oMB[15]) // different signs begin if(iA[15]) oPC_INC2=1; // Areg < M end // Areg > M else // equal signs if(! oA[15:0]) oPC_INC1=1; // Areg and M equal else if(oA[15]) oPC_INC2=1; // sign negative => < nextstate = EXE_POST; end MR_JST: begin oM_we_n = 0; // write memory word enable if(oExt) // Extended Mode ? oMbr = {oMB[15],iPC[14:0]}; // store PC (15bit) in EA (flag untouched) else // normal mode oMbr = {oMB[15:14],iPC[13:0]}; // store PC (15bit) in EA (flag,tag untouched) oPC=oY+1'b1; oPC_WR = 1; // and set the PC to Eff Addr + 1 nextstate = EXE_POST; end MR_IRS: begin oM_we_n = 0; // write memory word enable oMbr=oMB+1'b1; // increment and write back if(! oMbr) oPC_INC1=1; nextstate = EXE_POST; end MR_IMA: begin oM_we_n = 0; // write memory word enable oMbr = iA; // write A to memory nextstate = EXE_MR_2; end MR_XXX: begin // LDX: mY_WR=1; iY=16'h0000; // and set Y to 0 nextstate = EXE_MR_2; end default: nextstate = ERROR; endcase end EXE_MR_2: // Memory Reference Instructions begin case(opcode) MR_IMA: begin oA_WR = 1; // set A with content of MB oA=oMB; nextstate = EXE_POST; end MR_XXX: begin // LDX: store MB into address 0 oM_we_n = 0; // write memory word enable oMbr = oMB; // put MB at word 0 nextstate = EXE_POST; end default: nextstate = ERROR; endcase end TYO_POST: //this handshake cycle for savety, but may not be necessary begin if(oTtyCharO) // JTAG informed begin mTtyOutReq=0; // signal char output nextstate = EXE_POST; end else begin mTtyOutReq=1; // continue to signal char output nextstate = TYO_POST; end end PTP_POST: //this handshake cycle for savety, but may not be necessary begin if(oPtpChar) // JTAG informed begin mPtpOutReq=0; // signal char output nextstate = EXE_POST; end else begin mPtpOutReq=1; // continue to signal char output nextstate = PTP_POST; end end EXE_POST: begin iY=iPC; mY_WR = 1; // Set Y register; pointing to instruction to execute if(mStop) // panel stop or HLT? nextstate = IDLE_0; else if(iPC == iPR) // Preset Stop ?? nextstate = IDLE_0; else nextstate = FETCH; end ERROR: // CPU entered an error state begin oError = 1; nextstate = ERROR; end default: begin // error nextstate = ERROR; end endcase end always @(posedge iClk or negedge iMC_n) begin if(! iMC_n) state <= IDLE_0; else state <= nextstate; end endmodule