// Toplevel module of the FPGA implementation of a 32K Honeywell H316/516 minicomputer // This module integrates the CPU/CU module with the Controler and Memory as well as // the JTAG interface which takes care of the link to a personal Computer. // // Name : X16_04.v (02=>03=>04) // Version: 04 // Date : 07-10-2011 // Author : Theo Engel // Contact: Info@theoengel.nl // The toplevel module, integrating the CPU, RAM, Control, etc. also defines the interface signals // of the FPGA to the development board. These signals must be assigned to pins of the FPGA. // // version 03: wiring added for mPTry // version 04: same code as version 03 // Cpu module changed. // 03 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. module X16 ( // interface signals / pins //////////////////// Clock Input //////////////////// CLOCK_24, // 24 MHz //CLOCK_27, // 27 Mhz //CLOCK_50, // 50 MHz //////////////////// Push Buttons //////////////////// KEY, // Pushbutton[3:0] //////////////////// Switch //////////////////// SW, // Toggle Switch[9:0] //////////////////// 7-SEG Display //////////////////// HEX0, // Seven Segment Digit 0 HEX1, // Seven Segment Digit 1 HEX2, // Seven Segment Digit 2 HEX3, // Seven Segment Digit 3 //////////////////////// LEDs //////////////////////// LEDG, // LED Green[7:0] LEDR, // LED Red[9:0] //////////////////// SRAM Interface //////////////// SRAM_DQ, // SRAM Data bus 16 Bits SRAM_ADDR, // SRAM Address bus 18 Bits SRAM_UB_N, // SRAM High-byte Data Mask SRAM_LB_N, // SRAM Low-byte Data Mask SRAM_WE_N, // SRAM Write Enable SRAM_CE_N, // SRAM Chip Enable SRAM_OE_N, // SRAM Output Enable //////////////////// USB JTAG link //////////////////// TDI, // CPLD -> FPGA (data in) TCK, // CPLD -> FPGA (clk) TCS, // CPLD -> FPGA (CS) TDO // FPGA -> CPLD (data out) ); // Development Board Interface //////////////////////// Clock Input //////////////////////// input [1:0] CLOCK_24; // 24 MHz // //input [1:0] CLOCK_27; // 27 MHz // //input [1:0] CLOCK_50; // 50 MHz // //////////////////////// Push Button //////////////////////// input [3:0] KEY; // Pushbutton[3:0] //////////////////////// Switch //////////////////////// input [9:0] SW; // Toggle Switch[9:0] //////////////////////// 7-SEG Dispaly //////////////////////// output [6:0] HEX0; // Seven Segment Digit 0 output [6:0] HEX1; // Seven Segment Digit 1 output [6:0] HEX2; // Seven Segment Digit 2 output [6:0] HEX3; // Seven Segment Digit 3 //////////////////////////// LED //////////////////////////// output [7:0] LEDG; // LED Green[7:0] output [9:0] LEDR; // LED Red[9:0] //////////////////////// SRAM Interface //////////////////////// inout [15:0] SRAM_DQ; // SRAM Data bus 16 Bits output [17:0] SRAM_ADDR; // SRAM Address bus 18 Bits output SRAM_UB_N; // SRAM High-byte Data Mask output SRAM_LB_N; // SRAM Low-byte Data Mask output SRAM_WE_N; // SRAM Write Enable output SRAM_CE_N; // SRAM Chip Enable output SRAM_OE_N; // SRAM Output Enable //////////////////////// USB JTAG link ///////////////////////// input TDI; // CPLD -> FPGA (data in) input TCK; // CPLD -> FPGA (clk) input TCS; // CPLD -> FPGA (CS) output TDO; // FPGA -> CPLD (data out) ///////////////////////////////////////////////////////////////////// // USB JTAG wire [7:0] mRXD_DATA,mTXD_DATA; wire mRXD_Ready,mTXD_Done,mTXD_Start; wire mTCK; // SRAM: uses the 1st 32K words; so the address range is [14:0] // bit 15 is set to 0 either by the cpu or the panel when addressing memory wire [17:0] oSR_ADDR; // 16 bit word address (256k word memory) wire [15:0] oSR_DATA_TO_RAM, iSR_DATA_FROM_RAM; wire oSR_OE_N, oSR_WE_N; assign oSR_ADDR[17]=0; assign oSR_ADDR[16]=0; // SEG7 * 4 wire [15:0] mSEG7_DIG; wire Clock; assign Clock = CLOCK_24[1]; ////////////////////////////////////////////////////////////////////////////// // Wiring between CPU Registers/Switches and the CPU,Console and CPU-Console Muxes wire [15:0] oA,iA,oA_CPU,oA_Console; wire [15:0] oB,iB,oPC,iPC,oIR_CPU, oX_CPU; wire [15:0] oPR,iPR; wire oPC_WR,mPC_WR_Console,mPC_WR_CPU; wire oA_WR,mA_WR_Console,mA_WR_CPU; wire oB_WR,mB_WR_Console,mB_WR_CPU; wire mPC_INC1_CPU, mPC_INC2_CPU, mPR_WR; wire [15:0] oB_CPU,oB_Console,iPC_CPU,iPC_Console; wire oC_CPU; // Peripheral wiring between Console (with simulated peripheral support) and the CPU with the Control units wire mf_SWS; // TTY wire mTIRq,mTORq,mTIA,mTIRy,mTORy; wire [7:0] mTCI, mTCO; // PTR wire mPIRq,mPIRy,mPTry; wire [7:0] mPCI; // PTP wire mPtpO,mPORy; wire [7:0] mPCO; // Console Switches/CPU Control and Registers // mCpuActive: activated by the CPU when an instruction is executed (after a Run or Step) // reset after execution of HLT or a single step or honoration of a Stop request by the Console) // mCpuStop: Console requests the CPU to stop (honored by the CPU when CpuActive = 1) wire [3:0] mCpuSense; // 4 bits, representing the Sense Switches wire mCpuStep; // Single Step signal to the cpu wire mCpuRun; // Run signal to the cpu wire mCpuActive; // 1 => CPU is running wire mCpuEnb; // 1 => Interrupt is enabled wire mCpuPil0; // Standard Interrupt Line wire mCpuError; // 1 => CPU is in Error state wire mCpuStop; // Stop signal to the cpu wire mCpuExt; // 1 => Cpu in Extended addressing mode wire mMasterClear_n; // Master Clear signal to the cpu, registers, etc. // Registers (either controled by the Console or the CPU) register #(16) A (.iClk(Clock), .oQ(oA) , .iD(iA) , .iLoad(oA_WR), .iReset_n(mMasterClear_n)); register #(16) B (.iClk(Clock), .oQ(oB) , .iD(iB) , .iLoad(oB_WR), .iReset_n(mMasterClear_n)); register #(16) PR (.iClk(Clock), .oQ(oPR), .iD(iPR), .iLoad(mPR_WR), .iReset_n(mMasterClear_n)); program_counter PC (.iClk(Clock), .oQ(oPC[14:0]), .iD(iPC), .iLoad(oPC_WR), .iInc1(mPC_INC1_CPU), .iInc2(mPC_INC2_CPU),.iReset_n(mMasterClear_n)); assign oPC[15] = 1'b0; // 32 kword maximum // Muxes to select the input for A,B and the PC (either from CPU or Console) assign iA = mCpuActive ? oA_CPU : oA_Console; assign iB = mCpuActive ? oB_CPU : oB_Console; assign iPC = mCpuActive ? iPC_CPU : iPC_Console; assign oPC_WR = mCpuActive ? mPC_WR_CPU : mPC_WR_Console; assign oA_WR = mCpuActive ? mA_WR_CPU : mA_WR_Console; assign oB_WR = mCpuActive ? mB_WR_CPU : mB_WR_Console; // Wiring between RAM and the CPU, Console and CPU-Console Muxes wire [15:0] iSR_DATA_CPU, iSR_DATA_CON; wire [15:0] iSR_ADDR_CPU, iSR_ADDR_CON; wire iSR_OE_CPU_N, iSR_OE_CON_N; wire iSR_WE_CPU_N, iSR_WE_CON_N; // Muxes to select the input for the RAM (either from the CPU or Console) assign oSR_DATA_TO_RAM = mCpuActive ? iSR_DATA_CPU : iSR_DATA_CON; assign oSR_ADDR[15:0] = mCpuActive ? iSR_ADDR_CPU : iSR_ADDR_CON; assign oSR_OE_N = mCpuActive ? iSR_OE_CPU_N : iSR_OE_CON_N; assign oSR_WE_N = mCpuActive ? iSR_WE_CPU_N : iSR_WE_CON_N; ////////////////////////////////////////////////////////////////////////////// assign LEDG[3:0] = mCpuSense[3:0]; // displays the Sense Switch setting assign LEDG[4] = mCpuPil0; // displays the interrupt line status assign LEDG[5] = mCpuEnb; // displays whether the Interrupt is enabled or not assign LEDG[6] = mCpuError; // displays whether the CPU entered an error condition assign LEDG[7] = mCpuActive; // displays whether the CPU is active or not assign LEDR[6:0] = oIR_CPU[15:9]; // left 7 bits of the instruction (MR:flag,tag,opcode,pagebit) assign LEDR[7] = oC_CPU; // C-bit assign LEDR[8] = mCpuExt; // On: Extended mode == 1 assign LEDR[9] = mMasterClear_n; // Off: Master Clear Signal == 1 assign mSEG7_DIG = oPC; // Display the content of the Program counter wire mReset_n; assign mReset_n = KEY[0] & KEY[1] & KEY[2] & KEY[3]; // MasterClear by one of the pushbuttons ////////////////////////////////////////////////////////////////////////////// // JTAG Clock (Altera module, in Altera supplied file CLK_LOCK.v) CLK_LOCK cl (.inclk(TCK),.outclk(mTCK)); // JTAG link with the Personal Computer (Altera module, in Altera supplied file USB_JTAG.v) USB_JTAG u1 (// HOST .iTxD_DATA(mTXD_DATA),.oTxD_Done(mTXD_Done),.iTxD_Start(mTXD_Start), .oRxD_DATA(mRXD_DATA),.oRxD_Ready(mRXD_Ready),.iRST_n(mReset_n),.iCLK(Clock), // JTAG .TDO(TDO),.TDI(TDI),.TCS(TCS),.TCK(mTCK)); // 4 digit display for the Program Counter SEG7_4 d4 (HEX0,HEX1,HEX2,HEX3,mSEG7_DIG ); // Controller for the CPU Console functions and for the link with the Personal Computer X16_Control con (// USB JTAG .iRXD_DATA(mRXD_DATA),.iRXD_Ready(mRXD_Ready), .oTXD_DATA(mTXD_DATA),.oTXD_Start(mTXD_Start),.iTXD_Done(mTXD_Done), // SRAM interface with the console .iSR_DATA(iSR_DATA_FROM_RAM),.oSR_DATA(iSR_DATA_CON),.oSR_ADDR(iSR_ADDR_CON), .oSR_WE_N(iSR_WE_CON_N),.oSR_OE_N(iSR_OE_CON_N), // CPU interface with the Console //// Registers (C and IR only displayed; A,B,PC and Sense can be set by the Console) .iA(oA), .oA(oA_Console), .iB(oB), .oB(oB_Console), .iX(oX_CPU), .iC(oC_CPU), .iPC(oPC), .oPC(iPC_Console), .iIR(oIR_CPU), .oSense(mCpuSense), .oPC_WR(mPC_WR_Console),.oA_WR(mA_WR_Console),.oB_WR(mB_WR_Console), //// CPU Control .oRun(mCpuRun), .oStep(mCpuStep), .oStop(mCpuStop), .oMC_n(mMasterClear_n), .iRunning(mCpuActive), .iError(mCpuError), .iEnb(mCpuEnb), .iPR(oPR), .oPR(iPR), .oPR_WR(mPR_WR), //// Peripheral interfaces // TTY .TtyCharIn(mTCI), .iTtyInReq(mTIRq), .oTtyIChar(mTIRy), .iTty(mTCO), .iTtyCharO(mTORq), .oTtyOutReady(mTORy), // PTR .iPtrInReq(mPIRq),.oPtrIChar(mPIRy),.PtrCharIn(mPCI),.iPtrTry(mPTry), // PTP .iPtp(mPCO),.iPtpO(mPtpO),.oPtpOutReady(mPORy), // Control .iCLK(Clock),.iRST_n(mReset_n), .of_SWS(mf_SWS)); // 16k 16 bit words memory controller (the sram itself is on the development board) Sram ram (// Host .oHS_DATA(iSR_DATA_FROM_RAM),.iHS_DATA(oSR_DATA_TO_RAM),.iHS_ADDR(oSR_ADDR), .iHS_WE_N(oSR_WE_N),.iHS_OE_N(oSR_OE_N), // SRAM .SRAM_DQ(SRAM_DQ), .SRAM_ADDR(SRAM_ADDR), .SRAM_UB_N(SRAM_UB_N), .SRAM_LB_N(SRAM_LB_N), .SRAM_WE_N(SRAM_WE_N), .SRAM_CE_N(SRAM_CE_N), .SRAM_OE_N(SRAM_OE_N)); // X16 CPU and control units for the TTY, PTR, PTP and RTC. X16_CPU cpu (.iClk(Clock), .iA(oA), .oA(oA_CPU), .iB(oB), .oB(oB_CPU), .oC(oC_CPU), .oX(oX_CPU), .iPC(oPC), .oPC(iPC_CPU), .oIR(oIR_CPU), .iSense(mCpuSense), .oPC_WR(mPC_WR_CPU),.oPC_INC1(mPC_INC1_CPU),.oPC_INC2(mPC_INC2_CPU), .oA_WR(mA_WR_CPU),.oB_WR(mB_WR_CPU), // SRAM .iMbr(iSR_DATA_FROM_RAM), .oMbr(iSR_DATA_CPU), .oMaddr(iSR_ADDR_CPU), .oM_we_n(iSR_WE_CPU_N), .oM_oe_n(iSR_OE_CPU_N), // Control .iRun(mCpuRun), .iStep(mCpuStep), .iStop(mCpuStop), .iMC_n(mMasterClear_n), .oRunning(mCpuActive), .oError(mCpuError), .oEnb(mCpuEnb), .oPil(mCpuPil0), .if_SWS(mf_SWS), .iPR(oPR), .oExt(mCpuExt), //// Peripheral interfaces // TTY .TtyCharIn(mTCI), .oTtyInReq(mTIRq), .iTtyIChar(mTIRy), .oTty(mTCO), .oTtyCharO(mTORq), .iTtyOutReady(mTORy), // PTR .oPtrInReq(mPIRq), .iPtrIChar(mPIRy), .PtrCharIn(mPCI), .oPtrTry(mPTry), // PTP .oPtp(mPCO), .oPtpChar(mPtpO), .iPtpOutReady(mPORy)); endmodule // General Register module (used for A, B, PR, C, ENB, etc.) module register (iClk,oQ,iD,iLoad,iReset_n); parameter width = 16; input iClk,iReset_n,iLoad; input [width-1:0] iD; output reg [width-1:0] oQ; always @ (posedge iClk or negedge iReset_n) begin if(! iReset_n) begin oQ<=0; end else if(iLoad) begin oQ<=iD; end end endmodule // Program Counter module module program_counter (iClk,oQ,iD,iLoad,iInc1,iInc2,iReset_n); input iClk,iReset_n,iLoad,iInc1,iInc2; input [15:0] iD; output reg [14:0] oQ; always @ (posedge iClk or negedge iReset_n) begin if(! iReset_n) oQ<=0; else if(iLoad) oQ<=iD[14:0]; else if(iInc1) // increment with 1 oQ<=oQ+1'b1; else if(iInc2) // increment with 2 (for skip operations) oQ<=oQ+2'b10; end endmodule // Memory controller module (the sram itself is on the development board) module Sram( // Host oHS_DATA, //data to host iHS_DATA, //data from host iHS_ADDR, //address from host iHS_WE_N, //write enable iHS_OE_N, //read enable // SRAM SRAM_DQ, SRAM_ADDR, SRAM_UB_N, SRAM_LB_N, SRAM_WE_N, SRAM_CE_N, SRAM_OE_N ); // Host interface input [17:0] iHS_ADDR; input [15:0] iHS_DATA; output [15:0] oHS_DATA; input iHS_WE_N; input iHS_OE_N; // SRAM interface inout [15:0] SRAM_DQ; output [17:0] SRAM_ADDR; output SRAM_UB_N, SRAM_LB_N, SRAM_WE_N, SRAM_CE_N, SRAM_OE_N; assign SRAM_DQ = SRAM_WE_N ? 16'hzzzz : iHS_DATA ; assign oHS_DATA = SRAM_DQ ; assign SRAM_ADDR = iHS_ADDR; assign SRAM_WE_N = iHS_WE_N; assign SRAM_OE_N = iHS_OE_N; assign SRAM_CE_N = 1'b0; assign SRAM_UB_N = 1'b0; assign SRAM_LB_N = 1'b0; endmodule // This module implements the 4 digits of the seven segment hexadecimal display on the development board. // The display is used to show the content of the Program Counter module SEG7_4 ( oSEG0,oSEG1,oSEG2,oSEG3,iDIG ); input [15:0] iDIG; output [6:0] oSEG0,oSEG1,oSEG2,oSEG3; SEG7 d0 (oSEG0,iDIG[3:0]); SEG7 d1 (oSEG1,iDIG[7:4]); SEG7 d2 (oSEG2,iDIG[11:8]); SEG7 d3 (oSEG3,iDIG[15:12]); endmodule // One seven segment hexadecimal digit. module SEG7 (oSEG,iDIG); input [3:0] iDIG; output [6:0] oSEG; reg [6:0] oSEG; // Each segment ia addresses by a bit // in a 7-bit bit string, where bits are // numbered as follows: // 6 5 4 3 2 1 0 // A segment is ON when its bit in the // bitstring is 0 (and OFF when its bit is 1). // Segments and bits correspond as follows: // --0-- // | | // 5 1 // | | // --6-- // | | // 4 2 // | | // --3-- // The 16 hexadecimal digits blink with the following // bitstrings: always @(iDIG) begin case(iDIG) 4'h1: oSEG = 7'b1111001; 4'h2: oSEG = 7'b0100100; 4'h3: oSEG = 7'b0110000; 4'h4: oSEG = 7'b0011001; 4'h5: oSEG = 7'b0010010; 4'h6: oSEG = 7'b0000010; 4'h7: oSEG = 7'b1111000; 4'h8: oSEG = 7'b0000000; 4'h9: oSEG = 7'b0011000; 4'ha: oSEG = 7'b0001000; 4'hb: oSEG = 7'b0000011; 4'hc: oSEG = 7'b1000110; 4'hd: oSEG = 7'b0100001; 4'he: oSEG = 7'b0000110; 4'hf: oSEG = 7'b0001110; 4'h0: oSEG = 7'b1000000; endcase end endmodule