diff --git a/CII_Starter_pin_assignments.csv b/CII_Starter_pin_assignments.csv index f46adb0..3e1f8de 100644 --- a/CII_Starter_pin_assignments.csv +++ b/CII_Starter_pin_assignments.csv @@ -1,455 +1,455 @@ - -# Note: The column header names should not be changed if you wish to import this .csv file into the Quartus II software. - -From,To,Assignment Name,Value,Enabled -,GPIO_0[0],Location,PIN_A13,Yes -,GPIO_0[1],Location,PIN_B13,Yes -,GPIO_0[2],Location,PIN_A14,Yes -,GPIO_0[3],Location,PIN_B14,Yes -,GPIO_0[4],Location,PIN_A15,Yes -,GPIO_0[5],Location,PIN_B15,Yes -,GPIO_0[6],Location,PIN_A16,Yes -,GPIO_0[7],Location,PIN_B16,Yes -,GPIO_0[8],Location,PIN_A17,Yes -,GPIO_0[9],Location,PIN_B17,Yes -,GPIO_0[10],Location,PIN_A18,Yes -,GPIO_0[11],Location,PIN_B18,Yes -,GPIO_0[12],Location,PIN_A19,Yes -,GPIO_0[13],Location,PIN_B19,Yes -,GPIO_0[14],Location,PIN_A20,Yes -,GPIO_0[15],Location,PIN_B20,Yes -,GPIO_0[16],Location,PIN_C21,Yes -,GPIO_0[17],Location,PIN_C22,Yes -,GPIO_0[18],Location,PIN_D21,Yes -,GPIO_0[19],Location,PIN_D22,Yes -,GPIO_0[20],Location,PIN_E21,Yes -,GPIO_0[21],Location,PIN_E22,Yes -,GPIO_0[22],Location,PIN_F21,Yes -,GPIO_0[23],Location,PIN_F22,Yes -,GPIO_0[24],Location,PIN_G21,Yes -,GPIO_0[25],Location,PIN_G22,Yes -,GPIO_0[26],Location,PIN_J21,Yes -,GPIO_0[27],Location,PIN_J22,Yes -,GPIO_0[28],Location,PIN_K21,Yes -,GPIO_0[29],Location,PIN_K22,Yes -,GPIO_0[30],Location,PIN_J19,Yes -,GPIO_0[31],Location,PIN_J20,Yes -,GPIO_0[32],Location,PIN_J18,Yes -,GPIO_0[33],Location,PIN_K20,Yes -,GPIO_0[34],Location,PIN_L19,Yes -,GPIO_0[35],Location,PIN_L18,Yes -,GPIO_1[0],Location,PIN_H12,Yes -,GPIO_1[1],Location,PIN_H13,Yes -,GPIO_1[2],Location,PIN_H14,Yes -,GPIO_1[3],Location,PIN_G15,Yes -,GPIO_1[4],Location,PIN_E14,Yes -,GPIO_1[5],Location,PIN_E15,Yes -,GPIO_1[6],Location,PIN_F15,Yes -,GPIO_1[7],Location,PIN_G16,Yes -,GPIO_1[8],Location,PIN_F12,Yes -,GPIO_1[9],Location,PIN_F13,Yes -,GPIO_1[10],Location,PIN_C14,Yes -,GPIO_1[11],Location,PIN_D14,Yes -,GPIO_1[12],Location,PIN_D15,Yes -,GPIO_1[13],Location,PIN_D16,Yes -,GPIO_1[14],Location,PIN_C17,Yes -,GPIO_1[15],Location,PIN_C18,Yes -,GPIO_1[16],Location,PIN_C19,Yes -,GPIO_1[17],Location,PIN_C20,Yes -,GPIO_1[18],Location,PIN_D19,Yes -,GPIO_1[19],Location,PIN_D20,Yes -,GPIO_1[20],Location,PIN_E20,Yes -,GPIO_1[21],Location,PIN_F20,Yes -,GPIO_1[22],Location,PIN_E19,Yes -,GPIO_1[23],Location,PIN_E18,Yes -,GPIO_1[24],Location,PIN_G20,Yes -,GPIO_1[25],Location,PIN_G18,Yes -,GPIO_1[26],Location,PIN_G17,Yes -,GPIO_1[27],Location,PIN_H17,Yes -,GPIO_1[28],Location,PIN_J15,Yes -,GPIO_1[29],Location,PIN_H18,Yes -,GPIO_1[30],Location,PIN_N22,Yes -,GPIO_1[31],Location,PIN_N21,Yes -,GPIO_1[32],Location,PIN_P15,Yes -,GPIO_1[33],Location,PIN_N15,Yes -,GPIO_1[34],Location,PIN_P17,Yes -,GPIO_1[35],Location,PIN_P18,Yes -,GPIO_0[0],I/O Standard,LVTTL,Yes -,GPIO_0[1],I/O Standard,LVTTL,Yes -,GPIO_0[2],I/O Standard,LVTTL,Yes -,GPIO_0[3],I/O Standard,LVTTL,Yes -,GPIO_0[4],I/O Standard,LVTTL,Yes -,GPIO_0[5],I/O Standard,LVTTL,Yes -,GPIO_0[6],I/O Standard,LVTTL,Yes -,GPIO_0[7],I/O Standard,LVTTL,Yes -,GPIO_0[8],I/O Standard,LVTTL,Yes -,GPIO_0[9],I/O Standard,LVTTL,Yes -,GPIO_0[10],I/O Standard,LVTTL,Yes -,GPIO_0[11],I/O Standard,LVTTL,Yes -,GPIO_0[12],I/O Standard,LVTTL,Yes -,GPIO_0[13],I/O Standard,LVTTL,Yes -,GPIO_0[14],I/O Standard,LVTTL,Yes -,GPIO_0[15],I/O Standard,LVTTL,Yes -,GPIO_0[16],I/O Standard,LVTTL,Yes -,GPIO_0[17],I/O Standard,LVTTL,Yes -,GPIO_0[18],I/O Standard,LVTTL,Yes -,GPIO_0[19],I/O Standard,LVTTL,Yes -,GPIO_0[20],I/O Standard,LVTTL,Yes -,GPIO_0[21],I/O Standard,LVTTL,Yes -,GPIO_0[22],I/O Standard,LVTTL,Yes -,GPIO_0[23],I/O Standard,LVTTL,Yes -,GPIO_0[24],I/O Standard,LVTTL,Yes -,GPIO_0[25],I/O Standard,LVTTL,Yes -,GPIO_0[26],I/O Standard,LVTTL,Yes -,GPIO_0[27],I/O Standard,LVTTL,Yes -,GPIO_0[28],I/O Standard,LVTTL,Yes -,GPIO_0[29],I/O Standard,LVTTL,Yes -,GPIO_0[30],I/O Standard,LVTTL,Yes -,GPIO_0[31],I/O Standard,LVTTL,Yes -,GPIO_0[32],I/O Standard,LVTTL,Yes -,GPIO_0[33],I/O Standard,LVTTL,Yes -,GPIO_0[34],I/O Standard,LVTTL,Yes -,GPIO_0[35],I/O Standard,LVTTL,Yes -,GPIO_1[0],I/O Standard,LVTTL,Yes -,GPIO_1[1],I/O Standard,LVTTL,Yes -,GPIO_1[2],I/O Standard,LVTTL,Yes -,GPIO_1[3],I/O Standard,LVTTL,Yes -,GPIO_1[4],I/O Standard,LVTTL,Yes -,GPIO_1[5],I/O Standard,LVTTL,Yes -,GPIO_1[6],I/O Standard,LVTTL,Yes -,GPIO_1[7],I/O Standard,LVTTL,Yes -,GPIO_1[8],I/O Standard,LVTTL,Yes -,GPIO_1[9],I/O Standard,LVTTL,Yes -,GPIO_1[10],I/O Standard,LVTTL,Yes -,GPIO_1[11],I/O Standard,LVTTL,Yes -,GPIO_1[12],I/O Standard,LVTTL,Yes -,GPIO_1[13],I/O Standard,LVTTL,Yes -,GPIO_1[14],I/O Standard,LVTTL,Yes -,GPIO_1[15],I/O Standard,LVTTL,Yes -,GPIO_1[16],I/O Standard,LVTTL,Yes -,GPIO_1[17],I/O Standard,LVTTL,Yes -,GPIO_1[18],I/O Standard,LVTTL,Yes -,GPIO_1[19],I/O Standard,LVTTL,Yes -,GPIO_1[20],I/O Standard,LVTTL,Yes -,GPIO_1[21],I/O Standard,LVTTL,Yes -,GPIO_1[22],I/O Standard,LVTTL,Yes -,GPIO_1[23],I/O Standard,LVTTL,Yes -,GPIO_1[24],I/O Standard,LVTTL,Yes -,GPIO_1[25],I/O Standard,LVTTL,Yes -,GPIO_1[26],I/O Standard,LVTTL,Yes -,GPIO_1[27],I/O Standard,LVTTL,Yes -,GPIO_1[28],I/O Standard,LVTTL,Yes -,GPIO_1[29],I/O Standard,LVTTL,Yes -,GPIO_1[30],I/O Standard,LVTTL,Yes -,GPIO_1[31],I/O Standard,LVTTL,Yes -,GPIO_1[32],I/O Standard,LVTTL,Yes -,GPIO_1[33],I/O Standard,LVTTL,Yes -,GPIO_1[34],I/O Standard,LVTTL,Yes -,GPIO_1[35],I/O Standard,LVTTL,Yes -,SW[0],Location,PIN_L22,Yes -,SW[1],Location,PIN_L21,Yes -,SW[2],Location,PIN_M22,Yes -,SW[3],Location,PIN_V12,Yes -,SW[4],Location,PIN_W12,Yes -,SW[5],Location,PIN_U12,Yes -,SW[6],Location,PIN_U11,Yes -,SW[7],Location,PIN_M2,Yes -,SW[8],Location,PIN_M1,Yes -,SW[9],Location,PIN_L2,Yes -,SW[0],I/O Standard,LVTTL,Yes -,SW[1],I/O Standard,LVTTL,Yes -,SW[2],I/O Standard,LVTTL,Yes -,SW[3],I/O Standard,LVTTL,Yes -,SW[4],I/O Standard,LVTTL,Yes -,SW[5],I/O Standard,LVTTL,Yes -,SW[6],I/O Standard,LVTTL,Yes -,SW[7],I/O Standard,LVTTL,Yes -,SW[8],I/O Standard,LVTTL,Yes -,SW[9],I/O Standard,LVTTL,Yes -,HEX0[0],Location,PIN_J2,Yes -,HEX0[1],Location,PIN_J1,Yes -,HEX0[2],Location,PIN_H2,Yes -,HEX0[3],Location,PIN_H1,Yes -,HEX0[4],Location,PIN_F2,Yes -,HEX0[5],Location,PIN_F1,Yes -,HEX0[6],Location,PIN_E2,Yes -,HEX1[0],Location,PIN_E1,Yes -,HEX1[1],Location,PIN_H6,Yes -,HEX1[2],Location,PIN_H5,Yes -,HEX1[3],Location,PIN_H4,Yes -,HEX1[4],Location,PIN_G3,Yes -,HEX1[5],Location,PIN_D2,Yes -,HEX1[6],Location,PIN_D1,Yes -,HEX2[0],Location,PIN_G5,Yes -,HEX2[1],Location,PIN_G6,Yes -,HEX2[2],Location,PIN_C2,Yes -,HEX2[3],Location,PIN_C1,Yes -,HEX2[4],Location,PIN_E3,Yes -,HEX2[5],Location,PIN_E4,Yes -,HEX2[6],Location,PIN_D3,Yes -,HEX3[0],Location,PIN_F4,Yes -,HEX3[1],Location,PIN_D5,Yes -,HEX3[2],Location,PIN_D6,Yes -,HEX3[3],Location,PIN_J4,Yes -,HEX3[4],Location,PIN_L8,Yes -,HEX3[5],Location,PIN_F3,Yes -,HEX3[6],Location,PIN_D4,Yes -,HEX0[0],I/O Standard,LVTTL,Yes -,HEX0[1],I/O Standard,LVTTL,Yes -,HEX0[2],I/O Standard,LVTTL,Yes -,HEX0[3],I/O Standard,LVTTL,Yes -,HEX0[4],I/O Standard,LVTTL,Yes -,HEX0[5],I/O Standard,LVTTL,Yes -,HEX0[6],I/O Standard,LVTTL,Yes -,HEX1[0],I/O Standard,LVTTL,Yes -,HEX1[1],I/O Standard,LVTTL,Yes -,HEX1[2],I/O Standard,LVTTL,Yes -,HEX1[3],I/O Standard,LVTTL,Yes -,HEX1[4],I/O Standard,LVTTL,Yes -,HEX1[5],I/O Standard,LVTTL,Yes -,HEX1[6],I/O Standard,LVTTL,Yes -,HEX2[0],I/O Standard,LVTTL,Yes -,HEX2[1],I/O Standard,LVTTL,Yes -,HEX2[2],I/O Standard,LVTTL,Yes -,HEX2[3],I/O Standard,LVTTL,Yes -,HEX2[4],I/O Standard,LVTTL,Yes -,HEX2[5],I/O Standard,LVTTL,Yes -,HEX2[6],I/O Standard,LVTTL,Yes -,HEX3[0],I/O Standard,LVTTL,Yes -,HEX3[1],I/O Standard,LVTTL,Yes -,HEX3[2],I/O Standard,LVTTL,Yes -,HEX3[3],I/O Standard,LVTTL,Yes -,HEX3[4],I/O Standard,LVTTL,Yes -,HEX3[5],I/O Standard,LVTTL,Yes -,HEX3[6],I/O Standard,LVTTL,Yes -,KEY[0],Location,PIN_R22,Yes -,KEY[1],Location,PIN_R21,Yes -,KEY[2],Location,PIN_T22,Yes -,KEY[3],Location,PIN_T21,Yes -,LEDR[0],Location,PIN_R20,Yes -,LEDR[1],Location,PIN_R19,Yes -,LEDR[2],Location,PIN_U19,Yes -,LEDR[3],Location,PIN_Y19,Yes -,LEDR[4],Location,PIN_T18,Yes -,LEDR[5],Location,PIN_V19,Yes -,LEDR[6],Location,PIN_Y18,Yes -,LEDR[7],Location,PIN_U18,Yes -,LEDR[8],Location,PIN_R18,Yes -,LEDR[9],Location,PIN_R17,Yes -,LEDG[0],Location,PIN_U22,Yes -,LEDG[1],Location,PIN_U21,Yes -,LEDG[2],Location,PIN_V22,Yes -,LEDG[3],Location,PIN_V21,Yes -,LEDG[4],Location,PIN_W22,Yes -,LEDG[5],Location,PIN_W21,Yes -,LEDG[6],Location,PIN_Y22,Yes -,LEDG[7],Location,PIN_Y21,Yes -,KEY[0],I/O Standard,LVTTL,Yes -,KEY[1],I/O Standard,LVTTL,Yes -,KEY[2],I/O Standard,LVTTL,Yes -,KEY[3],I/O Standard,LVTTL,Yes -,LEDR[0],I/O Standard,LVTTL,Yes -,LEDR[1],I/O Standard,LVTTL,Yes -,LEDR[2],I/O Standard,LVTTL,Yes -,LEDR[3],I/O Standard,LVTTL,Yes -,LEDR[4],I/O Standard,LVTTL,Yes -,LEDR[5],I/O Standard,LVTTL,Yes -,LEDR[6],I/O Standard,LVTTL,Yes -,LEDR[7],I/O Standard,LVTTL,Yes -,LEDR[8],I/O Standard,LVTTL,Yes -,LEDR[9],I/O Standard,LVTTL,Yes -,LEDG[0],I/O Standard,LVTTL,Yes -,LEDG[1],I/O Standard,LVTTL,Yes -,LEDG[2],I/O Standard,LVTTL,Yes -,LEDG[3],I/O Standard,LVTTL,Yes -,LEDG[4],I/O Standard,LVTTL,Yes -,LEDG[5],I/O Standard,LVTTL,Yes -,LEDG[6],I/O Standard,LVTTL,Yes -,LEDG[7],I/O Standard,LVTTL,Yes -,CLOCK_27[0],Location,PIN_D12,Yes -,CLOCK_27[1],Location,PIN_E12,Yes -,CLOCK_24[0],Location,PIN_B12,Yes -,CLOCK_24[1],Location,PIN_A12,Yes -,CLOCK_50,Location,PIN_L1,Yes -,EXT_CLOCK,Location,PIN_M21,Yes -,CLOCK_27[1],I/O Standard,LVTTL,Yes -,CLOCK_24[0],I/O Standard,LVTTL,Yes -,CLOCK_24[1],I/O Standard,LVTTL,Yes -,CLOCK_50,I/O Standard,LVTTL,Yes -,EXT_CLOCK,I/O Standard,LVTTL,Yes -,PS2_CLK,Location,PIN_H15,Yes -,PS2_DAT,Location,PIN_J14,Yes -,UART_RXD,Location,PIN_F14,Yes -,UART_TXD,Location,PIN_G12,Yes -,PS2_CLK,I/O Standard,LVTTL,Yes -,PS2_DAT,I/O Standard,LVTTL,Yes -,UART_RXD,I/O Standard,LVTTL,Yes -,UART_TXD,I/O Standard,LVTTL,Yes -,TDI,Location,PIN_E8,Yes -,TCS,Location,PIN_D8,Yes -,TCK,Location,PIN_C7,Yes -,TDO,Location,PIN_D7,Yes -,TDI,I/O Standard,LVTTL,Yes -,TCS,I/O Standard,LVTTL,Yes -,TCK,I/O Standard,LVTTL,Yes -,TDO,I/O Standard,LVTTL,Yes -,VGA_R[0],Location,PIN_D9,Yes -,VGA_R[1],Location,PIN_C9,Yes -,VGA_R[2],Location,PIN_A7,Yes -,VGA_R[3],Location,PIN_B7,Yes -,VGA_G[0],Location,PIN_B8,Yes -,VGA_G[1],Location,PIN_C10,Yes -,VGA_G[2],Location,PIN_B9,Yes -,VGA_G[3],Location,PIN_A8,Yes -,VGA_B[0],Location,PIN_A9,Yes -,VGA_B[1],Location,PIN_D11,Yes -,VGA_B[2],Location,PIN_A10,Yes -,VGA_B[3],Location,PIN_B10,Yes -,VGA_HS,Location,PIN_A11,Yes -,VGA_VS,Location,PIN_B11,Yes -,VGA_R[0],I/O Standard,LVTTL,Yes -,VGA_R[1],I/O Standard,LVTTL,Yes -,VGA_R[2],I/O Standard,LVTTL,Yes -,VGA_R[3],I/O Standard,LVTTL,Yes -,VGA_G[0],I/O Standard,LVTTL,Yes -,VGA_G[1],I/O Standard,LVTTL,Yes -,VGA_G[2],I/O Standard,LVTTL,Yes -,VGA_G[3],I/O Standard,LVTTL,Yes -,VGA_B[0],I/O Standard,LVTTL,Yes -,VGA_B[1],I/O Standard,LVTTL,Yes -,VGA_B[2],I/O Standard,LVTTL,Yes -,VGA_B[3],I/O Standard,LVTTL,Yes -,VGA_HS,I/O Standard,LVTTL,Yes -,VGA_VS,I/O Standard,LVTTL,Yes -,I2C_SCLK,Location,PIN_A3,Yes -,I2C_SDAT,Location,PIN_B3,Yes -,AUD_ADCLRCK,Location,PIN_A6,Yes -,AUD_ADCDAT,Location,PIN_B6,Yes -,AUD_DACLRCK,Location,PIN_A5,Yes -,AUD_DACDAT,Location,PIN_B5,Yes -,AUD_XCK,Location,PIN_B4,Yes -,AUD_BCLK,Location,PIN_A4,Yes -,I2C_SCLK,I/O Standard,LVTTL,Yes -,I2C_SDAT,I/O Standard,LVTTL,Yes -,AUD_ADCLRCK,I/O Standard,LVTTL,Yes -,AUD_ADCDAT,I/O Standard,LVTTL,Yes -,AUD_DACLRCK,I/O Standard,LVTTL,Yes -,AUD_DACDAT,I/O Standard,LVTTL,Yes -,AUD_XCK,I/O Standard,LVTTL,Yes -,AUD_BCLK,I/O Standard,LVTTL,Yes -,DRAM_ADDR[0],Location,PIN_W4,Yes -,DRAM_ADDR[1],Location,PIN_W5,Yes -,DRAM_ADDR[2],Location,PIN_Y3,Yes -,DRAM_ADDR[3],Location,PIN_Y4,Yes -,DRAM_ADDR[4],Location,PIN_R6,Yes -,DRAM_ADDR[5],Location,PIN_R5,Yes -,DRAM_ADDR[6],Location,PIN_P6,Yes -,DRAM_ADDR[7],Location,PIN_P5,Yes -,DRAM_ADDR[8],Location,PIN_P3,Yes -,DRAM_ADDR[9],Location,PIN_N4,Yes -,DRAM_ADDR[10],Location,PIN_W3,Yes -,DRAM_ADDR[11],Location,PIN_N6,Yes -,DRAM_BA_0,Location,PIN_U3,Yes -,DRAM_BA_1,Location,PIN_V4,Yes -,DRAM_CAS_N,Location,PIN_T3,Yes -,DRAM_CKE,Location,PIN_N3,Yes -,DRAM_CLK,Location,PIN_U4,Yes -,DRAM_CS_N,Location,PIN_T6,Yes -,DRAM_DQ[0],Location,PIN_U1,Yes -,DRAM_DQ[1],Location,PIN_U2,Yes -,DRAM_DQ[2],Location,PIN_V1,Yes -,DRAM_DQ[3],Location,PIN_V2,Yes -,DRAM_DQ[4],Location,PIN_W1,Yes -,DRAM_DQ[5],Location,PIN_W2,Yes -,DRAM_DQ[6],Location,PIN_Y1,Yes -,DRAM_DQ[7],Location,PIN_Y2,Yes -,DRAM_DQ[8],Location,PIN_N1,Yes -,DRAM_DQ[9],Location,PIN_N2,Yes -,DRAM_DQ[10],Location,PIN_P1,Yes -,DRAM_DQ[11],Location,PIN_P2,Yes -,DRAM_DQ[12],Location,PIN_R1,Yes -,DRAM_DQ[13],Location,PIN_R2,Yes -,DRAM_DQ[14],Location,PIN_T1,Yes -,DRAM_DQ[15],Location,PIN_T2,Yes -,DRAM_LDQM,Location,PIN_R7,Yes -,DRAM_RAS_N,Location,PIN_T5,Yes -,DRAM_UDQM,Location,PIN_M5,Yes -,DRAM_WE_N,Location,PIN_R8,Yes -,FL_ADDR[0],Location,PIN_AB20,Yes -,FL_ADDR[1],Location,PIN_AA14,Yes -,FL_ADDR[2],Location,PIN_Y16,Yes -,FL_ADDR[3],Location,PIN_R15,Yes -,FL_ADDR[4],Location,PIN_T15,Yes -,FL_ADDR[5],Location,PIN_U15,Yes -,FL_ADDR[6],Location,PIN_V15,Yes -,FL_ADDR[7],Location,PIN_W15,Yes -,FL_ADDR[8],Location,PIN_R14,Yes -,FL_ADDR[9],Location,PIN_Y13,Yes -,FL_ADDR[10],Location,PIN_R12,Yes -,FL_ADDR[11],Location,PIN_T12,Yes -,FL_ADDR[12],Location,PIN_AB14,Yes -,FL_ADDR[13],Location,PIN_AA13,Yes -,FL_ADDR[14],Location,PIN_AB13,Yes -,FL_ADDR[15],Location,PIN_AA12,Yes -,FL_ADDR[16],Location,PIN_AB12,Yes -,FL_ADDR[17],Location,PIN_AA20,Yes -,FL_ADDR[18],Location,PIN_U14,Yes -,FL_ADDR[19],Location,PIN_V14,Yes -,FL_ADDR[20],Location,PIN_U13,Yes -,FL_ADDR[21],Location,PIN_R13,Yes -,FL_DQ[0],Location,PIN_AB16,Yes -,FL_DQ[1],Location,PIN_AA16,Yes -,FL_DQ[2],Location,PIN_AB17,Yes -,FL_DQ[3],Location,PIN_AA17,Yes -,FL_DQ[4],Location,PIN_AB18,Yes -,FL_DQ[5],Location,PIN_AA18,Yes -,FL_DQ[6],Location,PIN_AB19,Yes -,FL_DQ[7],Location,PIN_AA19,Yes -,FL_OE_N,Location,PIN_AA15,Yes -,FL_RST_N,Location,PIN_W14,Yes -,FL_WE_N,Location,PIN_Y14,Yes -,FL_CE_N,Location,PIN_AB15,Yes -,SRAM_ADDR[0],Location,PIN_AA3,Yes -,SRAM_ADDR[1],Location,PIN_AB3,Yes -,SRAM_ADDR[2],Location,PIN_AA4,Yes -,SRAM_ADDR[3],Location,PIN_AB4,Yes -,SRAM_ADDR[4],Location,PIN_AA5,Yes -,SRAM_ADDR[5],Location,PIN_AB10,Yes -,SRAM_ADDR[6],Location,PIN_AA11,Yes -,SRAM_ADDR[7],Location,PIN_AB11,Yes -,SRAM_ADDR[8],Location,PIN_V11,Yes -,SRAM_ADDR[9],Location,PIN_W11,Yes -,SRAM_ADDR[10],Location,PIN_R11,Yes -,SRAM_ADDR[11],Location,PIN_T11,Yes -,SRAM_ADDR[12],Location,PIN_Y10,Yes -,SRAM_ADDR[13],Location,PIN_U10,Yes -,SRAM_ADDR[14],Location,PIN_R10,Yes -,SRAM_ADDR[15],Location,PIN_T7,Yes -,SRAM_ADDR[16],Location,PIN_Y6,Yes -,SRAM_ADDR[17],Location,PIN_Y5,Yes -,SRAM_CE_N,Location,PIN_AB5,Yes -,SRAM_DQ[0],Location,PIN_AA6,Yes -,SRAM_DQ[1],Location,PIN_AB6,Yes -,SRAM_DQ[2],Location,PIN_AA7,Yes -,SRAM_DQ[3],Location,PIN_AB7,Yes -,SRAM_DQ[4],Location,PIN_AA8,Yes -,SRAM_DQ[5],Location,PIN_AB8,Yes -,SRAM_DQ[6],Location,PIN_AA9,Yes -,SRAM_DQ[7],Location,PIN_AB9,Yes -,SRAM_DQ[8],Location,PIN_Y9,Yes -,SRAM_DQ[9],Location,PIN_W9,Yes -,SRAM_DQ[10],Location,PIN_V9,Yes -,SRAM_DQ[11],Location,PIN_U9,Yes -,SRAM_DQ[12],Location,PIN_R9,Yes -,SRAM_DQ[13],Location,PIN_W8,Yes -,SRAM_DQ[14],Location,PIN_V8,Yes -,SRAM_DQ[15],Location,PIN_U8,Yes -,SRAM_LB_N,Location,PIN_Y7,Yes -,SRAM_OE_N,Location,PIN_T8,Yes -,SRAM_UB_N,Location,PIN_W7,Yes -,SRAM_WE_N,Location,PIN_AA10,Yes -,SD_nCS,Location,PIN_U20,Yes -,SD_MOSI,Location,PIN_Y20,Yes -,SD_SCLK,Location,PIN_V20,Yes -,SD_MISO,Location,PIN_W20,Yes - + +# Note: The column header names should not be changed if you wish to import this .csv file into the Quartus II software. + +From,To,Assignment Name,Value,Enabled +,GPIO_0[0],Location,PIN_A13,Yes +,GPIO_0[1],Location,PIN_B13,Yes +,GPIO_0[2],Location,PIN_A14,Yes +,GPIO_0[3],Location,PIN_B14,Yes +,GPIO_0[4],Location,PIN_A15,Yes +,GPIO_0[5],Location,PIN_B15,Yes +,GPIO_0[6],Location,PIN_A16,Yes +,GPIO_0[7],Location,PIN_B16,Yes +,GPIO_0[8],Location,PIN_A17,Yes +,GPIO_0[9],Location,PIN_B17,Yes +,GPIO_0[10],Location,PIN_A18,Yes +,GPIO_0[11],Location,PIN_B18,Yes +,GPIO_0[12],Location,PIN_A19,Yes +,GPIO_0[13],Location,PIN_B19,Yes +,GPIO_0[14],Location,PIN_A20,Yes +,GPIO_0[15],Location,PIN_B20,Yes +,GPIO_0[16],Location,PIN_C21,Yes +,GPIO_0[17],Location,PIN_C22,Yes +,GPIO_0[18],Location,PIN_D21,Yes +,GPIO_0[19],Location,PIN_D22,Yes +,GPIO_0[20],Location,PIN_E21,Yes +,GPIO_0[21],Location,PIN_E22,Yes +,GPIO_0[22],Location,PIN_F21,Yes +,GPIO_0[23],Location,PIN_F22,Yes +,GPIO_0[24],Location,PIN_G21,Yes +,GPIO_0[25],Location,PIN_G22,Yes +,GPIO_0[26],Location,PIN_J21,Yes +,GPIO_0[27],Location,PIN_J22,Yes +,GPIO_0[28],Location,PIN_K21,Yes +,GPIO_0[29],Location,PIN_K22,Yes +,GPIO_0[30],Location,PIN_J19,Yes +,GPIO_0[31],Location,PIN_J20,Yes +,GPIO_0[32],Location,PIN_J18,Yes +,GPIO_0[33],Location,PIN_K20,Yes +,GPIO_0[34],Location,PIN_L19,Yes +,GPIO_0[35],Location,PIN_L18,Yes +,GPIO_1[0],Location,PIN_H12,Yes +,GPIO_1[1],Location,PIN_H13,Yes +,GPIO_1[2],Location,PIN_H14,Yes +,GPIO_1[3],Location,PIN_G15,Yes +,GPIO_1[4],Location,PIN_E14,Yes +,GPIO_1[5],Location,PIN_E15,Yes +,GPIO_1[6],Location,PIN_F15,Yes +,GPIO_1[7],Location,PIN_G16,Yes +,GPIO_1[8],Location,PIN_F12,Yes +,GPIO_1[9],Location,PIN_F13,Yes +,GPIO_1[10],Location,PIN_C14,Yes +,GPIO_1[11],Location,PIN_D14,Yes +,GPIO_1[12],Location,PIN_D15,Yes +,GPIO_1[13],Location,PIN_D16,Yes +,GPIO_1[14],Location,PIN_C17,Yes +,GPIO_1[15],Location,PIN_C18,Yes +,GPIO_1[16],Location,PIN_C19,Yes +,GPIO_1[17],Location,PIN_C20,Yes +,GPIO_1[18],Location,PIN_D19,Yes +,GPIO_1[19],Location,PIN_D20,Yes +,GPIO_1[20],Location,PIN_E20,Yes +,GPIO_1[21],Location,PIN_F20,Yes +,GPIO_1[22],Location,PIN_E19,Yes +,GPIO_1[23],Location,PIN_E18,Yes +,GPIO_1[24],Location,PIN_G20,Yes +,GPIO_1[25],Location,PIN_G18,Yes +,GPIO_1[26],Location,PIN_G17,Yes +,GPIO_1[27],Location,PIN_H17,Yes +,GPIO_1[28],Location,PIN_J15,Yes +,GPIO_1[29],Location,PIN_H18,Yes +,GPIO_1[30],Location,PIN_N22,Yes +,GPIO_1[31],Location,PIN_N21,Yes +,GPIO_1[32],Location,PIN_P15,Yes +,GPIO_1[33],Location,PIN_N15,Yes +,GPIO_1[34],Location,PIN_P17,Yes +,GPIO_1[35],Location,PIN_P18,Yes +,GPIO_0[0],I/O Standard,LVTTL,Yes +,GPIO_0[1],I/O Standard,LVTTL,Yes +,GPIO_0[2],I/O Standard,LVTTL,Yes +,GPIO_0[3],I/O Standard,LVTTL,Yes +,GPIO_0[4],I/O Standard,LVTTL,Yes +,GPIO_0[5],I/O Standard,LVTTL,Yes +,GPIO_0[6],I/O Standard,LVTTL,Yes +,GPIO_0[7],I/O Standard,LVTTL,Yes +,GPIO_0[8],I/O Standard,LVTTL,Yes +,GPIO_0[9],I/O Standard,LVTTL,Yes +,GPIO_0[10],I/O Standard,LVTTL,Yes +,GPIO_0[11],I/O Standard,LVTTL,Yes +,GPIO_0[12],I/O Standard,LVTTL,Yes +,GPIO_0[13],I/O Standard,LVTTL,Yes +,GPIO_0[14],I/O Standard,LVTTL,Yes +,GPIO_0[15],I/O Standard,LVTTL,Yes +,GPIO_0[16],I/O Standard,LVTTL,Yes +,GPIO_0[17],I/O Standard,LVTTL,Yes +,GPIO_0[18],I/O Standard,LVTTL,Yes +,GPIO_0[19],I/O Standard,LVTTL,Yes +,GPIO_0[20],I/O Standard,LVTTL,Yes +,GPIO_0[21],I/O Standard,LVTTL,Yes +,GPIO_0[22],I/O Standard,LVTTL,Yes +,GPIO_0[23],I/O Standard,LVTTL,Yes +,GPIO_0[24],I/O Standard,LVTTL,Yes +,GPIO_0[25],I/O Standard,LVTTL,Yes +,GPIO_0[26],I/O Standard,LVTTL,Yes +,GPIO_0[27],I/O Standard,LVTTL,Yes +,GPIO_0[28],I/O Standard,LVTTL,Yes +,GPIO_0[29],I/O Standard,LVTTL,Yes +,GPIO_0[30],I/O Standard,LVTTL,Yes +,GPIO_0[31],I/O Standard,LVTTL,Yes +,GPIO_0[32],I/O Standard,LVTTL,Yes +,GPIO_0[33],I/O Standard,LVTTL,Yes +,GPIO_0[34],I/O Standard,LVTTL,Yes +,GPIO_0[35],I/O Standard,LVTTL,Yes +,GPIO_1[0],I/O Standard,LVTTL,Yes +,GPIO_1[1],I/O Standard,LVTTL,Yes +,GPIO_1[2],I/O Standard,LVTTL,Yes +,GPIO_1[3],I/O Standard,LVTTL,Yes +,GPIO_1[4],I/O Standard,LVTTL,Yes +,GPIO_1[5],I/O Standard,LVTTL,Yes +,GPIO_1[6],I/O Standard,LVTTL,Yes +,GPIO_1[7],I/O Standard,LVTTL,Yes +,GPIO_1[8],I/O Standard,LVTTL,Yes +,GPIO_1[9],I/O Standard,LVTTL,Yes +,GPIO_1[10],I/O Standard,LVTTL,Yes +,GPIO_1[11],I/O Standard,LVTTL,Yes +,GPIO_1[12],I/O Standard,LVTTL,Yes +,GPIO_1[13],I/O Standard,LVTTL,Yes +,GPIO_1[14],I/O Standard,LVTTL,Yes +,GPIO_1[15],I/O Standard,LVTTL,Yes +,GPIO_1[16],I/O Standard,LVTTL,Yes +,GPIO_1[17],I/O Standard,LVTTL,Yes +,GPIO_1[18],I/O Standard,LVTTL,Yes +,GPIO_1[19],I/O Standard,LVTTL,Yes +,GPIO_1[20],I/O Standard,LVTTL,Yes +,GPIO_1[21],I/O Standard,LVTTL,Yes +,GPIO_1[22],I/O Standard,LVTTL,Yes +,GPIO_1[23],I/O Standard,LVTTL,Yes +,GPIO_1[24],I/O Standard,LVTTL,Yes +,GPIO_1[25],I/O Standard,LVTTL,Yes +,GPIO_1[26],I/O Standard,LVTTL,Yes +,GPIO_1[27],I/O Standard,LVTTL,Yes +,GPIO_1[28],I/O Standard,LVTTL,Yes +,GPIO_1[29],I/O Standard,LVTTL,Yes +,GPIO_1[30],I/O Standard,LVTTL,Yes +,GPIO_1[31],I/O Standard,LVTTL,Yes +,GPIO_1[32],I/O Standard,LVTTL,Yes +,GPIO_1[33],I/O Standard,LVTTL,Yes +,GPIO_1[34],I/O Standard,LVTTL,Yes +,GPIO_1[35],I/O Standard,LVTTL,Yes +,SW[0],Location,PIN_L22,Yes +,SW[1],Location,PIN_L21,Yes +,SW[2],Location,PIN_M22,Yes +,SW[3],Location,PIN_V12,Yes +,SW[4],Location,PIN_W12,Yes +,SW[5],Location,PIN_U12,Yes +,SW[6],Location,PIN_U11,Yes +,SW[7],Location,PIN_M2,Yes +,SW[8],Location,PIN_M1,Yes +,SW[9],Location,PIN_L2,Yes +,SW[0],I/O Standard,LVTTL,Yes +,SW[1],I/O Standard,LVTTL,Yes +,SW[2],I/O Standard,LVTTL,Yes +,SW[3],I/O Standard,LVTTL,Yes +,SW[4],I/O Standard,LVTTL,Yes +,SW[5],I/O Standard,LVTTL,Yes +,SW[6],I/O Standard,LVTTL,Yes +,SW[7],I/O Standard,LVTTL,Yes +,SW[8],I/O Standard,LVTTL,Yes +,SW[9],I/O Standard,LVTTL,Yes +,HEX0[0],Location,PIN_J2,Yes +,HEX0[1],Location,PIN_J1,Yes +,HEX0[2],Location,PIN_H2,Yes +,HEX0[3],Location,PIN_H1,Yes +,HEX0[4],Location,PIN_F2,Yes +,HEX0[5],Location,PIN_F1,Yes +,HEX0[6],Location,PIN_E2,Yes +,HEX1[0],Location,PIN_E1,Yes +,HEX1[1],Location,PIN_H6,Yes +,HEX1[2],Location,PIN_H5,Yes +,HEX1[3],Location,PIN_H4,Yes +,HEX1[4],Location,PIN_G3,Yes +,HEX1[5],Location,PIN_D2,Yes +,HEX1[6],Location,PIN_D1,Yes +,HEX2[0],Location,PIN_G5,Yes +,HEX2[1],Location,PIN_G6,Yes +,HEX2[2],Location,PIN_C2,Yes +,HEX2[3],Location,PIN_C1,Yes +,HEX2[4],Location,PIN_E3,Yes +,HEX2[5],Location,PIN_E4,Yes +,HEX2[6],Location,PIN_D3,Yes +,HEX3[0],Location,PIN_F4,Yes +,HEX3[1],Location,PIN_D5,Yes +,HEX3[2],Location,PIN_D6,Yes +,HEX3[3],Location,PIN_J4,Yes +,HEX3[4],Location,PIN_L8,Yes +,HEX3[5],Location,PIN_F3,Yes +,HEX3[6],Location,PIN_D4,Yes +,HEX0[0],I/O Standard,LVTTL,Yes +,HEX0[1],I/O Standard,LVTTL,Yes +,HEX0[2],I/O Standard,LVTTL,Yes +,HEX0[3],I/O Standard,LVTTL,Yes +,HEX0[4],I/O Standard,LVTTL,Yes +,HEX0[5],I/O Standard,LVTTL,Yes +,HEX0[6],I/O Standard,LVTTL,Yes +,HEX1[0],I/O Standard,LVTTL,Yes +,HEX1[1],I/O Standard,LVTTL,Yes +,HEX1[2],I/O Standard,LVTTL,Yes +,HEX1[3],I/O Standard,LVTTL,Yes +,HEX1[4],I/O Standard,LVTTL,Yes +,HEX1[5],I/O Standard,LVTTL,Yes +,HEX1[6],I/O Standard,LVTTL,Yes +,HEX2[0],I/O Standard,LVTTL,Yes +,HEX2[1],I/O Standard,LVTTL,Yes +,HEX2[2],I/O Standard,LVTTL,Yes +,HEX2[3],I/O Standard,LVTTL,Yes +,HEX2[4],I/O Standard,LVTTL,Yes +,HEX2[5],I/O Standard,LVTTL,Yes +,HEX2[6],I/O Standard,LVTTL,Yes +,HEX3[0],I/O Standard,LVTTL,Yes +,HEX3[1],I/O Standard,LVTTL,Yes +,HEX3[2],I/O Standard,LVTTL,Yes +,HEX3[3],I/O Standard,LVTTL,Yes +,HEX3[4],I/O Standard,LVTTL,Yes +,HEX3[5],I/O Standard,LVTTL,Yes +,HEX3[6],I/O Standard,LVTTL,Yes +,KEY[0],Location,PIN_R22,Yes +,KEY[1],Location,PIN_R21,Yes +,KEY[2],Location,PIN_T22,Yes +,KEY[3],Location,PIN_T21,Yes +,LEDR[0],Location,PIN_R20,Yes +,LEDR[1],Location,PIN_R19,Yes +,LEDR[2],Location,PIN_U19,Yes +,LEDR[3],Location,PIN_Y19,Yes +,LEDR[4],Location,PIN_T18,Yes +,LEDR[5],Location,PIN_V19,Yes +,LEDR[6],Location,PIN_Y18,Yes +,LEDR[7],Location,PIN_U18,Yes +,LEDR[8],Location,PIN_R18,Yes +,LEDR[9],Location,PIN_R17,Yes +,LEDG[0],Location,PIN_U22,Yes +,LEDG[1],Location,PIN_U21,Yes +,LEDG[2],Location,PIN_V22,Yes +,LEDG[3],Location,PIN_V21,Yes +,LEDG[4],Location,PIN_W22,Yes +,LEDG[5],Location,PIN_W21,Yes +,LEDG[6],Location,PIN_Y22,Yes +,LEDG[7],Location,PIN_Y21,Yes +,KEY[0],I/O Standard,LVTTL,Yes +,KEY[1],I/O Standard,LVTTL,Yes +,KEY[2],I/O Standard,LVTTL,Yes +,KEY[3],I/O Standard,LVTTL,Yes +,LEDR[0],I/O Standard,LVTTL,Yes +,LEDR[1],I/O Standard,LVTTL,Yes +,LEDR[2],I/O Standard,LVTTL,Yes +,LEDR[3],I/O Standard,LVTTL,Yes +,LEDR[4],I/O Standard,LVTTL,Yes +,LEDR[5],I/O Standard,LVTTL,Yes +,LEDR[6],I/O Standard,LVTTL,Yes +,LEDR[7],I/O Standard,LVTTL,Yes +,LEDR[8],I/O Standard,LVTTL,Yes +,LEDR[9],I/O Standard,LVTTL,Yes +,LEDG[0],I/O Standard,LVTTL,Yes +,LEDG[1],I/O Standard,LVTTL,Yes +,LEDG[2],I/O Standard,LVTTL,Yes +,LEDG[3],I/O Standard,LVTTL,Yes +,LEDG[4],I/O Standard,LVTTL,Yes +,LEDG[5],I/O Standard,LVTTL,Yes +,LEDG[6],I/O Standard,LVTTL,Yes +,LEDG[7],I/O Standard,LVTTL,Yes +,CLOCK_27[0],Location,PIN_D12,Yes +,CLOCK_27[1],Location,PIN_E12,Yes +,CLOCK_24[0],Location,PIN_B12,Yes +,CLOCK_24[1],Location,PIN_A12,Yes +,CLOCK_50,Location,PIN_L1,Yes +,EXT_CLOCK,Location,PIN_M21,Yes +,CLOCK_27[1],I/O Standard,LVTTL,Yes +,CLOCK_24[0],I/O Standard,LVTTL,Yes +,CLOCK_24[1],I/O Standard,LVTTL,Yes +,CLOCK_50,I/O Standard,LVTTL,Yes +,EXT_CLOCK,I/O Standard,LVTTL,Yes +,PS2_CLK,Location,PIN_H15,Yes +,PS2_DAT,Location,PIN_J14,Yes +,UART_RXD,Location,PIN_F14,Yes +,UART_TXD,Location,PIN_G12,Yes +,PS2_CLK,I/O Standard,LVTTL,Yes +,PS2_DAT,I/O Standard,LVTTL,Yes +,UART_RXD,I/O Standard,LVTTL,Yes +,UART_TXD,I/O Standard,LVTTL,Yes +,TDI,Location,PIN_E8,Yes +,TCS,Location,PIN_D8,Yes +,TCK,Location,PIN_C7,Yes +,TDO,Location,PIN_D7,Yes +,TDI,I/O Standard,LVTTL,Yes +,TCS,I/O Standard,LVTTL,Yes +,TCK,I/O Standard,LVTTL,Yes +,TDO,I/O Standard,LVTTL,Yes +,VGA_R[0],Location,PIN_D9,Yes +,VGA_R[1],Location,PIN_C9,Yes +,VGA_R[2],Location,PIN_A7,Yes +,VGA_R[3],Location,PIN_B7,Yes +,VGA_G[0],Location,PIN_B8,Yes +,VGA_G[1],Location,PIN_C10,Yes +,VGA_G[2],Location,PIN_B9,Yes +,VGA_G[3],Location,PIN_A8,Yes +,VGA_B[0],Location,PIN_A9,Yes +,VGA_B[1],Location,PIN_D11,Yes +,VGA_B[2],Location,PIN_A10,Yes +,VGA_B[3],Location,PIN_B10,Yes +,VGA_HS,Location,PIN_A11,Yes +,VGA_VS,Location,PIN_B11,Yes +,VGA_R[0],I/O Standard,LVTTL,Yes +,VGA_R[1],I/O Standard,LVTTL,Yes +,VGA_R[2],I/O Standard,LVTTL,Yes +,VGA_R[3],I/O Standard,LVTTL,Yes +,VGA_G[0],I/O Standard,LVTTL,Yes +,VGA_G[1],I/O Standard,LVTTL,Yes +,VGA_G[2],I/O Standard,LVTTL,Yes +,VGA_G[3],I/O Standard,LVTTL,Yes +,VGA_B[0],I/O Standard,LVTTL,Yes +,VGA_B[1],I/O Standard,LVTTL,Yes +,VGA_B[2],I/O Standard,LVTTL,Yes +,VGA_B[3],I/O Standard,LVTTL,Yes +,VGA_HS,I/O Standard,LVTTL,Yes +,VGA_VS,I/O Standard,LVTTL,Yes +,I2C_SCLK,Location,PIN_A3,Yes +,I2C_SDAT,Location,PIN_B3,Yes +,AUD_ADCLRCK,Location,PIN_A6,Yes +,AUD_ADCDAT,Location,PIN_B6,Yes +,AUD_DACLRCK,Location,PIN_A5,Yes +,AUD_DACDAT,Location,PIN_B5,Yes +,AUD_XCK,Location,PIN_B4,Yes +,AUD_BCLK,Location,PIN_A4,Yes +,I2C_SCLK,I/O Standard,LVTTL,Yes +,I2C_SDAT,I/O Standard,LVTTL,Yes +,AUD_ADCLRCK,I/O Standard,LVTTL,Yes +,AUD_ADCDAT,I/O Standard,LVTTL,Yes +,AUD_DACLRCK,I/O Standard,LVTTL,Yes +,AUD_DACDAT,I/O Standard,LVTTL,Yes +,AUD_XCK,I/O Standard,LVTTL,Yes +,AUD_BCLK,I/O Standard,LVTTL,Yes +,DRAM_ADDR[0],Location,PIN_W4,Yes +,DRAM_ADDR[1],Location,PIN_W5,Yes +,DRAM_ADDR[2],Location,PIN_Y3,Yes +,DRAM_ADDR[3],Location,PIN_Y4,Yes +,DRAM_ADDR[4],Location,PIN_R6,Yes +,DRAM_ADDR[5],Location,PIN_R5,Yes +,DRAM_ADDR[6],Location,PIN_P6,Yes +,DRAM_ADDR[7],Location,PIN_P5,Yes +,DRAM_ADDR[8],Location,PIN_P3,Yes +,DRAM_ADDR[9],Location,PIN_N4,Yes +,DRAM_ADDR[10],Location,PIN_W3,Yes +,DRAM_ADDR[11],Location,PIN_N6,Yes +,DRAM_BA_0,Location,PIN_U3,Yes +,DRAM_BA_1,Location,PIN_V4,Yes +,DRAM_CAS_N,Location,PIN_T3,Yes +,DRAM_CKE,Location,PIN_N3,Yes +,DRAM_CLK,Location,PIN_U4,Yes +,DRAM_CS_N,Location,PIN_T6,Yes +,DRAM_DQ[0],Location,PIN_U1,Yes +,DRAM_DQ[1],Location,PIN_U2,Yes +,DRAM_DQ[2],Location,PIN_V1,Yes +,DRAM_DQ[3],Location,PIN_V2,Yes +,DRAM_DQ[4],Location,PIN_W1,Yes +,DRAM_DQ[5],Location,PIN_W2,Yes +,DRAM_DQ[6],Location,PIN_Y1,Yes +,DRAM_DQ[7],Location,PIN_Y2,Yes +,DRAM_DQ[8],Location,PIN_N1,Yes +,DRAM_DQ[9],Location,PIN_N2,Yes +,DRAM_DQ[10],Location,PIN_P1,Yes +,DRAM_DQ[11],Location,PIN_P2,Yes +,DRAM_DQ[12],Location,PIN_R1,Yes +,DRAM_DQ[13],Location,PIN_R2,Yes +,DRAM_DQ[14],Location,PIN_T1,Yes +,DRAM_DQ[15],Location,PIN_T2,Yes +,DRAM_LDQM,Location,PIN_R7,Yes +,DRAM_RAS_N,Location,PIN_T5,Yes +,DRAM_UDQM,Location,PIN_M5,Yes +,DRAM_WE_N,Location,PIN_R8,Yes +,FL_ADDR[0],Location,PIN_AB20,Yes +,FL_ADDR[1],Location,PIN_AA14,Yes +,FL_ADDR[2],Location,PIN_Y16,Yes +,FL_ADDR[3],Location,PIN_R15,Yes +,FL_ADDR[4],Location,PIN_T15,Yes +,FL_ADDR[5],Location,PIN_U15,Yes +,FL_ADDR[6],Location,PIN_V15,Yes +,FL_ADDR[7],Location,PIN_W15,Yes +,FL_ADDR[8],Location,PIN_R14,Yes +,FL_ADDR[9],Location,PIN_Y13,Yes +,FL_ADDR[10],Location,PIN_R12,Yes +,FL_ADDR[11],Location,PIN_T12,Yes +,FL_ADDR[12],Location,PIN_AB14,Yes +,FL_ADDR[13],Location,PIN_AA13,Yes +,FL_ADDR[14],Location,PIN_AB13,Yes +,FL_ADDR[15],Location,PIN_AA12,Yes +,FL_ADDR[16],Location,PIN_AB12,Yes +,FL_ADDR[17],Location,PIN_AA20,Yes +,FL_ADDR[18],Location,PIN_U14,Yes +,FL_ADDR[19],Location,PIN_V14,Yes +,FL_ADDR[20],Location,PIN_U13,Yes +,FL_ADDR[21],Location,PIN_R13,Yes +,FL_DQ[0],Location,PIN_AB16,Yes +,FL_DQ[1],Location,PIN_AA16,Yes +,FL_DQ[2],Location,PIN_AB17,Yes +,FL_DQ[3],Location,PIN_AA17,Yes +,FL_DQ[4],Location,PIN_AB18,Yes +,FL_DQ[5],Location,PIN_AA18,Yes +,FL_DQ[6],Location,PIN_AB19,Yes +,FL_DQ[7],Location,PIN_AA19,Yes +,FL_OE_N,Location,PIN_AA15,Yes +,FL_RST_N,Location,PIN_W14,Yes +,FL_WE_N,Location,PIN_Y14,Yes +,FL_CE_N,Location,PIN_AB15,Yes +,SRAM_ADDR[0],Location,PIN_AA3,Yes +,SRAM_ADDR[1],Location,PIN_AB3,Yes +,SRAM_ADDR[2],Location,PIN_AA4,Yes +,SRAM_ADDR[3],Location,PIN_AB4,Yes +,SRAM_ADDR[4],Location,PIN_AA5,Yes +,SRAM_ADDR[5],Location,PIN_AB10,Yes +,SRAM_ADDR[6],Location,PIN_AA11,Yes +,SRAM_ADDR[7],Location,PIN_AB11,Yes +,SRAM_ADDR[8],Location,PIN_V11,Yes +,SRAM_ADDR[9],Location,PIN_W11,Yes +,SRAM_ADDR[10],Location,PIN_R11,Yes +,SRAM_ADDR[11],Location,PIN_T11,Yes +,SRAM_ADDR[12],Location,PIN_Y10,Yes +,SRAM_ADDR[13],Location,PIN_U10,Yes +,SRAM_ADDR[14],Location,PIN_R10,Yes +,SRAM_ADDR[15],Location,PIN_T7,Yes +,SRAM_ADDR[16],Location,PIN_Y6,Yes +,SRAM_ADDR[17],Location,PIN_Y5,Yes +,SRAM_CE_N,Location,PIN_AB5,Yes +,SRAM_DQ[0],Location,PIN_AA6,Yes +,SRAM_DQ[1],Location,PIN_AB6,Yes +,SRAM_DQ[2],Location,PIN_AA7,Yes +,SRAM_DQ[3],Location,PIN_AB7,Yes +,SRAM_DQ[4],Location,PIN_AA8,Yes +,SRAM_DQ[5],Location,PIN_AB8,Yes +,SRAM_DQ[6],Location,PIN_AA9,Yes +,SRAM_DQ[7],Location,PIN_AB9,Yes +,SRAM_DQ[8],Location,PIN_Y9,Yes +,SRAM_DQ[9],Location,PIN_W9,Yes +,SRAM_DQ[10],Location,PIN_V9,Yes +,SRAM_DQ[11],Location,PIN_U9,Yes +,SRAM_DQ[12],Location,PIN_R9,Yes +,SRAM_DQ[13],Location,PIN_W8,Yes +,SRAM_DQ[14],Location,PIN_V8,Yes +,SRAM_DQ[15],Location,PIN_U8,Yes +,SRAM_LB_N,Location,PIN_Y7,Yes +,SRAM_OE_N,Location,PIN_T8,Yes +,SRAM_UB_N,Location,PIN_W7,Yes +,SRAM_WE_N,Location,PIN_AA10,Yes +,SD_nCS,Location,PIN_U20,Yes +,SD_MOSI,Location,PIN_Y20,Yes +,SD_SCLK,Location,PIN_V20,Yes +,SD_MISO,Location,PIN_W20,Yes + diff --git a/T65/T65.vhd b/T65/T65.vhd index 4a21d79..09253fe 100644 --- a/T65/T65.vhd +++ b/T65/T65.vhd @@ -1,564 +1,564 @@ --- **** --- T65(b) core. In an effort to merge and maintain bug fixes .... --- --- --- Ver 301 more merging --- Ver 300 Bugfixes by ehenciak added, started tidyup *bust* --- MikeJ March 2005 --- Latest version from www.fpgaarcade.com (original www.opencores.org) --- --- **** --- --- 65xx compatible microprocessor core --- --- Version : 0246 --- --- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written permission. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- Please report bugs to the author, but before you do so, please --- make sure that this is not a derivative work and that --- you have the latest version of this file. --- --- The latest version of this file can be found at: --- http://www.opencores.org/cvsweb.shtml/t65/ --- --- Limitations : --- --- 65C02 and 65C816 modes are incomplete --- Undocumented instructions are not supported --- Some interface signals behaves incorrect --- --- File history : --- --- 0246 : First release --- - -library IEEE; - use IEEE.std_logic_1164.all; - use IEEE.numeric_std.all; - use work.T65_Pack.all; - --- ehenciak 2-23-2005 : Added the enable signal so that one doesn't have to use --- the ready signal to limit the CPU. -entity T65 is - port( - Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 - Res_n : in std_logic; - Enable : in std_logic; - Clk : in std_logic; - Rdy : in std_logic; - Abort_n : in std_logic; - IRQ_n : in std_logic; - NMI_n : in std_logic; - SO_n : in std_logic; - R_W_n : out std_logic; - Sync : out std_logic; - EF : out std_logic; - MF : out std_logic; - XF : out std_logic; - ML_n : out std_logic; - VP_n : out std_logic; - VDA : out std_logic; - VPA : out std_logic; - A : out std_logic_vector(23 downto 0); - DI : in std_logic_vector(7 downto 0); - DO : out std_logic_vector(7 downto 0) - ); -end T65; - -architecture rtl of T65 is - - -- Registers - signal ABC, X, Y, D : std_logic_vector(15 downto 0); - signal P, AD, DL : std_logic_vector(7 downto 0) := x"00"; - signal BAH : std_logic_vector(7 downto 0); - signal BAL : std_logic_vector(8 downto 0); - signal PBR : std_logic_vector(7 downto 0); - signal DBR : std_logic_vector(7 downto 0); - signal PC : unsigned(15 downto 0); - signal S : unsigned(15 downto 0); - signal EF_i : std_logic; - signal MF_i : std_logic; - signal XF_i : std_logic; - - signal IR : std_logic_vector(7 downto 0); - signal MCycle : std_logic_vector(2 downto 0); - - signal Mode_r : std_logic_vector(1 downto 0); - signal ALU_Op_r : std_logic_vector(3 downto 0); - signal Write_Data_r : std_logic_vector(2 downto 0); - signal Set_Addr_To_r : std_logic_vector(1 downto 0); - signal PCAdder : unsigned(8 downto 0); - - signal RstCycle : std_logic; - signal IRQCycle : std_logic; - signal NMICycle : std_logic; - - signal B_o : std_logic; - signal SO_n_o : std_logic; - signal IRQ_n_o : std_logic; - signal NMI_n_o : std_logic; - signal NMIAct : std_logic; - - signal Break : std_logic; - - -- ALU signals - signal BusA : std_logic_vector(7 downto 0); - signal BusA_r : std_logic_vector(7 downto 0); - signal BusB : std_logic_vector(7 downto 0); - signal ALU_Q : std_logic_vector(7 downto 0); - signal P_Out : std_logic_vector(7 downto 0); - - -- Micro code outputs - signal LCycle : std_logic_vector(2 downto 0); - signal ALU_Op : std_logic_vector(3 downto 0); - signal Set_BusA_To : std_logic_vector(2 downto 0); - signal Set_Addr_To : std_logic_vector(1 downto 0); - signal Write_Data : std_logic_vector(2 downto 0); - signal Jump : std_logic_vector(1 downto 0); - signal BAAdd : std_logic_vector(1 downto 0); - signal BreakAtNA : std_logic; - signal ADAdd : std_logic; - signal AddY : std_logic; - signal PCAdd : std_logic; - signal Inc_S : std_logic; - signal Dec_S : std_logic; - signal LDA : std_logic; - signal LDP : std_logic; - signal LDX : std_logic; - signal LDY : std_logic; - signal LDS : std_logic; - signal LDDI : std_logic; - signal LDALU : std_logic; - signal LDAD : std_logic; - signal LDBAL : std_logic; - signal LDBAH : std_logic; - signal SaveP : std_logic; - signal Write : std_logic; - - signal really_rdy : std_logic; - signal R_W_n_i : std_logic; - -begin - -- ehenciak : gate Rdy with read/write to make an "OK, it's - -- really OK to stop the processor now if Rdy is - -- deasserted" signal - really_rdy <= Rdy or not(R_W_n_i); - - -- ehenciak : Drive R_W_n_i off chip. - R_W_n <= R_W_n_i; - - Sync <= '1' when MCycle = "000" else '0'; - EF <= EF_i; - MF <= MF_i; - XF <= XF_i; - ML_n <= '0' when IR(7 downto 6) /= "10" and IR(2 downto 1) = "11" and MCycle(2 downto 1) /= "00" else '1'; - VP_n <= '0' when IRQCycle = '1' and (MCycle = "101" or MCycle = "110") else '1'; - VDA <= '1' when Set_Addr_To_r /= "00" else '0'; -- Incorrect !!!!!!!!!!!! - VPA <= '1' when Jump(1) = '0' else '0'; -- Incorrect !!!!!!!!!!!! - - mcode : T65_MCode - port map( - Mode => Mode_r, - IR => IR, - MCycle => MCycle, - P => P, - LCycle => LCycle, - ALU_Op => ALU_Op, - Set_BusA_To => Set_BusA_To, - Set_Addr_To => Set_Addr_To, - Write_Data => Write_Data, - Jump => Jump, - BAAdd => BAAdd, - BreakAtNA => BreakAtNA, - ADAdd => ADAdd, - AddY => AddY, - PCAdd => PCAdd, - Inc_S => Inc_S, - Dec_S => Dec_S, - LDA => LDA, - LDP => LDP, - LDX => LDX, - LDY => LDY, - LDS => LDS, - LDDI => LDDI, - LDALU => LDALU, - LDAD => LDAD, - LDBAL => LDBAL, - LDBAH => LDBAH, - SaveP => SaveP, - Write => Write - ); - - alu : T65_ALU - port map( - Mode => Mode_r, - Op => ALU_Op_r, - BusA => BusA_r, - BusB => BusB, - P_In => P, - P_Out => P_Out, - Q => ALU_Q - ); - - process (Res_n, Clk) - begin - if Res_n = '0' then - PC <= (others => '0'); -- Program Counter - IR <= "00000000"; - S <= (others => '0'); -- Dummy !!!!!!!!!!!!!!!!!!!!! - D <= (others => '0'); - PBR <= (others => '0'); - DBR <= (others => '0'); - - Mode_r <= (others => '0'); - ALU_Op_r <= "1100"; - Write_Data_r <= "000"; - Set_Addr_To_r <= "00"; - - R_W_n_i <= '1'; - EF_i <= '1'; - MF_i <= '1'; - XF_i <= '1'; - - elsif Clk'event and Clk = '1' then - if (Enable = '1') then - if (really_rdy = '1') then - R_W_n_i <= not Write or RstCycle; - - D <= (others => '1'); -- Dummy - PBR <= (others => '1'); -- Dummy - DBR <= (others => '1'); -- Dummy - EF_i <= '0'; -- Dummy - MF_i <= '0'; -- Dummy - XF_i <= '0'; -- Dummy - - if MCycle = "000" then - Mode_r <= Mode; - - if IRQCycle = '0' and NMICycle = '0' then - PC <= PC + 1; - end if; - - if IRQCycle = '1' or NMICycle = '1' then - IR <= "00000000"; - else - IR <= DI; - end if; - end if; - - ALU_Op_r <= ALU_Op; - Write_Data_r <= Write_Data; - if Break = '1' then - Set_Addr_To_r <= "00"; - else - Set_Addr_To_r <= Set_Addr_To; - end if; - - if Inc_S = '1' then - S <= S + 1; - end if; - if Dec_S = '1' and RstCycle = '0' then - S <= S - 1; - end if; - if LDS = '1' then - S(7 downto 0) <= unsigned(ALU_Q); - end if; - - if IR = "00000000" and MCycle = "001" and IRQCycle = '0' and NMICycle = '0' then - PC <= PC + 1; - end if; - -- - -- jump control logic - -- - case Jump is - when "01" => - PC <= PC + 1; - - when "10" => - PC <= unsigned(DI & DL); - - when "11" => - if PCAdder(8) = '1' then - if DL(7) = '0' then - PC(15 downto 8) <= PC(15 downto 8) + 1; - else - PC(15 downto 8) <= PC(15 downto 8) - 1; - end if; - end if; - PC(7 downto 0) <= PCAdder(7 downto 0); - - when others => null; - end case; - end if; - end if; - end if; - end process; - - PCAdder <= resize(PC(7 downto 0),9) + resize(unsigned(DL(7) & DL),9) when PCAdd = '1' - else "0" & PC(7 downto 0); - - process (Clk) - begin - if Clk'event and Clk = '1' then - if (Enable = '1') then - if (really_rdy = '1') then - if MCycle = "000" then - if LDA = '1' then - ABC(7 downto 0) <= ALU_Q; - end if; - if LDX = '1' then - X(7 downto 0) <= ALU_Q; - end if; - if LDY = '1' then - Y(7 downto 0) <= ALU_Q; - end if; - if (LDA or LDX or LDY) = '1' then - P <= P_Out; - end if; - end if; - if SaveP = '1' then - P <= P_Out; - end if; - if LDP = '1' then - P <= ALU_Q; - end if; - if IR(4 downto 0) = "11000" then - case IR(7 downto 5) is - when "000" => - P(Flag_C) <= '0'; - when "001" => - P(Flag_C) <= '1'; - when "010" => - P(Flag_I) <= '0'; - when "011" => - P(Flag_I) <= '1'; - when "101" => - P(Flag_V) <= '0'; - when "110" => - P(Flag_D) <= '0'; - when "111" => - P(Flag_D) <= '1'; - when others => - end case; - end if; - - --if IR = "00000000" and MCycle = "011" and RstCycle = '0' and NMICycle = '0' and IRQCycle = '0' then - -- P(Flag_B) <= '1'; - --end if; - --if IR = "00000000" and MCycle = "100" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then - -- P(Flag_I) <= '1'; - -- P(Flag_B) <= B_o; - --end if; - - -- B=1 always on the 6502 - P(Flag_B) <= '1'; - if IR = "00000000" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then - if MCycle = "011" then - -- B=0 in *copy* of P pushed onto the stack - P(Flag_B) <= '0'; - elsif MCycle = "100" then - P(Flag_I) <= '1'; - end if; - end if; - - if SO_n_o = '1' and SO_n = '0' then - P(Flag_V) <= '1'; - end if; - if RstCycle = '1' and Mode_r /= "00" then - P(Flag_1) <= '1'; - P(Flag_D) <= '0'; - P(Flag_I) <= '1'; - end if; - P(Flag_1) <= '1'; - - B_o <= P(Flag_B); - SO_n_o <= SO_n; - IRQ_n_o <= IRQ_n; - NMI_n_o <= NMI_n; - end if; - end if; - end if; - end process; - ---------------------------------------------------------------------------- --- --- Buses --- ---------------------------------------------------------------------------- - - process (Res_n, Clk) - begin - if Res_n = '0' then - BusA_r <= (others => '0'); - BusB <= (others => '0'); - AD <= (others => '0'); - BAL <= (others => '0'); - BAH <= (others => '0'); - DL <= (others => '0'); - elsif Clk'event and Clk = '1' then - if (Enable = '1') then - if (Rdy = '1') then - BusA_r <= BusA; - BusB <= DI; - - case BAAdd is - when "01" => - -- BA Inc - AD <= std_logic_vector(unsigned(AD) + 1); - BAL <= std_logic_vector(unsigned(BAL) + 1); - when "10" => - -- BA Add - BAL <= std_logic_vector(resize(unsigned(BAL(7 downto 0)),9) + resize(unsigned(BusA),9)); - when "11" => - -- BA Adj - if BAL(8) = '1' then - BAH <= std_logic_vector(unsigned(BAH) + 1); - end if; - when others => - end case; - - -- ehenciak : modified to use Y register as well (bugfix) - if ADAdd = '1' then - if (AddY = '1') then - AD <= std_logic_vector(unsigned(AD) + unsigned(Y(7 downto 0))); - else - AD <= std_logic_vector(unsigned(AD) + unsigned(X(7 downto 0))); - end if; - end if; - - if IR = "00000000" then - BAL <= (others => '1'); - BAH <= (others => '1'); - if RstCycle = '1' then - BAL(2 downto 0) <= "100"; - elsif NMICycle = '1' then - BAL(2 downto 0) <= "010"; - else - BAL(2 downto 0) <= "110"; - end if; - if Set_addr_To_r = "11" then - BAL(0) <= '1'; - end if; - end if; - - - if LDDI = '1' then - DL <= DI; - end if; - if LDALU = '1' then - DL <= ALU_Q; - end if; - if LDAD = '1' then - AD <= DI; - end if; - if LDBAL = '1' then - BAL(7 downto 0) <= DI; - end if; - if LDBAH = '1' then - BAH <= DI; - end if; - end if; - end if; - end if; - end process; - - Break <= (BreakAtNA and not BAL(8)) or (PCAdd and not PCAdder(8)); - - - with Set_BusA_To select - BusA <= DI when "000", - ABC(7 downto 0) when "001", - X(7 downto 0) when "010", - Y(7 downto 0) when "011", - std_logic_vector(S(7 downto 0)) when "100", - P when "101", - (others => '-') when others; - - with Set_Addr_To_r select - A <= "0000000000000001" & std_logic_vector(S(7 downto 0)) when "01", - DBR & "00000000" & AD when "10", - "00000000" & BAH & BAL(7 downto 0) when "11", - PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when others; - - with Write_Data_r select - DO <= DL when "000", - ABC(7 downto 0) when "001", - X(7 downto 0) when "010", - Y(7 downto 0) when "011", - std_logic_vector(S(7 downto 0)) when "100", - P when "101", - std_logic_vector(PC(7 downto 0)) when "110", - std_logic_vector(PC(15 downto 8)) when others; - -------------------------------------------------------------------------- --- --- Main state machine --- -------------------------------------------------------------------------- - - process (Res_n, Clk) - begin - if Res_n = '0' then - MCycle <= "001"; - RstCycle <= '1'; - IRQCycle <= '0'; - NMICycle <= '0'; - NMIAct <= '0'; - elsif Clk'event and Clk = '1' then - if (Enable = '1') then - if (really_rdy = '1') then - if MCycle = LCycle or Break = '1' then - MCycle <= "000"; - RstCycle <= '0'; - IRQCycle <= '0'; - NMICycle <= '0'; - if NMIAct = '1' then - NMICycle <= '1'; - elsif IRQ_n_o = '0' and P(Flag_I) = '0' then - IRQCycle <= '1'; - end if; - else - MCycle <= std_logic_vector(unsigned(MCycle) + 1); - end if; - - if NMICycle = '1' then - NMIAct <= '0'; - end if; - if NMI_n_o = '1' and NMI_n = '0' then - NMIAct <= '1'; - end if; - end if; - end if; - end if; - end process; - -end; +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 301 more merging +-- Ver 300 Bugfixes by ehenciak added, started tidyup *bust* +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- 65xx compatible microprocessor core +-- +-- Version : 0246 +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t65/ +-- +-- Limitations : +-- +-- 65C02 and 65C816 modes are incomplete +-- Undocumented instructions are not supported +-- Some interface signals behaves incorrect +-- +-- File history : +-- +-- 0246 : First release +-- + +library IEEE; + use IEEE.std_logic_1164.all; + use IEEE.numeric_std.all; + use work.T65_Pack.all; + +-- ehenciak 2-23-2005 : Added the enable signal so that one doesn't have to use +-- the ready signal to limit the CPU. +entity T65 is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 + Res_n : in std_logic; + Enable : in std_logic; + Clk : in std_logic; + Rdy : in std_logic; + Abort_n : in std_logic; + IRQ_n : in std_logic; + NMI_n : in std_logic; + SO_n : in std_logic; + R_W_n : out std_logic; + Sync : out std_logic; + EF : out std_logic; + MF : out std_logic; + XF : out std_logic; + ML_n : out std_logic; + VP_n : out std_logic; + VDA : out std_logic; + VPA : out std_logic; + A : out std_logic_vector(23 downto 0); + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0) + ); +end T65; + +architecture rtl of T65 is + + -- Registers + signal ABC, X, Y, D : std_logic_vector(15 downto 0); + signal P, AD, DL : std_logic_vector(7 downto 0) := x"00"; + signal BAH : std_logic_vector(7 downto 0); + signal BAL : std_logic_vector(8 downto 0); + signal PBR : std_logic_vector(7 downto 0); + signal DBR : std_logic_vector(7 downto 0); + signal PC : unsigned(15 downto 0); + signal S : unsigned(15 downto 0); + signal EF_i : std_logic; + signal MF_i : std_logic; + signal XF_i : std_logic; + + signal IR : std_logic_vector(7 downto 0); + signal MCycle : std_logic_vector(2 downto 0); + + signal Mode_r : std_logic_vector(1 downto 0); + signal ALU_Op_r : std_logic_vector(3 downto 0); + signal Write_Data_r : std_logic_vector(2 downto 0); + signal Set_Addr_To_r : std_logic_vector(1 downto 0); + signal PCAdder : unsigned(8 downto 0); + + signal RstCycle : std_logic; + signal IRQCycle : std_logic; + signal NMICycle : std_logic; + + signal B_o : std_logic; + signal SO_n_o : std_logic; + signal IRQ_n_o : std_logic; + signal NMI_n_o : std_logic; + signal NMIAct : std_logic; + + signal Break : std_logic; + + -- ALU signals + signal BusA : std_logic_vector(7 downto 0); + signal BusA_r : std_logic_vector(7 downto 0); + signal BusB : std_logic_vector(7 downto 0); + signal ALU_Q : std_logic_vector(7 downto 0); + signal P_Out : std_logic_vector(7 downto 0); + + -- Micro code outputs + signal LCycle : std_logic_vector(2 downto 0); + signal ALU_Op : std_logic_vector(3 downto 0); + signal Set_BusA_To : std_logic_vector(2 downto 0); + signal Set_Addr_To : std_logic_vector(1 downto 0); + signal Write_Data : std_logic_vector(2 downto 0); + signal Jump : std_logic_vector(1 downto 0); + signal BAAdd : std_logic_vector(1 downto 0); + signal BreakAtNA : std_logic; + signal ADAdd : std_logic; + signal AddY : std_logic; + signal PCAdd : std_logic; + signal Inc_S : std_logic; + signal Dec_S : std_logic; + signal LDA : std_logic; + signal LDP : std_logic; + signal LDX : std_logic; + signal LDY : std_logic; + signal LDS : std_logic; + signal LDDI : std_logic; + signal LDALU : std_logic; + signal LDAD : std_logic; + signal LDBAL : std_logic; + signal LDBAH : std_logic; + signal SaveP : std_logic; + signal Write : std_logic; + + signal really_rdy : std_logic; + signal R_W_n_i : std_logic; + +begin + -- ehenciak : gate Rdy with read/write to make an "OK, it's + -- really OK to stop the processor now if Rdy is + -- deasserted" signal + really_rdy <= Rdy or not(R_W_n_i); + + -- ehenciak : Drive R_W_n_i off chip. + R_W_n <= R_W_n_i; + + Sync <= '1' when MCycle = "000" else '0'; + EF <= EF_i; + MF <= MF_i; + XF <= XF_i; + ML_n <= '0' when IR(7 downto 6) /= "10" and IR(2 downto 1) = "11" and MCycle(2 downto 1) /= "00" else '1'; + VP_n <= '0' when IRQCycle = '1' and (MCycle = "101" or MCycle = "110") else '1'; + VDA <= '1' when Set_Addr_To_r /= "00" else '0'; -- Incorrect !!!!!!!!!!!! + VPA <= '1' when Jump(1) = '0' else '0'; -- Incorrect !!!!!!!!!!!! + + mcode : T65_MCode + port map( + Mode => Mode_r, + IR => IR, + MCycle => MCycle, + P => P, + LCycle => LCycle, + ALU_Op => ALU_Op, + Set_BusA_To => Set_BusA_To, + Set_Addr_To => Set_Addr_To, + Write_Data => Write_Data, + Jump => Jump, + BAAdd => BAAdd, + BreakAtNA => BreakAtNA, + ADAdd => ADAdd, + AddY => AddY, + PCAdd => PCAdd, + Inc_S => Inc_S, + Dec_S => Dec_S, + LDA => LDA, + LDP => LDP, + LDX => LDX, + LDY => LDY, + LDS => LDS, + LDDI => LDDI, + LDALU => LDALU, + LDAD => LDAD, + LDBAL => LDBAL, + LDBAH => LDBAH, + SaveP => SaveP, + Write => Write + ); + + alu : T65_ALU + port map( + Mode => Mode_r, + Op => ALU_Op_r, + BusA => BusA_r, + BusB => BusB, + P_In => P, + P_Out => P_Out, + Q => ALU_Q + ); + + process (Res_n, Clk) + begin + if Res_n = '0' then + PC <= (others => '0'); -- Program Counter + IR <= "00000000"; + S <= (others => '0'); -- Dummy !!!!!!!!!!!!!!!!!!!!! + D <= (others => '0'); + PBR <= (others => '0'); + DBR <= (others => '0'); + + Mode_r <= (others => '0'); + ALU_Op_r <= "1100"; + Write_Data_r <= "000"; + Set_Addr_To_r <= "00"; + + R_W_n_i <= '1'; + EF_i <= '1'; + MF_i <= '1'; + XF_i <= '1'; + + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + R_W_n_i <= not Write or RstCycle; + + D <= (others => '1'); -- Dummy + PBR <= (others => '1'); -- Dummy + DBR <= (others => '1'); -- Dummy + EF_i <= '0'; -- Dummy + MF_i <= '0'; -- Dummy + XF_i <= '0'; -- Dummy + + if MCycle = "000" then + Mode_r <= Mode; + + if IRQCycle = '0' and NMICycle = '0' then + PC <= PC + 1; + end if; + + if IRQCycle = '1' or NMICycle = '1' then + IR <= "00000000"; + else + IR <= DI; + end if; + end if; + + ALU_Op_r <= ALU_Op; + Write_Data_r <= Write_Data; + if Break = '1' then + Set_Addr_To_r <= "00"; + else + Set_Addr_To_r <= Set_Addr_To; + end if; + + if Inc_S = '1' then + S <= S + 1; + end if; + if Dec_S = '1' and RstCycle = '0' then + S <= S - 1; + end if; + if LDS = '1' then + S(7 downto 0) <= unsigned(ALU_Q); + end if; + + if IR = "00000000" and MCycle = "001" and IRQCycle = '0' and NMICycle = '0' then + PC <= PC + 1; + end if; + -- + -- jump control logic + -- + case Jump is + when "01" => + PC <= PC + 1; + + when "10" => + PC <= unsigned(DI & DL); + + when "11" => + if PCAdder(8) = '1' then + if DL(7) = '0' then + PC(15 downto 8) <= PC(15 downto 8) + 1; + else + PC(15 downto 8) <= PC(15 downto 8) - 1; + end if; + end if; + PC(7 downto 0) <= PCAdder(7 downto 0); + + when others => null; + end case; + end if; + end if; + end if; + end process; + + PCAdder <= resize(PC(7 downto 0),9) + resize(unsigned(DL(7) & DL),9) when PCAdd = '1' + else "0" & PC(7 downto 0); + + process (Clk) + begin + if Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + if MCycle = "000" then + if LDA = '1' then + ABC(7 downto 0) <= ALU_Q; + end if; + if LDX = '1' then + X(7 downto 0) <= ALU_Q; + end if; + if LDY = '1' then + Y(7 downto 0) <= ALU_Q; + end if; + if (LDA or LDX or LDY) = '1' then + P <= P_Out; + end if; + end if; + if SaveP = '1' then + P <= P_Out; + end if; + if LDP = '1' then + P <= ALU_Q; + end if; + if IR(4 downto 0) = "11000" then + case IR(7 downto 5) is + when "000" => + P(Flag_C) <= '0'; + when "001" => + P(Flag_C) <= '1'; + when "010" => + P(Flag_I) <= '0'; + when "011" => + P(Flag_I) <= '1'; + when "101" => + P(Flag_V) <= '0'; + when "110" => + P(Flag_D) <= '0'; + when "111" => + P(Flag_D) <= '1'; + when others => + end case; + end if; + + --if IR = "00000000" and MCycle = "011" and RstCycle = '0' and NMICycle = '0' and IRQCycle = '0' then + -- P(Flag_B) <= '1'; + --end if; + --if IR = "00000000" and MCycle = "100" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then + -- P(Flag_I) <= '1'; + -- P(Flag_B) <= B_o; + --end if; + + -- B=1 always on the 6502 + P(Flag_B) <= '1'; + if IR = "00000000" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then + if MCycle = "011" then + -- B=0 in *copy* of P pushed onto the stack + P(Flag_B) <= '0'; + elsif MCycle = "100" then + P(Flag_I) <= '1'; + end if; + end if; + + if SO_n_o = '1' and SO_n = '0' then + P(Flag_V) <= '1'; + end if; + if RstCycle = '1' and Mode_r /= "00" then + P(Flag_1) <= '1'; + P(Flag_D) <= '0'; + P(Flag_I) <= '1'; + end if; + P(Flag_1) <= '1'; + + B_o <= P(Flag_B); + SO_n_o <= SO_n; + IRQ_n_o <= IRQ_n; + NMI_n_o <= NMI_n; + end if; + end if; + end if; + end process; + +--------------------------------------------------------------------------- +-- +-- Buses +-- +--------------------------------------------------------------------------- + + process (Res_n, Clk) + begin + if Res_n = '0' then + BusA_r <= (others => '0'); + BusB <= (others => '0'); + AD <= (others => '0'); + BAL <= (others => '0'); + BAH <= (others => '0'); + DL <= (others => '0'); + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (Rdy = '1') then + BusA_r <= BusA; + BusB <= DI; + + case BAAdd is + when "01" => + -- BA Inc + AD <= std_logic_vector(unsigned(AD) + 1); + BAL <= std_logic_vector(unsigned(BAL) + 1); + when "10" => + -- BA Add + BAL <= std_logic_vector(resize(unsigned(BAL(7 downto 0)),9) + resize(unsigned(BusA),9)); + when "11" => + -- BA Adj + if BAL(8) = '1' then + BAH <= std_logic_vector(unsigned(BAH) + 1); + end if; + when others => + end case; + + -- ehenciak : modified to use Y register as well (bugfix) + if ADAdd = '1' then + if (AddY = '1') then + AD <= std_logic_vector(unsigned(AD) + unsigned(Y(7 downto 0))); + else + AD <= std_logic_vector(unsigned(AD) + unsigned(X(7 downto 0))); + end if; + end if; + + if IR = "00000000" then + BAL <= (others => '1'); + BAH <= (others => '1'); + if RstCycle = '1' then + BAL(2 downto 0) <= "100"; + elsif NMICycle = '1' then + BAL(2 downto 0) <= "010"; + else + BAL(2 downto 0) <= "110"; + end if; + if Set_addr_To_r = "11" then + BAL(0) <= '1'; + end if; + end if; + + + if LDDI = '1' then + DL <= DI; + end if; + if LDALU = '1' then + DL <= ALU_Q; + end if; + if LDAD = '1' then + AD <= DI; + end if; + if LDBAL = '1' then + BAL(7 downto 0) <= DI; + end if; + if LDBAH = '1' then + BAH <= DI; + end if; + end if; + end if; + end if; + end process; + + Break <= (BreakAtNA and not BAL(8)) or (PCAdd and not PCAdder(8)); + + + with Set_BusA_To select + BusA <= DI when "000", + ABC(7 downto 0) when "001", + X(7 downto 0) when "010", + Y(7 downto 0) when "011", + std_logic_vector(S(7 downto 0)) when "100", + P when "101", + (others => '-') when others; + + with Set_Addr_To_r select + A <= "0000000000000001" & std_logic_vector(S(7 downto 0)) when "01", + DBR & "00000000" & AD when "10", + "00000000" & BAH & BAL(7 downto 0) when "11", + PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when others; + + with Write_Data_r select + DO <= DL when "000", + ABC(7 downto 0) when "001", + X(7 downto 0) when "010", + Y(7 downto 0) when "011", + std_logic_vector(S(7 downto 0)) when "100", + P when "101", + std_logic_vector(PC(7 downto 0)) when "110", + std_logic_vector(PC(15 downto 8)) when others; + +------------------------------------------------------------------------- +-- +-- Main state machine +-- +------------------------------------------------------------------------- + + process (Res_n, Clk) + begin + if Res_n = '0' then + MCycle <= "001"; + RstCycle <= '1'; + IRQCycle <= '0'; + NMICycle <= '0'; + NMIAct <= '0'; + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + if MCycle = LCycle or Break = '1' then + MCycle <= "000"; + RstCycle <= '0'; + IRQCycle <= '0'; + NMICycle <= '0'; + if NMIAct = '1' then + NMICycle <= '1'; + elsif IRQ_n_o = '0' and P(Flag_I) = '0' then + IRQCycle <= '1'; + end if; + else + MCycle <= std_logic_vector(unsigned(MCycle) + 1); + end if; + + if NMICycle = '1' then + NMIAct <= '0'; + end if; + if NMI_n_o = '1' and NMI_n = '0' then + NMIAct <= '1'; + end if; + end if; + end if; + end if; + end process; + +end; diff --git a/T65/T65_ALU.vhd b/T65/T65_ALU.vhd index d9d25e1..b1f6d63 100644 --- a/T65/T65_ALU.vhd +++ b/T65/T65_ALU.vhd @@ -1,260 +1,260 @@ --- **** --- T65(b) core. In an effort to merge and maintain bug fixes .... --- --- --- Ver 300 Bugfixes by ehenciak added --- MikeJ March 2005 --- Latest version from www.fpgaarcade.com (original www.opencores.org) --- --- **** --- --- 6502 compatible microprocessor core --- --- Version : 0245 --- --- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written permission. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- Please report bugs to the author, but before you do so, please --- make sure that this is not a derivative work and that --- you have the latest version of this file. --- --- The latest version of this file can be found at: --- http://www.opencores.org/cvsweb.shtml/t65/ --- --- Limitations : --- --- File history : --- --- 0245 : First version --- - -library IEEE; -use IEEE.std_logic_1164.all; -use IEEE.numeric_std.all; -use work.T65_Pack.all; - -entity T65_ALU is - port( - Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 - Op : in std_logic_vector(3 downto 0); - BusA : in std_logic_vector(7 downto 0); - BusB : in std_logic_vector(7 downto 0); - P_In : in std_logic_vector(7 downto 0); - P_Out : out std_logic_vector(7 downto 0); - Q : out std_logic_vector(7 downto 0) - ); -end T65_ALU; - -architecture rtl of T65_ALU is - - -- AddSub variables (temporary signals) - signal ADC_Z : std_logic; - signal ADC_C : std_logic; - signal ADC_V : std_logic; - signal ADC_N : std_logic; - signal ADC_Q : std_logic_vector(7 downto 0); - signal SBC_Z : std_logic; - signal SBC_C : std_logic; - signal SBC_V : std_logic; - signal SBC_N : std_logic; - signal SBC_Q : std_logic_vector(7 downto 0); - -begin - - process (P_In, BusA, BusB) - variable AL : unsigned(6 downto 0); - variable AH : unsigned(6 downto 0); - variable C : std_logic; - begin - AL := resize(unsigned(BusA(3 downto 0) & P_In(Flag_C)), 7) + resize(unsigned(BusB(3 downto 0) & "1"), 7); - AH := resize(unsigned(BusA(7 downto 4) & AL(5)), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); - --- pragma translate_off - if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; - if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; --- pragma translate_on - - if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then - ADC_Z <= '1'; - else - ADC_Z <= '0'; - end if; - - if AL(5 downto 1) > 9 and P_In(Flag_D) = '1' then - AL(6 downto 1) := AL(6 downto 1) + 6; - end if; - - C := AL(6) or AL(5); - AH := resize(unsigned(BusA(7 downto 4) & C), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); - - ADC_N <= AH(4); - ADC_V <= (AH(4) xor BusA(7)) and not (BusA(7) xor BusB(7)); - --- pragma translate_off - if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; --- pragma translate_on - - if AH(5 downto 1) > 9 and P_In(Flag_D) = '1' then - AH(6 downto 1) := AH(6 downto 1) + 6; - end if; - - ADC_C <= AH(6) or AH(5); - - ADC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); - end process; - - process (Op, P_In, BusA, BusB) - variable AL : unsigned(6 downto 0); - variable AH : unsigned(5 downto 0); - variable C : std_logic; - begin - C := P_In(Flag_C) or not Op(0); - AL := resize(unsigned(BusA(3 downto 0) & C), 7) - resize(unsigned(BusB(3 downto 0) & "1"), 6); - AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(5)), 6); - --- pragma translate_off - if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; - if is_x(std_logic_vector(AH)) then AH := "000000"; end if; --- pragma translate_on - - if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then - SBC_Z <= '1'; - else - SBC_Z <= '0'; - end if; - - SBC_C <= not AH(5); - SBC_V <= (AH(4) xor BusA(7)) and (BusA(7) xor BusB(7)); - SBC_N <= AH(4); - - if P_In(Flag_D) = '1' then - if AL(5) = '1' then - AL(5 downto 1) := AL(5 downto 1) - 6; - end if; - AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(6)), 6); - if AH(5) = '1' then - AH(5 downto 1) := AH(5 downto 1) - 6; - end if; - end if; - - SBC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); - end process; - - process (Op, P_In, BusA, BusB, - ADC_Z, ADC_C, ADC_V, ADC_N, ADC_Q, - SBC_Z, SBC_C, SBC_V, SBC_N, SBC_Q) - variable Q_t : std_logic_vector(7 downto 0); - begin - -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC - -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC - P_Out <= P_In; - Q_t := BusA; - case Op(3 downto 0) is - when "0000" => - -- ORA - Q_t := BusA or BusB; - when "0001" => - -- AND - Q_t := BusA and BusB; - when "0010" => - -- EOR - Q_t := BusA xor BusB; - when "0011" => - -- ADC - P_Out(Flag_V) <= ADC_V; - P_Out(Flag_C) <= ADC_C; - Q_t := ADC_Q; - when "0101" | "1101" => - -- LDA - when "0110" => - -- CMP - P_Out(Flag_C) <= SBC_C; - when "0111" => - -- SBC - P_Out(Flag_V) <= SBC_V; - P_Out(Flag_C) <= SBC_C; - Q_t := SBC_Q; - when "1000" => - -- ASL - Q_t := BusA(6 downto 0) & "0"; - P_Out(Flag_C) <= BusA(7); - when "1001" => - -- ROL - Q_t := BusA(6 downto 0) & P_In(Flag_C); - P_Out(Flag_C) <= BusA(7); - when "1010" => - -- LSR - Q_t := "0" & BusA(7 downto 1); - P_Out(Flag_C) <= BusA(0); - when "1011" => - -- ROR - Q_t := P_In(Flag_C) & BusA(7 downto 1); - P_Out(Flag_C) <= BusA(0); - when "1100" => - -- BIT - P_Out(Flag_V) <= BusB(6); - when "1110" => - -- DEC - Q_t := std_logic_vector(unsigned(BusA) - 1); - when "1111" => - -- INC - Q_t := std_logic_vector(unsigned(BusA) + 1); - when others => - end case; - - case Op(3 downto 0) is - when "0011" => - P_Out(Flag_N) <= ADC_N; - P_Out(Flag_Z) <= ADC_Z; - when "0110" | "0111" => - P_Out(Flag_N) <= SBC_N; - P_Out(Flag_Z) <= SBC_Z; - when "0100" => - when "1100" => - P_Out(Flag_N) <= BusB(7); - if (BusA and BusB) = "00000000" then - P_Out(Flag_Z) <= '1'; - else - P_Out(Flag_Z) <= '0'; - end if; - when others => - P_Out(Flag_N) <= Q_t(7); - if Q_t = "00000000" then - P_Out(Flag_Z) <= '1'; - else - P_Out(Flag_Z) <= '0'; - end if; - end case; - - Q <= Q_t; - end process; - -end; +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 300 Bugfixes by ehenciak added +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- 6502 compatible microprocessor core +-- +-- Version : 0245 +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t65/ +-- +-- Limitations : +-- +-- File history : +-- +-- 0245 : First version +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.T65_Pack.all; + +entity T65_ALU is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + Op : in std_logic_vector(3 downto 0); + BusA : in std_logic_vector(7 downto 0); + BusB : in std_logic_vector(7 downto 0); + P_In : in std_logic_vector(7 downto 0); + P_Out : out std_logic_vector(7 downto 0); + Q : out std_logic_vector(7 downto 0) + ); +end T65_ALU; + +architecture rtl of T65_ALU is + + -- AddSub variables (temporary signals) + signal ADC_Z : std_logic; + signal ADC_C : std_logic; + signal ADC_V : std_logic; + signal ADC_N : std_logic; + signal ADC_Q : std_logic_vector(7 downto 0); + signal SBC_Z : std_logic; + signal SBC_C : std_logic; + signal SBC_V : std_logic; + signal SBC_N : std_logic; + signal SBC_Q : std_logic_vector(7 downto 0); + +begin + + process (P_In, BusA, BusB) + variable AL : unsigned(6 downto 0); + variable AH : unsigned(6 downto 0); + variable C : std_logic; + begin + AL := resize(unsigned(BusA(3 downto 0) & P_In(Flag_C)), 7) + resize(unsigned(BusB(3 downto 0) & "1"), 7); + AH := resize(unsigned(BusA(7 downto 4) & AL(5)), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); + +-- pragma translate_off + if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; + if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; +-- pragma translate_on + + if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then + ADC_Z <= '1'; + else + ADC_Z <= '0'; + end if; + + if AL(5 downto 1) > 9 and P_In(Flag_D) = '1' then + AL(6 downto 1) := AL(6 downto 1) + 6; + end if; + + C := AL(6) or AL(5); + AH := resize(unsigned(BusA(7 downto 4) & C), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); + + ADC_N <= AH(4); + ADC_V <= (AH(4) xor BusA(7)) and not (BusA(7) xor BusB(7)); + +-- pragma translate_off + if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; +-- pragma translate_on + + if AH(5 downto 1) > 9 and P_In(Flag_D) = '1' then + AH(6 downto 1) := AH(6 downto 1) + 6; + end if; + + ADC_C <= AH(6) or AH(5); + + ADC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + end process; + + process (Op, P_In, BusA, BusB) + variable AL : unsigned(6 downto 0); + variable AH : unsigned(5 downto 0); + variable C : std_logic; + begin + C := P_In(Flag_C) or not Op(0); + AL := resize(unsigned(BusA(3 downto 0) & C), 7) - resize(unsigned(BusB(3 downto 0) & "1"), 6); + AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(5)), 6); + +-- pragma translate_off + if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; + if is_x(std_logic_vector(AH)) then AH := "000000"; end if; +-- pragma translate_on + + if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then + SBC_Z <= '1'; + else + SBC_Z <= '0'; + end if; + + SBC_C <= not AH(5); + SBC_V <= (AH(4) xor BusA(7)) and (BusA(7) xor BusB(7)); + SBC_N <= AH(4); + + if P_In(Flag_D) = '1' then + if AL(5) = '1' then + AL(5 downto 1) := AL(5 downto 1) - 6; + end if; + AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(6)), 6); + if AH(5) = '1' then + AH(5 downto 1) := AH(5 downto 1) - 6; + end if; + end if; + + SBC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + end process; + + process (Op, P_In, BusA, BusB, + ADC_Z, ADC_C, ADC_V, ADC_N, ADC_Q, + SBC_Z, SBC_C, SBC_V, SBC_N, SBC_Q) + variable Q_t : std_logic_vector(7 downto 0); + begin + -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC + -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC + P_Out <= P_In; + Q_t := BusA; + case Op(3 downto 0) is + when "0000" => + -- ORA + Q_t := BusA or BusB; + when "0001" => + -- AND + Q_t := BusA and BusB; + when "0010" => + -- EOR + Q_t := BusA xor BusB; + when "0011" => + -- ADC + P_Out(Flag_V) <= ADC_V; + P_Out(Flag_C) <= ADC_C; + Q_t := ADC_Q; + when "0101" | "1101" => + -- LDA + when "0110" => + -- CMP + P_Out(Flag_C) <= SBC_C; + when "0111" => + -- SBC + P_Out(Flag_V) <= SBC_V; + P_Out(Flag_C) <= SBC_C; + Q_t := SBC_Q; + when "1000" => + -- ASL + Q_t := BusA(6 downto 0) & "0"; + P_Out(Flag_C) <= BusA(7); + when "1001" => + -- ROL + Q_t := BusA(6 downto 0) & P_In(Flag_C); + P_Out(Flag_C) <= BusA(7); + when "1010" => + -- LSR + Q_t := "0" & BusA(7 downto 1); + P_Out(Flag_C) <= BusA(0); + when "1011" => + -- ROR + Q_t := P_In(Flag_C) & BusA(7 downto 1); + P_Out(Flag_C) <= BusA(0); + when "1100" => + -- BIT + P_Out(Flag_V) <= BusB(6); + when "1110" => + -- DEC + Q_t := std_logic_vector(unsigned(BusA) - 1); + when "1111" => + -- INC + Q_t := std_logic_vector(unsigned(BusA) + 1); + when others => + end case; + + case Op(3 downto 0) is + when "0011" => + P_Out(Flag_N) <= ADC_N; + P_Out(Flag_Z) <= ADC_Z; + when "0110" | "0111" => + P_Out(Flag_N) <= SBC_N; + P_Out(Flag_Z) <= SBC_Z; + when "0100" => + when "1100" => + P_Out(Flag_N) <= BusB(7); + if (BusA and BusB) = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + when others => + P_Out(Flag_N) <= Q_t(7); + if Q_t = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + end case; + + Q <= Q_t; + end process; + +end; diff --git a/T65/T65_MCode.vhd b/T65/T65_MCode.vhd index 3fd40d8..6c6c864 100644 --- a/T65/T65_MCode.vhd +++ b/T65/T65_MCode.vhd @@ -1,1052 +1,1052 @@ --- **** --- T65(b) core. In an effort to merge and maintain bug fixes .... --- --- --- Ver 302 minor timing fixes --- Ver 301 Jump timing fixed --- Ver 300 Bugfixes by ehenciak added --- MikeJ March 2005 --- Latest version from www.fpgaarcade.com (original www.opencores.org) --- --- **** --- --- 65xx compatible microprocessor core --- --- Version : 0246 + fix --- --- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written permission. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- Please report bugs to the author, but before you do so, please --- make sure that this is not a derivative work and that --- you have the latest version of this file. --- --- The latest version of this file can be found at: --- http://www.opencores.org/cvsweb.shtml/t65/ --- --- Limitations : --- --- 65C02 --- supported : inc, dec, phx, plx, phy, ply --- missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8 --- --- File history : --- --- 0246 : First release --- - -library IEEE; -use IEEE.std_logic_1164.all; -use IEEE.numeric_std.all; -use work.T65_Pack.all; - -entity T65_MCode is - port( - Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 - IR : in std_logic_vector(7 downto 0); - MCycle : in std_logic_vector(2 downto 0); - P : in std_logic_vector(7 downto 0); - LCycle : out std_logic_vector(2 downto 0); - ALU_Op : out std_logic_vector(3 downto 0); - Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P - Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA - Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH - Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel - BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj - BreakAtNA : out std_logic; - ADAdd : out std_logic; - AddY : out std_logic; - PCAdd : out std_logic; - Inc_S : out std_logic; - Dec_S : out std_logic; - LDA : out std_logic; - LDP : out std_logic; - LDX : out std_logic; - LDY : out std_logic; - LDS : out std_logic; - LDDI : out std_logic; - LDALU : out std_logic; - LDAD : out std_logic; - LDBAL : out std_logic; - LDBAH : out std_logic; - SaveP : out std_logic; - Write : out std_logic - ); -end T65_MCode; - -architecture rtl of T65_MCode is - - signal Branch : std_logic; - -begin - - with IR(7 downto 5) select - Branch <= not P(Flag_N) when "000", - P(Flag_N) when "001", - not P(Flag_V) when "010", - P(Flag_V) when "011", - not P(Flag_C) when "100", - P(Flag_C) when "101", - not P(Flag_Z) when "110", - P(Flag_Z) when others; - - process (IR, MCycle, P, Branch, Mode) - begin - LCycle <= "001"; - Set_BusA_To <= "001"; -- A - Set_Addr_To <= (others => '0'); - Write_Data <= (others => '0'); - Jump <= (others => '0'); - BAAdd <= "00"; - BreakAtNA <= '0'; - ADAdd <= '0'; - PCAdd <= '0'; - Inc_S <= '0'; - Dec_S <= '0'; - LDA <= '0'; - LDP <= '0'; - LDX <= '0'; - LDY <= '0'; - LDS <= '0'; - LDDI <= '0'; - LDALU <= '0'; - LDAD <= '0'; - LDBAL <= '0'; - LDBAH <= '0'; - SaveP <= '0'; - Write <= '0'; - AddY <= '0'; - - case IR(7 downto 5) is - when "100" => - --{{{ - case IR(1 downto 0) is - when "00" => - Set_BusA_To <= "011"; -- Y - Write_Data <= "011"; -- Y - when "10" => - Set_BusA_To <= "010"; -- X - Write_Data <= "010"; -- X - when others => - Write_Data <= "001"; -- A - end case; - --}}} - when "101" => - --{{{ - case IR(1 downto 0) is - when "00" => - if IR(4) /= '1' or IR(2) /= '0' then - LDY <= '1'; - end if; - when "10" => - LDX <= '1'; - when others => - LDA <= '1'; - end case; - Set_BusA_To <= "000"; -- DI - --}}} - when "110" => - --{{{ - case IR(1 downto 0) is - when "00" => - if IR(4) = '0' then - LDY <= '1'; - end if; - Set_BusA_To <= "011"; -- Y - when others => - Set_BusA_To <= "001"; -- A - end case; - --}}} - when "111" => - --{{{ - case IR(1 downto 0) is - when "00" => - if IR(4) = '0' then - LDX <= '1'; - end if; - Set_BusA_To <= "010"; -- X - when others => - Set_BusA_To <= "001"; -- A - end case; - --}}} - when others => - end case; - - if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then - Set_BusA_To <= "000"; -- DI - end if; - - case IR(4 downto 0) is - when "00000" | "01000" | "01010" | "11000" | "11010" => - --{{{ - -- Implied - case IR is - when "00000000" => - -- BRK - LCycle <= "110"; - case to_integer(unsigned(MCycle)) is - when 1 => - Set_Addr_To <= "01"; -- S - Write_Data <= "111"; -- PCH - Write <= '1'; - when 2 => - Dec_S <= '1'; - Set_Addr_To <= "01"; -- S - Write_Data <= "110"; -- PCL - Write <= '1'; - when 3 => - Dec_S <= '1'; - Set_Addr_To <= "01"; -- S - Write_Data <= "101"; -- P - Write <= '1'; - when 4 => - Dec_S <= '1'; - Set_Addr_To <= "11"; -- BA - when 5 => - LDDI <= '1'; - Set_Addr_To <= "11"; -- BA - when 6 => - Jump <= "10"; -- DIDL - when others => - end case; - when "00100000" => - -- JSR - LCycle <= "101"; - case to_integer(unsigned(MCycle)) is - when 1 => - Jump <= "01"; - LDDI <= '1'; - Set_Addr_To <= "01"; -- S - when 2 => - Set_Addr_To <= "01"; -- S - Write_Data <= "111"; -- PCH - Write <= '1'; - when 3 => - Dec_S <= '1'; - Set_Addr_To <= "01"; -- S - Write_Data <= "110"; -- PCL - Write <= '1'; - when 4 => - Dec_S <= '1'; - when 5 => - Jump <= "10"; -- DIDL - when others => - end case; - when "01000000" => - -- RTI - LCycle <= "101"; - case to_integer(unsigned(MCycle)) is - when 1 => - Set_Addr_To <= "01"; -- S - when 2 => - Inc_S <= '1'; - Set_Addr_To <= "01"; -- S - when 3 => - Inc_S <= '1'; - Set_Addr_To <= "01"; -- S - Set_BusA_To <= "000"; -- DI - when 4 => - LDP <= '1'; - Inc_S <= '1'; - LDDI <= '1'; - Set_Addr_To <= "01"; -- S - when 5 => - Jump <= "10"; -- DIDL - when others => - end case; - when "01100000" => - -- RTS - LCycle <= "101"; - case to_integer(unsigned(MCycle)) is - when 1 => - Set_Addr_To <= "01"; -- S - when 2 => - Inc_S <= '1'; - Set_Addr_To <= "01"; -- S - when 3 => - Inc_S <= '1'; - LDDI <= '1'; - Set_Addr_To <= "01"; -- S - when 4 => - Jump <= "10"; -- DIDL - when 5 => - Jump <= "01"; - when others => - end case; - when "00001000" | "01001000" | "01011010" | "11011010" => - -- PHP, PHA, PHY*, PHX* - LCycle <= "010"; - if Mode = "00" and IR(1) = '1' then - LCycle <= "001"; - end if; - case to_integer(unsigned(MCycle)) is - when 1 => - case IR(7 downto 4) is - when "0000" => - Write_Data <= "101"; -- P - when "0100" => - Write_Data <= "001"; -- A - when "0101" => - Write_Data <= "011"; -- Y - when "1101" => - Write_Data <= "010"; -- X - when others => - end case; - Write <= '1'; - Set_Addr_To <= "01"; -- S - when 2 => - Dec_S <= '1'; - when others => - end case; - when "00101000" | "01101000" | "01111010" | "11111010" => - -- PLP, PLA, PLY*, PLX* - LCycle <= "011"; - if Mode = "00" and IR(1) = '1' then - LCycle <= "001"; - end if; - case IR(7 downto 4) is - when "0010" => - LDP <= '1'; - when "0110" => - LDA <= '1'; - when "0111" => - if Mode /= "00" then - LDY <= '1'; - end if; - when "1111" => - if Mode /= "00" then - LDX <= '1'; - end if; - when others => - end case; - case to_integer(unsigned(MCycle)) is - when 0 => - SaveP <= '1'; - when 1 => - Set_Addr_To <= "01"; -- S - when 2 => - Inc_S <= '1'; - Set_Addr_To <= "01"; -- S - when 3 => - Set_BusA_To <= "000"; -- DI - when others => - end case; - when "10100000" | "11000000" | "11100000" => - -- LDY, CPY, CPX - -- Immediate - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Jump <= "01"; - when others => - end case; - when "10001000" => - -- DEY - LDY <= '1'; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Set_BusA_To <= "011"; -- Y - when others => - end case; - when "11001010" => - -- DEX - LDX <= '1'; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Set_BusA_To <= "010"; -- X - when others => - end case; - when "00011010" | "00111010" => - -- INC*, DEC* - if Mode /= "00" then - LDA <= '1'; -- A - end if; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Set_BusA_To <= "100"; -- S - when others => - end case; - when "00001010" | "00101010" | "01001010" | "01101010" => - -- ASL, ROL, LSR, ROR - LDA <= '1'; -- A - Set_BusA_To <= "001"; -- A - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - when others => - end case; - when "10001010" | "10011000" => - -- TYA, TXA - LDA <= '1'; -- A - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - when others => - end case; - when "10101010" | "10101000" => - -- TAX, TAY - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Set_BusA_To <= "001"; -- A - when others => - end case; - when "10011010" => - -- TXS - case to_integer(unsigned(MCycle)) is - when 0 => - LDS <= '1'; - when 1 => - when others => - end case; - when "10111010" => - -- TSX - LDX <= '1'; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Set_BusA_To <= "100"; -- S - when others => - end case; - - -- when "00011000" | "00111000" | "01011000" | "01111000" | "10111000" | "11011000" | "11111000" | "11001000" | "11101000" => - -- -- CLC, SEC, CLI, SEI, CLV, CLD, SED, INY, INX - -- case to_integer(unsigned(MCycle)) is - -- when 1 => - -- when others => - -- end case; - when others => - case to_integer(unsigned(MCycle)) is - when 0 => - when others => - end case; - end case; - --}}} - - when "00001" | "00011" => - --{{{ - -- Zero Page Indexed Indirect (d,x) - LCycle <= "101"; - if IR(7 downto 6) /= "10" then - LDA <= '1'; - end if; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Jump <= "01"; - LDAD <= '1'; - Set_Addr_To <= "10"; -- AD - when 2 => - ADAdd <= '1'; - Set_Addr_To <= "10"; -- AD - when 3 => - BAAdd <= "01"; -- DB Inc - LDBAL <= '1'; - Set_Addr_To <= "10"; -- AD - when 4 => - LDBAH <= '1'; - if IR(7 downto 5) = "100" then - Write <= '1'; - end if; - Set_Addr_To <= "11"; -- BA - when 5 => - when others => - end case; - --}}} - - when "01001" | "01011" => - --{{{ - -- Immediate - LDA <= '1'; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Jump <= "01"; - when others => - end case; - - --}}} - - when "00010" | "10010" => - --{{{ - -- Immediate, KIL - LDX <= '1'; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - if IR = "10100010" then - -- LDX - Jump <= "01"; - else - -- KIL !!!!!!!!!!!!!!!!!!!!!!!!!!!!! - end if; - when others => - end case; - --}}} - - when "00100" => - --{{{ - -- Zero Page - LCycle <= "010"; - case to_integer(unsigned(MCycle)) is - when 0 => - if IR(7 downto 5) = "001" then - SaveP <= '1'; - end if; - when 1 => - Jump <= "01"; - LDAD <= '1'; - if IR(7 downto 5) = "100" then - Write <= '1'; - end if; - Set_Addr_To <= "10"; -- AD - when 2 => - when others => - end case; - --}}} - - when "00101" | "00110" | "00111" => - --{{{ - -- Zero Page - if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then - -- Read-Modify-Write - LCycle <= "100"; - case to_integer(unsigned(MCycle)) is - when 1 => - Jump <= "01"; - LDAD <= '1'; - Set_Addr_To <= "10"; -- AD - when 2 => - LDDI <= '1'; - Write <= '1'; - Set_Addr_To <= "10"; -- AD - when 3 => - LDALU <= '1'; - SaveP <= '1'; - Write <= '1'; - Set_Addr_To <= "10"; -- AD - when 4 => - when others => - end case; - else - LCycle <= "010"; - if IR(7 downto 6) /= "10" then - LDA <= '1'; - end if; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Jump <= "01"; - LDAD <= '1'; - if IR(7 downto 5) = "100" then - Write <= '1'; - end if; - Set_Addr_To <= "10"; -- AD - when 2 => - when others => - end case; - end if; - --}}} - - when "01100" => - --{{{ - -- Absolute - if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then - -- JMP - if IR(5) = '0' then - --LCycle <= "011"; - LCycle <= "010"; - case to_integer(unsigned(MCycle)) is - when 1 => - Jump <= "01"; - LDDI <= '1'; - when 2 => - Jump <= "10"; -- DIDL - when others => - end case; - else - --LCycle <= "101"; - LCycle <= "100"; -- mikej - case to_integer(unsigned(MCycle)) is - when 1 => - Jump <= "01"; - LDDI <= '1'; - LDBAL <= '1'; - when 2 => - LDBAH <= '1'; - if Mode /= "00" then - Jump <= "10"; -- DIDL - end if; - if Mode = "00" then - Set_Addr_To <= "11"; -- BA - end if; - when 3 => - LDDI <= '1'; - if Mode = "00" then - Set_Addr_To <= "11"; -- BA - BAAdd <= "01"; -- DB Inc - else - Jump <= "01"; - end if; - when 4 => - Jump <= "10"; -- DIDL - when others => - end case; - end if; - else - LCycle <= "011"; - case to_integer(unsigned(MCycle)) is - when 0 => - if IR(7 downto 5) = "001" then - SaveP <= '1'; - end if; - when 1 => - Jump <= "01"; - LDBAL <= '1'; - when 2 => - Jump <= "01"; - LDBAH <= '1'; - if IR(7 downto 5) = "100" then - Write <= '1'; - end if; - Set_Addr_To <= "11"; -- BA - when 3 => - when others => - end case; - end if; - --}}} - - when "01101" | "01110" | "01111" => - --{{{ - -- Absolute - if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then - -- Read-Modify-Write - LCycle <= "101"; - case to_integer(unsigned(MCycle)) is - when 1 => - Jump <= "01"; - LDBAL <= '1'; - when 2 => - Jump <= "01"; - LDBAH <= '1'; - Set_Addr_To <= "11"; -- BA - when 3 => - LDDI <= '1'; - Write <= '1'; - Set_Addr_To <= "11"; -- BA - when 4 => - Write <= '1'; - LDALU <= '1'; - SaveP <= '1'; - Set_Addr_To <= "11"; -- BA - when 5 => - SaveP <= '0'; -- MIKEJ was 1 - when others => - end case; - else - LCycle <= "011"; - if IR(7 downto 6) /= "10" then - LDA <= '1'; - end if; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Jump <= "01"; - LDBAL <= '1'; - when 2 => - Jump <= "01"; - LDBAH <= '1'; - if IR(7 downto 5) = "100" then - Write <= '1'; - end if; - Set_Addr_To <= "11"; -- BA - when 3 => - when others => - end case; - end if; - --}}} - - when "10000" => - --{{{ - -- Relative - - -- This circuit dictates when the last - -- microcycle occurs for the branch depending on - -- whether or not the branch is taken and if a page - -- is crossed... - if (Branch = '1') then - - LCycle <= "011"; -- We're done @ T3 if branching...upper - -- level logic will stop at T2 if no page cross - -- (See the Break signal) - else - - LCycle <= "001"; - - end if; - - -- This decodes the current microcycle and takes the - -- proper course of action... - case to_integer(unsigned(MCycle)) is - - -- On the T1 microcycle, increment the program counter - -- and instruct the upper level logic to fetch the offset - -- from the Din bus and store it in the data latches. This - -- will be the last microcycle if the branch isn't taken. - when 1 => - - Jump <= "01"; -- Increments the PC by one (PC will now be PC+2) - -- from microcycle T0. - - LDDI <= '1'; -- Tells logic in top level (T65.vhd) to route - -- the Din bus to the memory data latch (DL) - -- so that the branch offset is fetched. - - -- In microcycle T2, tell the logic in the top level to - -- add the offset. If the most significant byte of the - -- program counter (i.e. the current "page") does not need - -- updating, we are done here...the Break signal at the - -- T65.vhd level takes care of that... - when 2 => - - Jump <= "11"; -- Tell the PC Jump logic to use relative mode. - - PCAdd <= '1'; -- This tells the PC adder to update itself with - -- the current offset recently fetched from - -- memory. - - -- The following is microcycle T3 : - -- The program counter should be completely updated - -- on this cycle after the page cross is detected. - -- We don't need to do anything here... - when 3 => - - - when others => null; -- Do nothing. - - end case; - --}}} - - when "10001" | "10011" => - --{{{ - -- Zero Page Indirect Indexed (d),y - LCycle <= "101"; - if IR(7 downto 6) /= "10" then - LDA <= '1'; - end if; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Jump <= "01"; - LDAD <= '1'; - Set_Addr_To <= "10"; -- AD - when 2 => - LDBAL <= '1'; - BAAdd <= "01"; -- DB Inc - Set_Addr_To <= "10"; -- AD - when 3 => - Set_BusA_To <= "011"; -- Y - BAAdd <= "10"; -- BA Add - LDBAH <= '1'; - Set_Addr_To <= "11"; -- BA - when 4 => - BAAdd <= "11"; -- BA Adj - if IR(7 downto 5) = "100" then - Write <= '1'; - else - BreakAtNA <= '1'; - end if; - Set_Addr_To <= "11"; -- BA - when 5 => - when others => - end case; - --}}} - - when "10100" | "10101" | "10110" | "10111" => - --{{{ - -- Zero Page, X - if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then - -- Read-Modify-Write - LCycle <= "101"; - case to_integer(unsigned(MCycle)) is - when 1 => - Jump <= "01"; - LDAD <= '1'; - Set_Addr_To <= "10"; -- AD - when 2 => - ADAdd <= '1'; - Set_Addr_To <= "10"; -- AD - when 3 => - LDDI <= '1'; - Write <= '1'; - Set_Addr_To <= "10"; -- AD - when 4 => - LDALU <= '1'; - SaveP <= '1'; - Write <= '1'; - Set_Addr_To <= "10"; -- AD - when 5 => - when others => - end case; - else - LCycle <= "011"; - if IR(7 downto 6) /= "10" then - LDA <= '1'; - end if; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Jump <= "01"; - LDAD <= '1'; - Set_Addr_To <= "10"; -- AD - when 2 => - ADAdd <= '1'; - -- Added this check for Y reg. use... - if (IR(3 downto 0) = "0110") then - AddY <= '1'; - end if; - - if IR(7 downto 5) = "100" then - Write <= '1'; - end if; - Set_Addr_To <= "10"; -- AD - when 3 => null; - when others => - end case; - end if; - --}}} - - when "11001" | "11011" => - --{{{ - -- Absolute Y - LCycle <= "100"; - if IR(7 downto 6) /= "10" then - LDA <= '1'; - end if; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Jump <= "01"; - LDBAL <= '1'; - when 2 => - Jump <= "01"; - Set_BusA_To <= "011"; -- Y - BAAdd <= "10"; -- BA Add - LDBAH <= '1'; - Set_Addr_To <= "11"; -- BA - when 3 => - BAAdd <= "11"; -- BA adj - if IR(7 downto 5) = "100" then - Write <= '1'; - else - BreakAtNA <= '1'; - end if; - Set_Addr_To <= "11"; -- BA - when 4 => - when others => - end case; - --}}} - - when "11100" | "11101" | "11110" | "11111" => - --{{{ - -- Absolute X - - if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then - -- Read-Modify-Write - LCycle <= "110"; - case to_integer(unsigned(MCycle)) is - when 1 => - Jump <= "01"; - LDBAL <= '1'; - when 2 => - Jump <= "01"; - Set_BusA_To <= "010"; -- X - BAAdd <= "10"; -- BA Add - LDBAH <= '1'; - Set_Addr_To <= "11"; -- BA - when 3 => - BAAdd <= "11"; -- BA adj - Set_Addr_To <= "11"; -- BA - when 4 => - LDDI <= '1'; - Write <= '1'; - Set_Addr_To <= "11"; -- BA - when 5 => - LDALU <= '1'; - SaveP <= '1'; - Write <= '1'; - Set_Addr_To <= "11"; -- BA - when 6 => - when others => - end case; - else - LCycle <= "100"; - if IR(7 downto 6) /= "10" then - LDA <= '1'; - end if; - case to_integer(unsigned(MCycle)) is - when 0 => - when 1 => - Jump <= "01"; - LDBAL <= '1'; - when 2 => - Jump <= "01"; - -- mikej - -- special case 0xBE which uses Y reg as index!! - if (IR = "10111110") then - Set_BusA_To <= "011"; -- Y - else - Set_BusA_To <= "010"; -- X - end if; - BAAdd <= "10"; -- BA Add - LDBAH <= '1'; - Set_Addr_To <= "11"; -- BA - when 3 => - BAAdd <= "11"; -- BA adj - if IR(7 downto 5) = "100" then - Write <= '1'; - else - BreakAtNA <= '1'; - end if; - Set_Addr_To <= "11"; -- BA - when 4 => - when others => - end case; - end if; - --}}} - when others => - end case; - end process; - - process (IR, MCycle) - begin - -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC - -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC - case IR(1 downto 0) is - when "00" => - --{{{ - case IR(4 downto 2) is - when "000" | "001" | "011" => - case IR(7 downto 5) is - when "110" | "111" => - -- CP - ALU_Op <= "0110"; - when "101" => - -- LD - ALU_Op <= "0101"; - when "001" => - -- BIT - ALU_Op <= "1100"; - when others => - -- NOP/ST - ALU_Op <= "0100"; - end case; - when "010" => - case IR(7 downto 5) is - when "111" | "110" => - -- IN - ALU_Op <= "1111"; - when "100" => - -- DEY - ALU_Op <= "1110"; - when others => - -- LD - ALU_Op <= "1101"; - end case; - when "110" => - case IR(7 downto 5) is - when "100" => - -- TYA - ALU_Op <= "1101"; - when others => - ALU_Op <= "----"; - end case; - when others => - case IR(7 downto 5) is - when "101" => - -- LD - ALU_Op <= "1101"; - when others => - ALU_Op <= "0100"; - end case; - end case; - --}}} - when "01" => -- OR - --{{{ - ALU_Op(3) <= '0'; - ALU_Op(2 downto 0) <= IR(7 downto 5); - --}}} - when "10" => - --{{{ - ALU_Op(3) <= '1'; - ALU_Op(2 downto 0) <= IR(7 downto 5); - case IR(7 downto 5) is - when "000" => - if IR(4 downto 2) = "110" then - -- INC - ALU_Op <= "1111"; - end if; - when "001" => - if IR(4 downto 2) = "110" then - -- DEC - ALU_Op <= "1110"; - end if; - when "100" => - if IR(4 downto 2) = "010" then - -- TXA - ALU_Op <= "0101"; - else - ALU_Op <= "0100"; - end if; - when others => - end case; - --}}} - when others => - --{{{ - case IR(7 downto 5) is - when "100" => - ALU_Op <= "0100"; - when others => - if MCycle = "000" then - ALU_Op(3) <= '0'; - ALU_Op(2 downto 0) <= IR(7 downto 5); - else - ALU_Op(3) <= '1'; - ALU_Op(2 downto 0) <= IR(7 downto 5); - end if; - end case; - --}}} - end case; - end process; - -end; +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 302 minor timing fixes +-- Ver 301 Jump timing fixed +-- Ver 300 Bugfixes by ehenciak added +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- 65xx compatible microprocessor core +-- +-- Version : 0246 + fix +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t65/ +-- +-- Limitations : +-- +-- 65C02 +-- supported : inc, dec, phx, plx, phy, ply +-- missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8 +-- +-- File history : +-- +-- 0246 : First release +-- + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.T65_Pack.all; + +entity T65_MCode is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + IR : in std_logic_vector(7 downto 0); + MCycle : in std_logic_vector(2 downto 0); + P : in std_logic_vector(7 downto 0); + LCycle : out std_logic_vector(2 downto 0); + ALU_Op : out std_logic_vector(3 downto 0); + Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P + Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA + Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH + Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel + BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj + BreakAtNA : out std_logic; + ADAdd : out std_logic; + AddY : out std_logic; + PCAdd : out std_logic; + Inc_S : out std_logic; + Dec_S : out std_logic; + LDA : out std_logic; + LDP : out std_logic; + LDX : out std_logic; + LDY : out std_logic; + LDS : out std_logic; + LDDI : out std_logic; + LDALU : out std_logic; + LDAD : out std_logic; + LDBAL : out std_logic; + LDBAH : out std_logic; + SaveP : out std_logic; + Write : out std_logic + ); +end T65_MCode; + +architecture rtl of T65_MCode is + + signal Branch : std_logic; + +begin + + with IR(7 downto 5) select + Branch <= not P(Flag_N) when "000", + P(Flag_N) when "001", + not P(Flag_V) when "010", + P(Flag_V) when "011", + not P(Flag_C) when "100", + P(Flag_C) when "101", + not P(Flag_Z) when "110", + P(Flag_Z) when others; + + process (IR, MCycle, P, Branch, Mode) + begin + LCycle <= "001"; + Set_BusA_To <= "001"; -- A + Set_Addr_To <= (others => '0'); + Write_Data <= (others => '0'); + Jump <= (others => '0'); + BAAdd <= "00"; + BreakAtNA <= '0'; + ADAdd <= '0'; + PCAdd <= '0'; + Inc_S <= '0'; + Dec_S <= '0'; + LDA <= '0'; + LDP <= '0'; + LDX <= '0'; + LDY <= '0'; + LDS <= '0'; + LDDI <= '0'; + LDALU <= '0'; + LDAD <= '0'; + LDBAL <= '0'; + LDBAH <= '0'; + SaveP <= '0'; + Write <= '0'; + AddY <= '0'; + + case IR(7 downto 5) is + when "100" => + --{{{ + case IR(1 downto 0) is + when "00" => + Set_BusA_To <= "011"; -- Y + Write_Data <= "011"; -- Y + when "10" => + Set_BusA_To <= "010"; -- X + Write_Data <= "010"; -- X + when others => + Write_Data <= "001"; -- A + end case; + --}}} + when "101" => + --{{{ + case IR(1 downto 0) is + when "00" => + if IR(4) /= '1' or IR(2) /= '0' then + LDY <= '1'; + end if; + when "10" => + LDX <= '1'; + when others => + LDA <= '1'; + end case; + Set_BusA_To <= "000"; -- DI + --}}} + when "110" => + --{{{ + case IR(1 downto 0) is + when "00" => + if IR(4) = '0' then + LDY <= '1'; + end if; + Set_BusA_To <= "011"; -- Y + when others => + Set_BusA_To <= "001"; -- A + end case; + --}}} + when "111" => + --{{{ + case IR(1 downto 0) is + when "00" => + if IR(4) = '0' then + LDX <= '1'; + end if; + Set_BusA_To <= "010"; -- X + when others => + Set_BusA_To <= "001"; -- A + end case; + --}}} + when others => + end case; + + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + Set_BusA_To <= "000"; -- DI + end if; + + case IR(4 downto 0) is + when "00000" | "01000" | "01010" | "11000" | "11010" => + --{{{ + -- Implied + case IR is + when "00000000" => + -- BRK + LCycle <= "110"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= "01"; -- S + Write_Data <= "111"; -- PCH + Write <= '1'; + when 2 => + Dec_S <= '1'; + Set_Addr_To <= "01"; -- S + Write_Data <= "110"; -- PCL + Write <= '1'; + when 3 => + Dec_S <= '1'; + Set_Addr_To <= "01"; -- S + Write_Data <= "101"; -- P + Write <= '1'; + when 4 => + Dec_S <= '1'; + Set_Addr_To <= "11"; -- BA + when 5 => + LDDI <= '1'; + Set_Addr_To <= "11"; -- BA + when 6 => + Jump <= "10"; -- DIDL + when others => + end case; + when "00100000" => + -- JSR + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDDI <= '1'; + Set_Addr_To <= "01"; -- S + when 2 => + Set_Addr_To <= "01"; -- S + Write_Data <= "111"; -- PCH + Write <= '1'; + when 3 => + Dec_S <= '1'; + Set_Addr_To <= "01"; -- S + Write_Data <= "110"; -- PCL + Write <= '1'; + when 4 => + Dec_S <= '1'; + when 5 => + Jump <= "10"; -- DIDL + when others => + end case; + when "01000000" => + -- RTI + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= "01"; -- S + when 2 => + Inc_S <= '1'; + Set_Addr_To <= "01"; -- S + when 3 => + Inc_S <= '1'; + Set_Addr_To <= "01"; -- S + Set_BusA_To <= "000"; -- DI + when 4 => + LDP <= '1'; + Inc_S <= '1'; + LDDI <= '1'; + Set_Addr_To <= "01"; -- S + when 5 => + Jump <= "10"; -- DIDL + when others => + end case; + when "01100000" => + -- RTS + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Set_Addr_To <= "01"; -- S + when 2 => + Inc_S <= '1'; + Set_Addr_To <= "01"; -- S + when 3 => + Inc_S <= '1'; + LDDI <= '1'; + Set_Addr_To <= "01"; -- S + when 4 => + Jump <= "10"; -- DIDL + when 5 => + Jump <= "01"; + when others => + end case; + when "00001000" | "01001000" | "01011010" | "11011010" => + -- PHP, PHA, PHY*, PHX* + LCycle <= "010"; + if Mode = "00" and IR(1) = '1' then + LCycle <= "001"; + end if; + case to_integer(unsigned(MCycle)) is + when 1 => + case IR(7 downto 4) is + when "0000" => + Write_Data <= "101"; -- P + when "0100" => + Write_Data <= "001"; -- A + when "0101" => + Write_Data <= "011"; -- Y + when "1101" => + Write_Data <= "010"; -- X + when others => + end case; + Write <= '1'; + Set_Addr_To <= "01"; -- S + when 2 => + Dec_S <= '1'; + when others => + end case; + when "00101000" | "01101000" | "01111010" | "11111010" => + -- PLP, PLA, PLY*, PLX* + LCycle <= "011"; + if Mode = "00" and IR(1) = '1' then + LCycle <= "001"; + end if; + case IR(7 downto 4) is + when "0010" => + LDP <= '1'; + when "0110" => + LDA <= '1'; + when "0111" => + if Mode /= "00" then + LDY <= '1'; + end if; + when "1111" => + if Mode /= "00" then + LDX <= '1'; + end if; + when others => + end case; + case to_integer(unsigned(MCycle)) is + when 0 => + SaveP <= '1'; + when 1 => + Set_Addr_To <= "01"; -- S + when 2 => + Inc_S <= '1'; + Set_Addr_To <= "01"; -- S + when 3 => + Set_BusA_To <= "000"; -- DI + when others => + end case; + when "10100000" | "11000000" | "11100000" => + -- LDY, CPY, CPX + -- Immediate + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + when others => + end case; + when "10001000" => + -- DEY + LDY <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "011"; -- Y + when others => + end case; + when "11001010" => + -- DEX + LDX <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "010"; -- X + when others => + end case; + when "00011010" | "00111010" => + -- INC*, DEC* + if Mode /= "00" then + LDA <= '1'; -- A + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "100"; -- S + when others => + end case; + when "00001010" | "00101010" | "01001010" | "01101010" => + -- ASL, ROL, LSR, ROR + LDA <= '1'; -- A + Set_BusA_To <= "001"; -- A + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + when others => + end case; + when "10001010" | "10011000" => + -- TYA, TXA + LDA <= '1'; -- A + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + when others => + end case; + when "10101010" | "10101000" => + -- TAX, TAY + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "001"; -- A + when others => + end case; + when "10011010" => + -- TXS + case to_integer(unsigned(MCycle)) is + when 0 => + LDS <= '1'; + when 1 => + when others => + end case; + when "10111010" => + -- TSX + LDX <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Set_BusA_To <= "100"; -- S + when others => + end case; + + -- when "00011000" | "00111000" | "01011000" | "01111000" | "10111000" | "11011000" | "11111000" | "11001000" | "11101000" => + -- -- CLC, SEC, CLI, SEI, CLV, CLD, SED, INY, INX + -- case to_integer(unsigned(MCycle)) is + -- when 1 => + -- when others => + -- end case; + when others => + case to_integer(unsigned(MCycle)) is + when 0 => + when others => + end case; + end case; + --}}} + + when "00001" | "00011" => + --{{{ + -- Zero Page Indexed Indirect (d,x) + LCycle <= "101"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + ADAdd <= '1'; + Set_Addr_To <= "10"; -- AD + when 3 => + BAAdd <= "01"; -- DB Inc + LDBAL <= '1'; + Set_Addr_To <= "10"; -- AD + when 4 => + LDBAH <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 5 => + when others => + end case; + --}}} + + when "01001" | "01011" => + --{{{ + -- Immediate + LDA <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + when others => + end case; + + --}}} + + when "00010" | "10010" => + --{{{ + -- Immediate, KIL + LDX <= '1'; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + if IR = "10100010" then + -- LDX + Jump <= "01"; + else + -- KIL !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + end if; + when others => + end case; + --}}} + + when "00100" => + --{{{ + -- Zero Page + LCycle <= "010"; + case to_integer(unsigned(MCycle)) is + when 0 => + if IR(7 downto 5) = "001" then + SaveP <= '1'; + end if; + when 1 => + Jump <= "01"; + LDAD <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "10"; -- AD + when 2 => + when others => + end case; + --}}} + + when "00101" | "00110" | "00111" => + --{{{ + -- Zero Page + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + -- Read-Modify-Write + LCycle <= "100"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + LDDI <= '1'; + Write <= '1'; + Set_Addr_To <= "10"; -- AD + when 3 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= "10"; -- AD + when 4 => + when others => + end case; + else + LCycle <= "010"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDAD <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "10"; -- AD + when 2 => + when others => + end case; + end if; + --}}} + + when "01100" => + --{{{ + -- Absolute + if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then + -- JMP + if IR(5) = '0' then + --LCycle <= "011"; + LCycle <= "010"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDDI <= '1'; + when 2 => + Jump <= "10"; -- DIDL + when others => + end case; + else + --LCycle <= "101"; + LCycle <= "100"; -- mikej + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDDI <= '1'; + LDBAL <= '1'; + when 2 => + LDBAH <= '1'; + if Mode /= "00" then + Jump <= "10"; -- DIDL + end if; + if Mode = "00" then + Set_Addr_To <= "11"; -- BA + end if; + when 3 => + LDDI <= '1'; + if Mode = "00" then + Set_Addr_To <= "11"; -- BA + BAAdd <= "01"; -- DB Inc + else + Jump <= "01"; + end if; + when 4 => + Jump <= "10"; -- DIDL + when others => + end case; + end if; + else + LCycle <= "011"; + case to_integer(unsigned(MCycle)) is + when 0 => + if IR(7 downto 5) = "001" then + SaveP <= '1'; + end if; + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + LDBAH <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 3 => + when others => + end case; + end if; + --}}} + + when "01101" | "01110" | "01111" => + --{{{ + -- Absolute + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + -- Read-Modify-Write + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 3 => + LDDI <= '1'; + Write <= '1'; + Set_Addr_To <= "11"; -- BA + when 4 => + Write <= '1'; + LDALU <= '1'; + SaveP <= '1'; + Set_Addr_To <= "11"; -- BA + when 5 => + SaveP <= '0'; -- MIKEJ was 1 + when others => + end case; + else + LCycle <= "011"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + LDBAH <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 3 => + when others => + end case; + end if; + --}}} + + when "10000" => + --{{{ + -- Relative + + -- This circuit dictates when the last + -- microcycle occurs for the branch depending on + -- whether or not the branch is taken and if a page + -- is crossed... + if (Branch = '1') then + + LCycle <= "011"; -- We're done @ T3 if branching...upper + -- level logic will stop at T2 if no page cross + -- (See the Break signal) + else + + LCycle <= "001"; + + end if; + + -- This decodes the current microcycle and takes the + -- proper course of action... + case to_integer(unsigned(MCycle)) is + + -- On the T1 microcycle, increment the program counter + -- and instruct the upper level logic to fetch the offset + -- from the Din bus and store it in the data latches. This + -- will be the last microcycle if the branch isn't taken. + when 1 => + + Jump <= "01"; -- Increments the PC by one (PC will now be PC+2) + -- from microcycle T0. + + LDDI <= '1'; -- Tells logic in top level (T65.vhd) to route + -- the Din bus to the memory data latch (DL) + -- so that the branch offset is fetched. + + -- In microcycle T2, tell the logic in the top level to + -- add the offset. If the most significant byte of the + -- program counter (i.e. the current "page") does not need + -- updating, we are done here...the Break signal at the + -- T65.vhd level takes care of that... + when 2 => + + Jump <= "11"; -- Tell the PC Jump logic to use relative mode. + + PCAdd <= '1'; -- This tells the PC adder to update itself with + -- the current offset recently fetched from + -- memory. + + -- The following is microcycle T3 : + -- The program counter should be completely updated + -- on this cycle after the page cross is detected. + -- We don't need to do anything here... + when 3 => + + + when others => null; -- Do nothing. + + end case; + --}}} + + when "10001" | "10011" => + --{{{ + -- Zero Page Indirect Indexed (d),y + LCycle <= "101"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + LDBAL <= '1'; + BAAdd <= "01"; -- DB Inc + Set_Addr_To <= "10"; -- AD + when 3 => + Set_BusA_To <= "011"; -- Y + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 4 => + BAAdd <= "11"; -- BA Adj + if IR(7 downto 5) = "100" then + Write <= '1'; + else + BreakAtNA <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 5 => + when others => + end case; + --}}} + + when "10100" | "10101" | "10110" | "10111" => + --{{{ + -- Zero Page, X + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + -- Read-Modify-Write + LCycle <= "101"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + ADAdd <= '1'; + Set_Addr_To <= "10"; -- AD + when 3 => + LDDI <= '1'; + Write <= '1'; + Set_Addr_To <= "10"; -- AD + when 4 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= "10"; -- AD + when 5 => + when others => + end case; + else + LCycle <= "011"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= "10"; -- AD + when 2 => + ADAdd <= '1'; + -- Added this check for Y reg. use... + if (IR(3 downto 0) = "0110") then + AddY <= '1'; + end if; + + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= "10"; -- AD + when 3 => null; + when others => + end case; + end if; + --}}} + + when "11001" | "11011" => + --{{{ + -- Absolute Y + LCycle <= "100"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + Set_BusA_To <= "011"; -- Y + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 3 => + BAAdd <= "11"; -- BA adj + if IR(7 downto 5) = "100" then + Write <= '1'; + else + BreakAtNA <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 4 => + when others => + end case; + --}}} + + when "11100" | "11101" | "11110" | "11111" => + --{{{ + -- Absolute X + + if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then + -- Read-Modify-Write + LCycle <= "110"; + case to_integer(unsigned(MCycle)) is + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + Set_BusA_To <= "010"; -- X + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 3 => + BAAdd <= "11"; -- BA adj + Set_Addr_To <= "11"; -- BA + when 4 => + LDDI <= '1'; + Write <= '1'; + Set_Addr_To <= "11"; -- BA + when 5 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= "11"; -- BA + when 6 => + when others => + end case; + else + LCycle <= "100"; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case to_integer(unsigned(MCycle)) is + when 0 => + when 1 => + Jump <= "01"; + LDBAL <= '1'; + when 2 => + Jump <= "01"; + -- mikej + -- special case 0xBE which uses Y reg as index!! + if (IR = "10111110") then + Set_BusA_To <= "011"; -- Y + else + Set_BusA_To <= "010"; -- X + end if; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= "11"; -- BA + when 3 => + BAAdd <= "11"; -- BA adj + if IR(7 downto 5) = "100" then + Write <= '1'; + else + BreakAtNA <= '1'; + end if; + Set_Addr_To <= "11"; -- BA + when 4 => + when others => + end case; + end if; + --}}} + when others => + end case; + end process; + + process (IR, MCycle) + begin + -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC + -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC + case IR(1 downto 0) is + when "00" => + --{{{ + case IR(4 downto 2) is + when "000" | "001" | "011" => + case IR(7 downto 5) is + when "110" | "111" => + -- CP + ALU_Op <= "0110"; + when "101" => + -- LD + ALU_Op <= "0101"; + when "001" => + -- BIT + ALU_Op <= "1100"; + when others => + -- NOP/ST + ALU_Op <= "0100"; + end case; + when "010" => + case IR(7 downto 5) is + when "111" | "110" => + -- IN + ALU_Op <= "1111"; + when "100" => + -- DEY + ALU_Op <= "1110"; + when others => + -- LD + ALU_Op <= "1101"; + end case; + when "110" => + case IR(7 downto 5) is + when "100" => + -- TYA + ALU_Op <= "1101"; + when others => + ALU_Op <= "----"; + end case; + when others => + case IR(7 downto 5) is + when "101" => + -- LD + ALU_Op <= "1101"; + when others => + ALU_Op <= "0100"; + end case; + end case; + --}}} + when "01" => -- OR + --{{{ + ALU_Op(3) <= '0'; + ALU_Op(2 downto 0) <= IR(7 downto 5); + --}}} + when "10" => + --{{{ + ALU_Op(3) <= '1'; + ALU_Op(2 downto 0) <= IR(7 downto 5); + case IR(7 downto 5) is + when "000" => + if IR(4 downto 2) = "110" then + -- INC + ALU_Op <= "1111"; + end if; + when "001" => + if IR(4 downto 2) = "110" then + -- DEC + ALU_Op <= "1110"; + end if; + when "100" => + if IR(4 downto 2) = "010" then + -- TXA + ALU_Op <= "0101"; + else + ALU_Op <= "0100"; + end if; + when others => + end case; + --}}} + when others => + --{{{ + case IR(7 downto 5) is + when "100" => + ALU_Op <= "0100"; + when others => + if MCycle = "000" then + ALU_Op(3) <= '0'; + ALU_Op(2 downto 0) <= IR(7 downto 5); + else + ALU_Op(3) <= '1'; + ALU_Op(2 downto 0) <= IR(7 downto 5); + end if; + end case; + --}}} + end case; + end process; + +end; diff --git a/T65/T65_Pack.vhd b/T65/T65_Pack.vhd index f8d603c..e025e1b 100644 --- a/T65/T65_Pack.vhd +++ b/T65/T65_Pack.vhd @@ -1,117 +1,117 @@ --- **** --- T65(b) core. In an effort to merge and maintain bug fixes .... --- --- --- Ver 300 Bugfixes by ehenciak added --- MikeJ March 2005 --- Latest version from www.fpgaarcade.com (original www.opencores.org) --- --- **** --- --- 65xx compatible microprocessor core --- --- Version : 0246 --- --- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written permission. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- Please report bugs to the author, but before you do so, please --- make sure that this is not a derivative work and that --- you have the latest version of this file. --- --- The latest version of this file can be found at: --- http://www.opencores.org/cvsweb.shtml/t65/ --- --- Limitations : --- --- File history : --- - -library IEEE; -use IEEE.std_logic_1164.all; - -package T65_Pack is - - constant Flag_C : integer := 0; - constant Flag_Z : integer := 1; - constant Flag_I : integer := 2; - constant Flag_D : integer := 3; - constant Flag_B : integer := 4; - constant Flag_1 : integer := 5; - constant Flag_V : integer := 6; - constant Flag_N : integer := 7; - - component T65_MCode - port( - Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 - IR : in std_logic_vector(7 downto 0); - MCycle : in std_logic_vector(2 downto 0); - P : in std_logic_vector(7 downto 0); - LCycle : out std_logic_vector(2 downto 0); - ALU_Op : out std_logic_vector(3 downto 0); - Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P - Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA - Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH - Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel - BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj - BreakAtNA : out std_logic; - ADAdd : out std_logic; - AddY : out std_logic; - PCAdd : out std_logic; - Inc_S : out std_logic; - Dec_S : out std_logic; - LDA : out std_logic; - LDP : out std_logic; - LDX : out std_logic; - LDY : out std_logic; - LDS : out std_logic; - LDDI : out std_logic; - LDALU : out std_logic; - LDAD : out std_logic; - LDBAL : out std_logic; - LDBAH : out std_logic; - SaveP : out std_logic; - Write : out std_logic - ); - end component; - - component T65_ALU - port( - Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 - Op : in std_logic_vector(3 downto 0); - BusA : in std_logic_vector(7 downto 0); - BusB : in std_logic_vector(7 downto 0); - P_In : in std_logic_vector(7 downto 0); - P_Out : out std_logic_vector(7 downto 0); - Q : out std_logic_vector(7 downto 0) - ); - end component; - -end; +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- +-- Ver 300 Bugfixes by ehenciak added +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- +-- 65xx compatible microprocessor core +-- +-- Version : 0246 +-- +-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- The latest version of this file can be found at: +-- http://www.opencores.org/cvsweb.shtml/t65/ +-- +-- Limitations : +-- +-- File history : +-- + +library IEEE; +use IEEE.std_logic_1164.all; + +package T65_Pack is + + constant Flag_C : integer := 0; + constant Flag_Z : integer := 1; + constant Flag_I : integer := 2; + constant Flag_D : integer := 3; + constant Flag_B : integer := 4; + constant Flag_1 : integer := 5; + constant Flag_V : integer := 6; + constant Flag_N : integer := 7; + + component T65_MCode + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + IR : in std_logic_vector(7 downto 0); + MCycle : in std_logic_vector(2 downto 0); + P : in std_logic_vector(7 downto 0); + LCycle : out std_logic_vector(2 downto 0); + ALU_Op : out std_logic_vector(3 downto 0); + Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P + Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA + Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH + Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel + BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj + BreakAtNA : out std_logic; + ADAdd : out std_logic; + AddY : out std_logic; + PCAdd : out std_logic; + Inc_S : out std_logic; + Dec_S : out std_logic; + LDA : out std_logic; + LDP : out std_logic; + LDX : out std_logic; + LDY : out std_logic; + LDS : out std_logic; + LDDI : out std_logic; + LDALU : out std_logic; + LDAD : out std_logic; + LDBAL : out std_logic; + LDBAH : out std_logic; + SaveP : out std_logic; + Write : out std_logic + ); + end component; + + component T65_ALU + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 + Op : in std_logic_vector(3 downto 0); + BusA : in std_logic_vector(7 downto 0); + BusB : in std_logic_vector(7 downto 0); + P_In : in std_logic_vector(7 downto 0); + P_Out : out std_logic_vector(7 downto 0); + Q : out std_logic_vector(7 downto 0) + ); + end component; + +end; diff --git a/bbc_micro.qpf b/bbc_micro.qpf index 52e0fd0..c2ade9e 100644 --- a/bbc_micro.qpf +++ b/bbc_micro.qpf @@ -1,30 +1,30 @@ -# -------------------------------------------------------------------------- # -# -# Copyright (C) 1991-2009 Altera Corporation -# Your use of Altera Corporation's design tools, logic functions -# and other software and tools, and its AMPP partner logic -# functions, and any output files from any of the foregoing -# (including device programming or simulation files), and any -# associated documentation or information are expressly subject -# to the terms and conditions of the Altera Program License -# Subscription Agreement, Altera MegaCore Function License -# Agreement, or other applicable license agreement, including, -# without limitation, that your use is for the sole purpose of -# programming logic devices manufactured by Altera and sold by -# Altera or its authorized distributors. Please refer to the -# applicable agreement for further details. -# -# -------------------------------------------------------------------------- # -# -# Quartus II -# Version 9.1 Build 222 10/21/2009 SJ Web Edition -# Date created = 20:48:44 July 12, 2011 -# -# -------------------------------------------------------------------------- # - -QUARTUS_VERSION = "9.1" -DATE = "20:48:44 July 12, 2011" - -# Revisions - -PROJECT_REVISION = "bbc_micro_de1" +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2009 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus II +# Version 9.1 Build 222 10/21/2009 SJ Web Edition +# Date created = 20:48:44 July 12, 2011 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "9.1" +DATE = "20:48:44 July 12, 2011" + +# Revisions + +PROJECT_REVISION = "bbc_micro_de1" diff --git a/bbc_micro_de1.qsf b/bbc_micro_de1.qsf index be8b1f2..0ae4816 100644 --- a/bbc_micro_de1.qsf +++ b/bbc_micro_de1.qsf @@ -1,537 +1,537 @@ -# -------------------------------------------------------------------------- # -# -# Copyright (C) 1991-2009 Altera Corporation -# Your use of Altera Corporation's design tools, logic functions -# and other software and tools, and its AMPP partner logic -# functions, and any output files from any of the foregoing -# (including device programming or simulation files), and any -# associated documentation or information are expressly subject -# to the terms and conditions of the Altera Program License -# Subscription Agreement, Altera MegaCore Function License -# Agreement, or other applicable license agreement, including, -# without limitation, that your use is for the sole purpose of -# programming logic devices manufactured by Altera and sold by -# Altera or its authorized distributors. Please refer to the -# applicable agreement for further details. -# -# -------------------------------------------------------------------------- # -# -# Quartus II -# Version 9.1 Build 222 10/21/2009 SJ Web Edition -# Date created = 20:48:44 July 12, 2011 -# -# -------------------------------------------------------------------------- # -# -# Notes: -# -# 1) The default values for assignments are stored in the file: -# bbc_micro_de1_assignment_defaults.qdf -# If this file doesn't exist, see file: -# assignment_defaults.qdf -# -# 2) Altera recommends that you do not modify this file. This -# file is updated automatically by the Quartus II software -# and any changes you make may be lost or overwritten. -# -# -------------------------------------------------------------------------- # - - -set_global_assignment -name FAMILY "Cyclone II" -set_global_assignment -name DEVICE EP2C20F484C7 -set_global_assignment -name TOP_LEVEL_ENTITY bbc_micro_de1 -set_global_assignment -name ORIGINAL_QUARTUS_VERSION 9.1 -set_global_assignment -name PROJECT_CREATION_TIME_DATE "20:48:44 JULY 12, 2011" -set_global_assignment -name LAST_QUARTUS_VERSION 9.1 -set_global_assignment -name USE_GENERATED_PHYSICAL_CONSTRAINTS OFF -section_id eda_blast_fpga -set_global_assignment -name DEVICE_FILTER_PACKAGE FBGA -set_global_assignment -name DEVICE_FILTER_PIN_COUNT 484 -set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 7 -set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 -set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 -set_location_assignment PIN_A13 -to GPIO_0[0] -set_location_assignment PIN_B13 -to GPIO_0[1] -set_location_assignment PIN_A14 -to GPIO_0[2] -set_location_assignment PIN_B14 -to GPIO_0[3] -set_location_assignment PIN_A15 -to GPIO_0[4] -set_location_assignment PIN_B15 -to GPIO_0[5] -set_location_assignment PIN_A16 -to GPIO_0[6] -set_location_assignment PIN_B16 -to GPIO_0[7] -set_location_assignment PIN_A17 -to GPIO_0[8] -set_location_assignment PIN_B17 -to GPIO_0[9] -set_location_assignment PIN_A18 -to GPIO_0[10] -set_location_assignment PIN_B18 -to GPIO_0[11] -set_location_assignment PIN_A19 -to GPIO_0[12] -set_location_assignment PIN_B19 -to GPIO_0[13] -set_location_assignment PIN_A20 -to GPIO_0[14] -set_location_assignment PIN_B20 -to GPIO_0[15] -set_location_assignment PIN_C21 -to GPIO_0[16] -set_location_assignment PIN_C22 -to GPIO_0[17] -set_location_assignment PIN_D21 -to GPIO_0[18] -set_location_assignment PIN_D22 -to GPIO_0[19] -set_location_assignment PIN_E21 -to GPIO_0[20] -set_location_assignment PIN_E22 -to GPIO_0[21] -set_location_assignment PIN_F21 -to GPIO_0[22] -set_location_assignment PIN_F22 -to GPIO_0[23] -set_location_assignment PIN_G21 -to GPIO_0[24] -set_location_assignment PIN_G22 -to GPIO_0[25] -set_location_assignment PIN_J21 -to GPIO_0[26] -set_location_assignment PIN_J22 -to GPIO_0[27] -set_location_assignment PIN_K21 -to GPIO_0[28] -set_location_assignment PIN_K22 -to GPIO_0[29] -set_location_assignment PIN_J19 -to GPIO_0[30] -set_location_assignment PIN_J20 -to GPIO_0[31] -set_location_assignment PIN_J18 -to GPIO_0[32] -set_location_assignment PIN_K20 -to GPIO_0[33] -set_location_assignment PIN_L19 -to GPIO_0[34] -set_location_assignment PIN_L18 -to GPIO_0[35] -set_location_assignment PIN_H12 -to GPIO_1[0] -set_location_assignment PIN_H13 -to GPIO_1[1] -set_location_assignment PIN_H14 -to GPIO_1[2] -set_location_assignment PIN_G15 -to GPIO_1[3] -set_location_assignment PIN_E14 -to GPIO_1[4] -set_location_assignment PIN_E15 -to GPIO_1[5] -set_location_assignment PIN_F15 -to GPIO_1[6] -set_location_assignment PIN_G16 -to GPIO_1[7] -set_location_assignment PIN_F12 -to GPIO_1[8] -set_location_assignment PIN_F13 -to GPIO_1[9] -set_location_assignment PIN_C14 -to GPIO_1[10] -set_location_assignment PIN_D14 -to GPIO_1[11] -set_location_assignment PIN_D15 -to GPIO_1[12] -set_location_assignment PIN_D16 -to GPIO_1[13] -set_location_assignment PIN_C17 -to GPIO_1[14] -set_location_assignment PIN_C18 -to GPIO_1[15] -set_location_assignment PIN_C19 -to GPIO_1[16] -set_location_assignment PIN_C20 -to GPIO_1[17] -set_location_assignment PIN_D19 -to GPIO_1[18] -set_location_assignment PIN_D20 -to GPIO_1[19] -set_location_assignment PIN_E20 -to GPIO_1[20] -set_location_assignment PIN_F20 -to GPIO_1[21] -set_location_assignment PIN_E19 -to GPIO_1[22] -set_location_assignment PIN_E18 -to GPIO_1[23] -set_location_assignment PIN_G20 -to GPIO_1[24] -set_location_assignment PIN_G18 -to GPIO_1[25] -set_location_assignment PIN_G17 -to GPIO_1[26] -set_location_assignment PIN_H17 -to GPIO_1[27] -set_location_assignment PIN_J15 -to GPIO_1[28] -set_location_assignment PIN_H18 -to GPIO_1[29] -set_location_assignment PIN_N22 -to GPIO_1[30] -set_location_assignment PIN_N21 -to GPIO_1[31] -set_location_assignment PIN_P15 -to GPIO_1[32] -set_location_assignment PIN_N15 -to GPIO_1[33] -set_location_assignment PIN_P17 -to GPIO_1[34] -set_location_assignment PIN_P18 -to GPIO_1[35] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[0] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[1] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[2] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[3] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[4] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[5] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[6] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[7] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[8] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[9] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[10] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[11] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[12] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[13] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[14] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[15] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[16] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[17] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[18] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[19] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[20] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[21] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[22] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[23] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[24] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[25] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[26] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[27] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[28] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[29] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[30] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[31] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[32] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[33] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[34] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[35] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[0] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[1] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[2] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[3] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[4] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[5] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[6] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[7] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[8] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[9] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[10] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[11] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[12] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[13] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[14] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[15] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[16] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[17] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[18] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[19] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[20] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[21] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[22] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[23] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[24] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[25] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[26] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[27] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[28] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[29] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[30] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[31] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[32] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[33] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[34] -set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[35] -set_location_assignment PIN_L22 -to SW[0] -set_location_assignment PIN_L21 -to SW[1] -set_location_assignment PIN_M22 -to SW[2] -set_location_assignment PIN_V12 -to SW[3] -set_location_assignment PIN_W12 -to SW[4] -set_location_assignment PIN_U12 -to SW[5] -set_location_assignment PIN_U11 -to SW[6] -set_location_assignment PIN_M2 -to SW[7] -set_location_assignment PIN_M1 -to SW[8] -set_location_assignment PIN_L2 -to SW[9] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[0] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[1] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[2] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[3] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[4] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[5] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[6] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[7] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[8] -set_instance_assignment -name IO_STANDARD LVTTL -to SW[9] -set_location_assignment PIN_J2 -to HEX0[0] -set_location_assignment PIN_J1 -to HEX0[1] -set_location_assignment PIN_H2 -to HEX0[2] -set_location_assignment PIN_H1 -to HEX0[3] -set_location_assignment PIN_F2 -to HEX0[4] -set_location_assignment PIN_F1 -to HEX0[5] -set_location_assignment PIN_E2 -to HEX0[6] -set_location_assignment PIN_E1 -to HEX1[0] -set_location_assignment PIN_H6 -to HEX1[1] -set_location_assignment PIN_H5 -to HEX1[2] -set_location_assignment PIN_H4 -to HEX1[3] -set_location_assignment PIN_G3 -to HEX1[4] -set_location_assignment PIN_D2 -to HEX1[5] -set_location_assignment PIN_D1 -to HEX1[6] -set_location_assignment PIN_G5 -to HEX2[0] -set_location_assignment PIN_G6 -to HEX2[1] -set_location_assignment PIN_C2 -to HEX2[2] -set_location_assignment PIN_C1 -to HEX2[3] -set_location_assignment PIN_E3 -to HEX2[4] -set_location_assignment PIN_E4 -to HEX2[5] -set_location_assignment PIN_D3 -to HEX2[6] -set_location_assignment PIN_F4 -to HEX3[0] -set_location_assignment PIN_D5 -to HEX3[1] -set_location_assignment PIN_D6 -to HEX3[2] -set_location_assignment PIN_J4 -to HEX3[3] -set_location_assignment PIN_L8 -to HEX3[4] -set_location_assignment PIN_F3 -to HEX3[5] -set_location_assignment PIN_D4 -to HEX3[6] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[0] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[1] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[2] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[3] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[4] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[5] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[6] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[0] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[1] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[2] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[3] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[4] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[5] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[6] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[0] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[1] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[2] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[3] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[4] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[5] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[6] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[0] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[1] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[2] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[3] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[4] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[5] -set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[6] -set_location_assignment PIN_R22 -to KEY[0] -set_location_assignment PIN_R21 -to KEY[1] -set_location_assignment PIN_T22 -to KEY[2] -set_location_assignment PIN_T21 -to KEY[3] -set_location_assignment PIN_R20 -to LEDR[0] -set_location_assignment PIN_R19 -to LEDR[1] -set_location_assignment PIN_U19 -to LEDR[2] -set_location_assignment PIN_Y19 -to LEDR[3] -set_location_assignment PIN_T18 -to LEDR[4] -set_location_assignment PIN_V19 -to LEDR[5] -set_location_assignment PIN_Y18 -to LEDR[6] -set_location_assignment PIN_U18 -to LEDR[7] -set_location_assignment PIN_R18 -to LEDR[8] -set_location_assignment PIN_R17 -to LEDR[9] -set_location_assignment PIN_U22 -to LEDG[0] -set_location_assignment PIN_U21 -to LEDG[1] -set_location_assignment PIN_V22 -to LEDG[2] -set_location_assignment PIN_V21 -to LEDG[3] -set_location_assignment PIN_W22 -to LEDG[4] -set_location_assignment PIN_W21 -to LEDG[5] -set_location_assignment PIN_Y22 -to LEDG[6] -set_location_assignment PIN_Y21 -to LEDG[7] -set_instance_assignment -name IO_STANDARD LVTTL -to KEY[0] -set_instance_assignment -name IO_STANDARD LVTTL -to KEY[1] -set_instance_assignment -name IO_STANDARD LVTTL -to KEY[2] -set_instance_assignment -name IO_STANDARD LVTTL -to KEY[3] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[0] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[1] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[2] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[3] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[4] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[5] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[6] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[7] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[8] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[9] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[0] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[1] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[2] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[3] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[4] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[5] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[6] -set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[7] -set_location_assignment PIN_D12 -to CLOCK_27[0] -set_location_assignment PIN_E12 -to CLOCK_27[1] -set_location_assignment PIN_B12 -to CLOCK_24[0] -set_location_assignment PIN_A12 -to CLOCK_24[1] -set_location_assignment PIN_L1 -to CLOCK_50 -set_location_assignment PIN_M21 -to EXT_CLOCK -set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_27[1] -set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_24[0] -set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_24[1] -set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_50 -set_instance_assignment -name IO_STANDARD LVTTL -to EXT_CLOCK -set_location_assignment PIN_H15 -to PS2_CLK -set_location_assignment PIN_J14 -to PS2_DAT -set_location_assignment PIN_F14 -to UART_RXD -set_location_assignment PIN_G12 -to UART_TXD -set_instance_assignment -name IO_STANDARD LVTTL -to PS2_CLK -set_instance_assignment -name IO_STANDARD LVTTL -to PS2_DAT -set_instance_assignment -name IO_STANDARD LVTTL -to UART_RXD -set_instance_assignment -name IO_STANDARD LVTTL -to UART_TXD -set_location_assignment PIN_E8 -to TDI -set_location_assignment PIN_D8 -to TCS -set_location_assignment PIN_C7 -to TCK -set_location_assignment PIN_D7 -to TDO -set_instance_assignment -name IO_STANDARD LVTTL -to TDI -set_instance_assignment -name IO_STANDARD LVTTL -to TCS -set_instance_assignment -name IO_STANDARD LVTTL -to TCK -set_instance_assignment -name IO_STANDARD LVTTL -to TDO -set_location_assignment PIN_D9 -to VGA_R[0] -set_location_assignment PIN_C9 -to VGA_R[1] -set_location_assignment PIN_A7 -to VGA_R[2] -set_location_assignment PIN_B7 -to VGA_R[3] -set_location_assignment PIN_B8 -to VGA_G[0] -set_location_assignment PIN_C10 -to VGA_G[1] -set_location_assignment PIN_B9 -to VGA_G[2] -set_location_assignment PIN_A8 -to VGA_G[3] -set_location_assignment PIN_A9 -to VGA_B[0] -set_location_assignment PIN_D11 -to VGA_B[1] -set_location_assignment PIN_A10 -to VGA_B[2] -set_location_assignment PIN_B10 -to VGA_B[3] -set_location_assignment PIN_A11 -to VGA_HS -set_location_assignment PIN_B11 -to VGA_VS -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[0] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[1] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[2] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[3] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[0] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[1] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[2] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[3] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[0] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[1] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[2] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[3] -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_HS -set_instance_assignment -name IO_STANDARD LVTTL -to VGA_VS -set_location_assignment PIN_A3 -to I2C_SCLK -set_location_assignment PIN_B3 -to I2C_SDAT -set_location_assignment PIN_A6 -to AUD_ADCLRCK -set_location_assignment PIN_B6 -to AUD_ADCDAT -set_location_assignment PIN_A5 -to AUD_DACLRCK -set_location_assignment PIN_B5 -to AUD_DACDAT -set_location_assignment PIN_B4 -to AUD_XCK -set_location_assignment PIN_A4 -to AUD_BCLK -set_instance_assignment -name IO_STANDARD LVTTL -to I2C_SCLK -set_instance_assignment -name IO_STANDARD LVTTL -to I2C_SDAT -set_instance_assignment -name IO_STANDARD LVTTL -to AUD_ADCLRCK -set_instance_assignment -name IO_STANDARD LVTTL -to AUD_ADCDAT -set_instance_assignment -name IO_STANDARD LVTTL -to AUD_DACLRCK -set_instance_assignment -name IO_STANDARD LVTTL -to AUD_DACDAT -set_instance_assignment -name IO_STANDARD LVTTL -to AUD_XCK -set_instance_assignment -name IO_STANDARD LVTTL -to AUD_BCLK -set_location_assignment PIN_W4 -to DRAM_ADDR[0] -set_location_assignment PIN_W5 -to DRAM_ADDR[1] -set_location_assignment PIN_Y3 -to DRAM_ADDR[2] -set_location_assignment PIN_Y4 -to DRAM_ADDR[3] -set_location_assignment PIN_R6 -to DRAM_ADDR[4] -set_location_assignment PIN_R5 -to DRAM_ADDR[5] -set_location_assignment PIN_P6 -to DRAM_ADDR[6] -set_location_assignment PIN_P5 -to DRAM_ADDR[7] -set_location_assignment PIN_P3 -to DRAM_ADDR[8] -set_location_assignment PIN_N4 -to DRAM_ADDR[9] -set_location_assignment PIN_W3 -to DRAM_ADDR[10] -set_location_assignment PIN_N6 -to DRAM_ADDR[11] -set_location_assignment PIN_U3 -to DRAM_BA_0 -set_location_assignment PIN_V4 -to DRAM_BA_1 -set_location_assignment PIN_T3 -to DRAM_CAS_N -set_location_assignment PIN_N3 -to DRAM_CKE -set_location_assignment PIN_U4 -to DRAM_CLK -set_location_assignment PIN_T6 -to DRAM_CS_N -set_location_assignment PIN_U1 -to DRAM_DQ[0] -set_location_assignment PIN_U2 -to DRAM_DQ[1] -set_location_assignment PIN_V1 -to DRAM_DQ[2] -set_location_assignment PIN_V2 -to DRAM_DQ[3] -set_location_assignment PIN_W1 -to DRAM_DQ[4] -set_location_assignment PIN_W2 -to DRAM_DQ[5] -set_location_assignment PIN_Y1 -to DRAM_DQ[6] -set_location_assignment PIN_Y2 -to DRAM_DQ[7] -set_location_assignment PIN_N1 -to DRAM_DQ[8] -set_location_assignment PIN_N2 -to DRAM_DQ[9] -set_location_assignment PIN_P1 -to DRAM_DQ[10] -set_location_assignment PIN_P2 -to DRAM_DQ[11] -set_location_assignment PIN_R1 -to DRAM_DQ[12] -set_location_assignment PIN_R2 -to DRAM_DQ[13] -set_location_assignment PIN_T1 -to DRAM_DQ[14] -set_location_assignment PIN_T2 -to DRAM_DQ[15] -set_location_assignment PIN_R7 -to DRAM_LDQM -set_location_assignment PIN_T5 -to DRAM_RAS_N -set_location_assignment PIN_M5 -to DRAM_UDQM -set_location_assignment PIN_R8 -to DRAM_WE_N -set_location_assignment PIN_AB20 -to FL_ADDR[0] -set_location_assignment PIN_AA14 -to FL_ADDR[1] -set_location_assignment PIN_Y16 -to FL_ADDR[2] -set_location_assignment PIN_R15 -to FL_ADDR[3] -set_location_assignment PIN_T15 -to FL_ADDR[4] -set_location_assignment PIN_U15 -to FL_ADDR[5] -set_location_assignment PIN_V15 -to FL_ADDR[6] -set_location_assignment PIN_W15 -to FL_ADDR[7] -set_location_assignment PIN_R14 -to FL_ADDR[8] -set_location_assignment PIN_Y13 -to FL_ADDR[9] -set_location_assignment PIN_R12 -to FL_ADDR[10] -set_location_assignment PIN_T12 -to FL_ADDR[11] -set_location_assignment PIN_AB14 -to FL_ADDR[12] -set_location_assignment PIN_AA13 -to FL_ADDR[13] -set_location_assignment PIN_AB13 -to FL_ADDR[14] -set_location_assignment PIN_AA12 -to FL_ADDR[15] -set_location_assignment PIN_AB12 -to FL_ADDR[16] -set_location_assignment PIN_AA20 -to FL_ADDR[17] -set_location_assignment PIN_U14 -to FL_ADDR[18] -set_location_assignment PIN_V14 -to FL_ADDR[19] -set_location_assignment PIN_U13 -to FL_ADDR[20] -set_location_assignment PIN_R13 -to FL_ADDR[21] -set_location_assignment PIN_AB16 -to FL_DQ[0] -set_location_assignment PIN_AA16 -to FL_DQ[1] -set_location_assignment PIN_AB17 -to FL_DQ[2] -set_location_assignment PIN_AA17 -to FL_DQ[3] -set_location_assignment PIN_AB18 -to FL_DQ[4] -set_location_assignment PIN_AA18 -to FL_DQ[5] -set_location_assignment PIN_AB19 -to FL_DQ[6] -set_location_assignment PIN_AA19 -to FL_DQ[7] -set_location_assignment PIN_AA15 -to FL_OE_N -set_location_assignment PIN_W14 -to FL_RST_N -set_location_assignment PIN_Y14 -to FL_WE_N -set_location_assignment PIN_AA3 -to SRAM_ADDR[0] -set_location_assignment PIN_AB3 -to SRAM_ADDR[1] -set_location_assignment PIN_AA4 -to SRAM_ADDR[2] -set_location_assignment PIN_AB4 -to SRAM_ADDR[3] -set_location_assignment PIN_AA5 -to SRAM_ADDR[4] -set_location_assignment PIN_AB10 -to SRAM_ADDR[5] -set_location_assignment PIN_AA11 -to SRAM_ADDR[6] -set_location_assignment PIN_AB11 -to SRAM_ADDR[7] -set_location_assignment PIN_V11 -to SRAM_ADDR[8] -set_location_assignment PIN_W11 -to SRAM_ADDR[9] -set_location_assignment PIN_R11 -to SRAM_ADDR[10] -set_location_assignment PIN_T11 -to SRAM_ADDR[11] -set_location_assignment PIN_Y10 -to SRAM_ADDR[12] -set_location_assignment PIN_U10 -to SRAM_ADDR[13] -set_location_assignment PIN_R10 -to SRAM_ADDR[14] -set_location_assignment PIN_T7 -to SRAM_ADDR[15] -set_location_assignment PIN_Y6 -to SRAM_ADDR[16] -set_location_assignment PIN_Y5 -to SRAM_ADDR[17] -set_location_assignment PIN_AB5 -to SRAM_CE_N -set_location_assignment PIN_AA6 -to SRAM_DQ[0] -set_location_assignment PIN_AB6 -to SRAM_DQ[1] -set_location_assignment PIN_AA7 -to SRAM_DQ[2] -set_location_assignment PIN_AB7 -to SRAM_DQ[3] -set_location_assignment PIN_AA8 -to SRAM_DQ[4] -set_location_assignment PIN_AB8 -to SRAM_DQ[5] -set_location_assignment PIN_AA9 -to SRAM_DQ[6] -set_location_assignment PIN_AB9 -to SRAM_DQ[7] -set_location_assignment PIN_Y9 -to SRAM_DQ[8] -set_location_assignment PIN_W9 -to SRAM_DQ[9] -set_location_assignment PIN_V9 -to SRAM_DQ[10] -set_location_assignment PIN_U9 -to SRAM_DQ[11] -set_location_assignment PIN_R9 -to SRAM_DQ[12] -set_location_assignment PIN_W8 -to SRAM_DQ[13] -set_location_assignment PIN_V8 -to SRAM_DQ[14] -set_location_assignment PIN_U8 -to SRAM_DQ[15] -set_location_assignment PIN_Y7 -to SRAM_LB_N -set_location_assignment PIN_T8 -to SRAM_OE_N -set_location_assignment PIN_W7 -to SRAM_UB_N -set_location_assignment PIN_AA10 -to SRAM_WE_N -set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED WITH WEAK PULL-UP" -set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top -set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top -set_global_assignment -name LL_ROOT_REGION ON -section_id "Root Region" -set_global_assignment -name LL_MEMBER_STATE LOCKED -section_id "Root Region" -set_global_assignment -name MISC_FILE "U:/git_repos/fpga/bbc/bbc_micro_de1.dpf" -set_location_assignment PIN_AB15 -to FL_CE_N -set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" -set_global_assignment -name STRATIX_CONFIGURATION_DEVICE EPCS4 -set_global_assignment -name RESERVE_ASDO_AFTER_CONFIGURATION "AS INPUT TRI-STATED" -set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" -set_location_assignment PIN_U20 -to SD_nCS -set_location_assignment PIN_V20 -to SD_SCLK -set_location_assignment PIN_Y20 -to SD_MOSI -set_location_assignment PIN_W20 -to SD_MISO -set_global_assignment -name VHDL_FILE saa5050.vhd -set_global_assignment -name VHDL_FILE i2s_intf.vhd -set_global_assignment -name VHDL_FILE i2c_loader.vhd -set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_comp_pack-p.vhd" -set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_noise.vhd" -set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_tone.vhd" -set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_top.vhd" -set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_attenuator.vhd" -set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_clock_div.vhd" -set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_latch_ctrl.vhd" -set_global_assignment -name VHDL_FILE ps2_intf.vhd -set_global_assignment -name VHDL_FILE m6522.vhd -set_global_assignment -name VHDL_FILE seg7.vhd -set_global_assignment -name VHDL_FILE vidproc.vhd -set_global_assignment -name VHDL_FILE mc6845.vhd -set_global_assignment -name VHDL_FILE T65/T65_Pack.vhd -set_global_assignment -name VHDL_FILE T65/T65.vhd -set_global_assignment -name VHDL_FILE T65/T65_ALU.vhd -set_global_assignment -name VHDL_FILE T65/T65_MCode.vhd -set_global_assignment -name QIP_FILE pll32.qip -set_global_assignment -name VHDL_FILE bbc_micro_de1.vhd -set_global_assignment -name VHDL_FILE bbc_micro_de1_tb.vhd -set_global_assignment -name VHDL_FILE m6522_tb.vhd -set_global_assignment -name VHDL_FILE keyboard.vhd -set_global_assignment -name VHDL_FILE debugger.vhd -set_global_assignment -name QIP_FILE saa5050_rom.qip +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2009 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus II +# Version 9.1 Build 222 10/21/2009 SJ Web Edition +# Date created = 20:48:44 July 12, 2011 +# +# -------------------------------------------------------------------------- # +# +# Notes: +# +# 1) The default values for assignments are stored in the file: +# bbc_micro_de1_assignment_defaults.qdf +# If this file doesn't exist, see file: +# assignment_defaults.qdf +# +# 2) Altera recommends that you do not modify this file. This +# file is updated automatically by the Quartus II software +# and any changes you make may be lost or overwritten. +# +# -------------------------------------------------------------------------- # + + +set_global_assignment -name FAMILY "Cyclone II" +set_global_assignment -name DEVICE EP2C20F484C7 +set_global_assignment -name TOP_LEVEL_ENTITY bbc_micro_de1 +set_global_assignment -name ORIGINAL_QUARTUS_VERSION 9.1 +set_global_assignment -name PROJECT_CREATION_TIME_DATE "20:48:44 JULY 12, 2011" +set_global_assignment -name LAST_QUARTUS_VERSION 9.1 +set_global_assignment -name USE_GENERATED_PHYSICAL_CONSTRAINTS OFF -section_id eda_blast_fpga +set_global_assignment -name DEVICE_FILTER_PACKAGE FBGA +set_global_assignment -name DEVICE_FILTER_PIN_COUNT 484 +set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 7 +set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 +set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 +set_location_assignment PIN_A13 -to GPIO_0[0] +set_location_assignment PIN_B13 -to GPIO_0[1] +set_location_assignment PIN_A14 -to GPIO_0[2] +set_location_assignment PIN_B14 -to GPIO_0[3] +set_location_assignment PIN_A15 -to GPIO_0[4] +set_location_assignment PIN_B15 -to GPIO_0[5] +set_location_assignment PIN_A16 -to GPIO_0[6] +set_location_assignment PIN_B16 -to GPIO_0[7] +set_location_assignment PIN_A17 -to GPIO_0[8] +set_location_assignment PIN_B17 -to GPIO_0[9] +set_location_assignment PIN_A18 -to GPIO_0[10] +set_location_assignment PIN_B18 -to GPIO_0[11] +set_location_assignment PIN_A19 -to GPIO_0[12] +set_location_assignment PIN_B19 -to GPIO_0[13] +set_location_assignment PIN_A20 -to GPIO_0[14] +set_location_assignment PIN_B20 -to GPIO_0[15] +set_location_assignment PIN_C21 -to GPIO_0[16] +set_location_assignment PIN_C22 -to GPIO_0[17] +set_location_assignment PIN_D21 -to GPIO_0[18] +set_location_assignment PIN_D22 -to GPIO_0[19] +set_location_assignment PIN_E21 -to GPIO_0[20] +set_location_assignment PIN_E22 -to GPIO_0[21] +set_location_assignment PIN_F21 -to GPIO_0[22] +set_location_assignment PIN_F22 -to GPIO_0[23] +set_location_assignment PIN_G21 -to GPIO_0[24] +set_location_assignment PIN_G22 -to GPIO_0[25] +set_location_assignment PIN_J21 -to GPIO_0[26] +set_location_assignment PIN_J22 -to GPIO_0[27] +set_location_assignment PIN_K21 -to GPIO_0[28] +set_location_assignment PIN_K22 -to GPIO_0[29] +set_location_assignment PIN_J19 -to GPIO_0[30] +set_location_assignment PIN_J20 -to GPIO_0[31] +set_location_assignment PIN_J18 -to GPIO_0[32] +set_location_assignment PIN_K20 -to GPIO_0[33] +set_location_assignment PIN_L19 -to GPIO_0[34] +set_location_assignment PIN_L18 -to GPIO_0[35] +set_location_assignment PIN_H12 -to GPIO_1[0] +set_location_assignment PIN_H13 -to GPIO_1[1] +set_location_assignment PIN_H14 -to GPIO_1[2] +set_location_assignment PIN_G15 -to GPIO_1[3] +set_location_assignment PIN_E14 -to GPIO_1[4] +set_location_assignment PIN_E15 -to GPIO_1[5] +set_location_assignment PIN_F15 -to GPIO_1[6] +set_location_assignment PIN_G16 -to GPIO_1[7] +set_location_assignment PIN_F12 -to GPIO_1[8] +set_location_assignment PIN_F13 -to GPIO_1[9] +set_location_assignment PIN_C14 -to GPIO_1[10] +set_location_assignment PIN_D14 -to GPIO_1[11] +set_location_assignment PIN_D15 -to GPIO_1[12] +set_location_assignment PIN_D16 -to GPIO_1[13] +set_location_assignment PIN_C17 -to GPIO_1[14] +set_location_assignment PIN_C18 -to GPIO_1[15] +set_location_assignment PIN_C19 -to GPIO_1[16] +set_location_assignment PIN_C20 -to GPIO_1[17] +set_location_assignment PIN_D19 -to GPIO_1[18] +set_location_assignment PIN_D20 -to GPIO_1[19] +set_location_assignment PIN_E20 -to GPIO_1[20] +set_location_assignment PIN_F20 -to GPIO_1[21] +set_location_assignment PIN_E19 -to GPIO_1[22] +set_location_assignment PIN_E18 -to GPIO_1[23] +set_location_assignment PIN_G20 -to GPIO_1[24] +set_location_assignment PIN_G18 -to GPIO_1[25] +set_location_assignment PIN_G17 -to GPIO_1[26] +set_location_assignment PIN_H17 -to GPIO_1[27] +set_location_assignment PIN_J15 -to GPIO_1[28] +set_location_assignment PIN_H18 -to GPIO_1[29] +set_location_assignment PIN_N22 -to GPIO_1[30] +set_location_assignment PIN_N21 -to GPIO_1[31] +set_location_assignment PIN_P15 -to GPIO_1[32] +set_location_assignment PIN_N15 -to GPIO_1[33] +set_location_assignment PIN_P17 -to GPIO_1[34] +set_location_assignment PIN_P18 -to GPIO_1[35] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[0] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[1] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[2] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[3] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[4] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[5] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[6] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[7] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[8] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[9] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[10] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[11] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[12] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[13] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[14] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[15] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[16] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[17] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[18] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[19] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[20] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[21] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[22] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[23] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[24] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[25] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[26] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[27] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[28] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[29] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[30] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[31] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[32] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[33] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[34] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[35] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[0] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[1] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[2] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[3] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[4] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[5] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[6] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[7] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[8] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[9] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[10] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[11] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[12] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[13] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[14] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[15] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[16] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[17] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[18] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[19] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[20] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[21] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[22] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[23] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[24] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[25] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[26] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[27] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[28] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[29] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[30] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[31] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[32] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[33] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[34] +set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[35] +set_location_assignment PIN_L22 -to SW[0] +set_location_assignment PIN_L21 -to SW[1] +set_location_assignment PIN_M22 -to SW[2] +set_location_assignment PIN_V12 -to SW[3] +set_location_assignment PIN_W12 -to SW[4] +set_location_assignment PIN_U12 -to SW[5] +set_location_assignment PIN_U11 -to SW[6] +set_location_assignment PIN_M2 -to SW[7] +set_location_assignment PIN_M1 -to SW[8] +set_location_assignment PIN_L2 -to SW[9] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[0] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[1] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[2] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[3] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[4] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[5] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[6] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[7] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[8] +set_instance_assignment -name IO_STANDARD LVTTL -to SW[9] +set_location_assignment PIN_J2 -to HEX0[0] +set_location_assignment PIN_J1 -to HEX0[1] +set_location_assignment PIN_H2 -to HEX0[2] +set_location_assignment PIN_H1 -to HEX0[3] +set_location_assignment PIN_F2 -to HEX0[4] +set_location_assignment PIN_F1 -to HEX0[5] +set_location_assignment PIN_E2 -to HEX0[6] +set_location_assignment PIN_E1 -to HEX1[0] +set_location_assignment PIN_H6 -to HEX1[1] +set_location_assignment PIN_H5 -to HEX1[2] +set_location_assignment PIN_H4 -to HEX1[3] +set_location_assignment PIN_G3 -to HEX1[4] +set_location_assignment PIN_D2 -to HEX1[5] +set_location_assignment PIN_D1 -to HEX1[6] +set_location_assignment PIN_G5 -to HEX2[0] +set_location_assignment PIN_G6 -to HEX2[1] +set_location_assignment PIN_C2 -to HEX2[2] +set_location_assignment PIN_C1 -to HEX2[3] +set_location_assignment PIN_E3 -to HEX2[4] +set_location_assignment PIN_E4 -to HEX2[5] +set_location_assignment PIN_D3 -to HEX2[6] +set_location_assignment PIN_F4 -to HEX3[0] +set_location_assignment PIN_D5 -to HEX3[1] +set_location_assignment PIN_D6 -to HEX3[2] +set_location_assignment PIN_J4 -to HEX3[3] +set_location_assignment PIN_L8 -to HEX3[4] +set_location_assignment PIN_F3 -to HEX3[5] +set_location_assignment PIN_D4 -to HEX3[6] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[0] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[1] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[2] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[3] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[4] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[5] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[6] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[0] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[1] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[2] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[3] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[4] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[5] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[6] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[0] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[1] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[2] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[3] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[4] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[5] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[6] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[0] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[1] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[2] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[3] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[4] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[5] +set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[6] +set_location_assignment PIN_R22 -to KEY[0] +set_location_assignment PIN_R21 -to KEY[1] +set_location_assignment PIN_T22 -to KEY[2] +set_location_assignment PIN_T21 -to KEY[3] +set_location_assignment PIN_R20 -to LEDR[0] +set_location_assignment PIN_R19 -to LEDR[1] +set_location_assignment PIN_U19 -to LEDR[2] +set_location_assignment PIN_Y19 -to LEDR[3] +set_location_assignment PIN_T18 -to LEDR[4] +set_location_assignment PIN_V19 -to LEDR[5] +set_location_assignment PIN_Y18 -to LEDR[6] +set_location_assignment PIN_U18 -to LEDR[7] +set_location_assignment PIN_R18 -to LEDR[8] +set_location_assignment PIN_R17 -to LEDR[9] +set_location_assignment PIN_U22 -to LEDG[0] +set_location_assignment PIN_U21 -to LEDG[1] +set_location_assignment PIN_V22 -to LEDG[2] +set_location_assignment PIN_V21 -to LEDG[3] +set_location_assignment PIN_W22 -to LEDG[4] +set_location_assignment PIN_W21 -to LEDG[5] +set_location_assignment PIN_Y22 -to LEDG[6] +set_location_assignment PIN_Y21 -to LEDG[7] +set_instance_assignment -name IO_STANDARD LVTTL -to KEY[0] +set_instance_assignment -name IO_STANDARD LVTTL -to KEY[1] +set_instance_assignment -name IO_STANDARD LVTTL -to KEY[2] +set_instance_assignment -name IO_STANDARD LVTTL -to KEY[3] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[0] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[1] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[2] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[3] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[4] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[5] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[6] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[7] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[8] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[9] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[0] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[1] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[2] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[3] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[4] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[5] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[6] +set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[7] +set_location_assignment PIN_D12 -to CLOCK_27[0] +set_location_assignment PIN_E12 -to CLOCK_27[1] +set_location_assignment PIN_B12 -to CLOCK_24[0] +set_location_assignment PIN_A12 -to CLOCK_24[1] +set_location_assignment PIN_L1 -to CLOCK_50 +set_location_assignment PIN_M21 -to EXT_CLOCK +set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_27[1] +set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_24[0] +set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_24[1] +set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_50 +set_instance_assignment -name IO_STANDARD LVTTL -to EXT_CLOCK +set_location_assignment PIN_H15 -to PS2_CLK +set_location_assignment PIN_J14 -to PS2_DAT +set_location_assignment PIN_F14 -to UART_RXD +set_location_assignment PIN_G12 -to UART_TXD +set_instance_assignment -name IO_STANDARD LVTTL -to PS2_CLK +set_instance_assignment -name IO_STANDARD LVTTL -to PS2_DAT +set_instance_assignment -name IO_STANDARD LVTTL -to UART_RXD +set_instance_assignment -name IO_STANDARD LVTTL -to UART_TXD +set_location_assignment PIN_E8 -to TDI +set_location_assignment PIN_D8 -to TCS +set_location_assignment PIN_C7 -to TCK +set_location_assignment PIN_D7 -to TDO +set_instance_assignment -name IO_STANDARD LVTTL -to TDI +set_instance_assignment -name IO_STANDARD LVTTL -to TCS +set_instance_assignment -name IO_STANDARD LVTTL -to TCK +set_instance_assignment -name IO_STANDARD LVTTL -to TDO +set_location_assignment PIN_D9 -to VGA_R[0] +set_location_assignment PIN_C9 -to VGA_R[1] +set_location_assignment PIN_A7 -to VGA_R[2] +set_location_assignment PIN_B7 -to VGA_R[3] +set_location_assignment PIN_B8 -to VGA_G[0] +set_location_assignment PIN_C10 -to VGA_G[1] +set_location_assignment PIN_B9 -to VGA_G[2] +set_location_assignment PIN_A8 -to VGA_G[3] +set_location_assignment PIN_A9 -to VGA_B[0] +set_location_assignment PIN_D11 -to VGA_B[1] +set_location_assignment PIN_A10 -to VGA_B[2] +set_location_assignment PIN_B10 -to VGA_B[3] +set_location_assignment PIN_A11 -to VGA_HS +set_location_assignment PIN_B11 -to VGA_VS +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[0] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[1] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[2] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[3] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[0] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[1] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[2] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[3] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[0] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[1] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[2] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[3] +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_HS +set_instance_assignment -name IO_STANDARD LVTTL -to VGA_VS +set_location_assignment PIN_A3 -to I2C_SCLK +set_location_assignment PIN_B3 -to I2C_SDAT +set_location_assignment PIN_A6 -to AUD_ADCLRCK +set_location_assignment PIN_B6 -to AUD_ADCDAT +set_location_assignment PIN_A5 -to AUD_DACLRCK +set_location_assignment PIN_B5 -to AUD_DACDAT +set_location_assignment PIN_B4 -to AUD_XCK +set_location_assignment PIN_A4 -to AUD_BCLK +set_instance_assignment -name IO_STANDARD LVTTL -to I2C_SCLK +set_instance_assignment -name IO_STANDARD LVTTL -to I2C_SDAT +set_instance_assignment -name IO_STANDARD LVTTL -to AUD_ADCLRCK +set_instance_assignment -name IO_STANDARD LVTTL -to AUD_ADCDAT +set_instance_assignment -name IO_STANDARD LVTTL -to AUD_DACLRCK +set_instance_assignment -name IO_STANDARD LVTTL -to AUD_DACDAT +set_instance_assignment -name IO_STANDARD LVTTL -to AUD_XCK +set_instance_assignment -name IO_STANDARD LVTTL -to AUD_BCLK +set_location_assignment PIN_W4 -to DRAM_ADDR[0] +set_location_assignment PIN_W5 -to DRAM_ADDR[1] +set_location_assignment PIN_Y3 -to DRAM_ADDR[2] +set_location_assignment PIN_Y4 -to DRAM_ADDR[3] +set_location_assignment PIN_R6 -to DRAM_ADDR[4] +set_location_assignment PIN_R5 -to DRAM_ADDR[5] +set_location_assignment PIN_P6 -to DRAM_ADDR[6] +set_location_assignment PIN_P5 -to DRAM_ADDR[7] +set_location_assignment PIN_P3 -to DRAM_ADDR[8] +set_location_assignment PIN_N4 -to DRAM_ADDR[9] +set_location_assignment PIN_W3 -to DRAM_ADDR[10] +set_location_assignment PIN_N6 -to DRAM_ADDR[11] +set_location_assignment PIN_U3 -to DRAM_BA_0 +set_location_assignment PIN_V4 -to DRAM_BA_1 +set_location_assignment PIN_T3 -to DRAM_CAS_N +set_location_assignment PIN_N3 -to DRAM_CKE +set_location_assignment PIN_U4 -to DRAM_CLK +set_location_assignment PIN_T6 -to DRAM_CS_N +set_location_assignment PIN_U1 -to DRAM_DQ[0] +set_location_assignment PIN_U2 -to DRAM_DQ[1] +set_location_assignment PIN_V1 -to DRAM_DQ[2] +set_location_assignment PIN_V2 -to DRAM_DQ[3] +set_location_assignment PIN_W1 -to DRAM_DQ[4] +set_location_assignment PIN_W2 -to DRAM_DQ[5] +set_location_assignment PIN_Y1 -to DRAM_DQ[6] +set_location_assignment PIN_Y2 -to DRAM_DQ[7] +set_location_assignment PIN_N1 -to DRAM_DQ[8] +set_location_assignment PIN_N2 -to DRAM_DQ[9] +set_location_assignment PIN_P1 -to DRAM_DQ[10] +set_location_assignment PIN_P2 -to DRAM_DQ[11] +set_location_assignment PIN_R1 -to DRAM_DQ[12] +set_location_assignment PIN_R2 -to DRAM_DQ[13] +set_location_assignment PIN_T1 -to DRAM_DQ[14] +set_location_assignment PIN_T2 -to DRAM_DQ[15] +set_location_assignment PIN_R7 -to DRAM_LDQM +set_location_assignment PIN_T5 -to DRAM_RAS_N +set_location_assignment PIN_M5 -to DRAM_UDQM +set_location_assignment PIN_R8 -to DRAM_WE_N +set_location_assignment PIN_AB20 -to FL_ADDR[0] +set_location_assignment PIN_AA14 -to FL_ADDR[1] +set_location_assignment PIN_Y16 -to FL_ADDR[2] +set_location_assignment PIN_R15 -to FL_ADDR[3] +set_location_assignment PIN_T15 -to FL_ADDR[4] +set_location_assignment PIN_U15 -to FL_ADDR[5] +set_location_assignment PIN_V15 -to FL_ADDR[6] +set_location_assignment PIN_W15 -to FL_ADDR[7] +set_location_assignment PIN_R14 -to FL_ADDR[8] +set_location_assignment PIN_Y13 -to FL_ADDR[9] +set_location_assignment PIN_R12 -to FL_ADDR[10] +set_location_assignment PIN_T12 -to FL_ADDR[11] +set_location_assignment PIN_AB14 -to FL_ADDR[12] +set_location_assignment PIN_AA13 -to FL_ADDR[13] +set_location_assignment PIN_AB13 -to FL_ADDR[14] +set_location_assignment PIN_AA12 -to FL_ADDR[15] +set_location_assignment PIN_AB12 -to FL_ADDR[16] +set_location_assignment PIN_AA20 -to FL_ADDR[17] +set_location_assignment PIN_U14 -to FL_ADDR[18] +set_location_assignment PIN_V14 -to FL_ADDR[19] +set_location_assignment PIN_U13 -to FL_ADDR[20] +set_location_assignment PIN_R13 -to FL_ADDR[21] +set_location_assignment PIN_AB16 -to FL_DQ[0] +set_location_assignment PIN_AA16 -to FL_DQ[1] +set_location_assignment PIN_AB17 -to FL_DQ[2] +set_location_assignment PIN_AA17 -to FL_DQ[3] +set_location_assignment PIN_AB18 -to FL_DQ[4] +set_location_assignment PIN_AA18 -to FL_DQ[5] +set_location_assignment PIN_AB19 -to FL_DQ[6] +set_location_assignment PIN_AA19 -to FL_DQ[7] +set_location_assignment PIN_AA15 -to FL_OE_N +set_location_assignment PIN_W14 -to FL_RST_N +set_location_assignment PIN_Y14 -to FL_WE_N +set_location_assignment PIN_AA3 -to SRAM_ADDR[0] +set_location_assignment PIN_AB3 -to SRAM_ADDR[1] +set_location_assignment PIN_AA4 -to SRAM_ADDR[2] +set_location_assignment PIN_AB4 -to SRAM_ADDR[3] +set_location_assignment PIN_AA5 -to SRAM_ADDR[4] +set_location_assignment PIN_AB10 -to SRAM_ADDR[5] +set_location_assignment PIN_AA11 -to SRAM_ADDR[6] +set_location_assignment PIN_AB11 -to SRAM_ADDR[7] +set_location_assignment PIN_V11 -to SRAM_ADDR[8] +set_location_assignment PIN_W11 -to SRAM_ADDR[9] +set_location_assignment PIN_R11 -to SRAM_ADDR[10] +set_location_assignment PIN_T11 -to SRAM_ADDR[11] +set_location_assignment PIN_Y10 -to SRAM_ADDR[12] +set_location_assignment PIN_U10 -to SRAM_ADDR[13] +set_location_assignment PIN_R10 -to SRAM_ADDR[14] +set_location_assignment PIN_T7 -to SRAM_ADDR[15] +set_location_assignment PIN_Y6 -to SRAM_ADDR[16] +set_location_assignment PIN_Y5 -to SRAM_ADDR[17] +set_location_assignment PIN_AB5 -to SRAM_CE_N +set_location_assignment PIN_AA6 -to SRAM_DQ[0] +set_location_assignment PIN_AB6 -to SRAM_DQ[1] +set_location_assignment PIN_AA7 -to SRAM_DQ[2] +set_location_assignment PIN_AB7 -to SRAM_DQ[3] +set_location_assignment PIN_AA8 -to SRAM_DQ[4] +set_location_assignment PIN_AB8 -to SRAM_DQ[5] +set_location_assignment PIN_AA9 -to SRAM_DQ[6] +set_location_assignment PIN_AB9 -to SRAM_DQ[7] +set_location_assignment PIN_Y9 -to SRAM_DQ[8] +set_location_assignment PIN_W9 -to SRAM_DQ[9] +set_location_assignment PIN_V9 -to SRAM_DQ[10] +set_location_assignment PIN_U9 -to SRAM_DQ[11] +set_location_assignment PIN_R9 -to SRAM_DQ[12] +set_location_assignment PIN_W8 -to SRAM_DQ[13] +set_location_assignment PIN_V8 -to SRAM_DQ[14] +set_location_assignment PIN_U8 -to SRAM_DQ[15] +set_location_assignment PIN_Y7 -to SRAM_LB_N +set_location_assignment PIN_T8 -to SRAM_OE_N +set_location_assignment PIN_W7 -to SRAM_UB_N +set_location_assignment PIN_AA10 -to SRAM_WE_N +set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED WITH WEAK PULL-UP" +set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top +set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top +set_global_assignment -name LL_ROOT_REGION ON -section_id "Root Region" +set_global_assignment -name LL_MEMBER_STATE LOCKED -section_id "Root Region" +set_global_assignment -name MISC_FILE "U:/git_repos/fpga/bbc/bbc_micro_de1.dpf" +set_location_assignment PIN_AB15 -to FL_CE_N +set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" +set_global_assignment -name STRATIX_CONFIGURATION_DEVICE EPCS4 +set_global_assignment -name RESERVE_ASDO_AFTER_CONFIGURATION "AS INPUT TRI-STATED" +set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_location_assignment PIN_U20 -to SD_nCS +set_location_assignment PIN_V20 -to SD_SCLK +set_location_assignment PIN_Y20 -to SD_MOSI +set_location_assignment PIN_W20 -to SD_MISO +set_global_assignment -name VHDL_FILE saa5050.vhd +set_global_assignment -name VHDL_FILE i2s_intf.vhd +set_global_assignment -name VHDL_FILE i2c_loader.vhd +set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_comp_pack-p.vhd" +set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_noise.vhd" +set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_tone.vhd" +set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_top.vhd" +set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_attenuator.vhd" +set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_clock_div.vhd" +set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_latch_ctrl.vhd" +set_global_assignment -name VHDL_FILE ps2_intf.vhd +set_global_assignment -name VHDL_FILE m6522.vhd +set_global_assignment -name VHDL_FILE seg7.vhd +set_global_assignment -name VHDL_FILE vidproc.vhd +set_global_assignment -name VHDL_FILE mc6845.vhd +set_global_assignment -name VHDL_FILE T65/T65_Pack.vhd +set_global_assignment -name VHDL_FILE T65/T65.vhd +set_global_assignment -name VHDL_FILE T65/T65_ALU.vhd +set_global_assignment -name VHDL_FILE T65/T65_MCode.vhd +set_global_assignment -name QIP_FILE pll32.qip +set_global_assignment -name VHDL_FILE bbc_micro_de1.vhd +set_global_assignment -name VHDL_FILE bbc_micro_de1_tb.vhd +set_global_assignment -name VHDL_FILE m6522_tb.vhd +set_global_assignment -name VHDL_FILE keyboard.vhd +set_global_assignment -name VHDL_FILE debugger.vhd +set_global_assignment -name QIP_FILE saa5050_rom.qip set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd index e109c36..0fca9de 100644 --- a/bbc_micro_de1.vhd +++ b/bbc_micro_de1.vhd @@ -1,1265 +1,1265 @@ --- BBC Micro for Altera DE1 --- --- Copyright (c) 2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- BBC B Micro --- --- Terasic DE1 top-level --- --- (C) 2011 Mike Stirling - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - --- Generic top-level entity for Altera DE1 board -entity bbc_micro_de1 is -generic ( - -- ROM offset - -- The 4MB Flash is used in 16KB banks as a simple mechanism for - -- different machines to address different parts of the ROM, saving - -- on re-flashing each time a new machine is run on the board. - -- This generic sets the upper 8 address bits. - -- Note that the lower bits may be ignored by the implementation, - -- e.g. where ROMs are bigger than 16K or where multiple banks - -- are required. In this case it is important to ensure that the - -- ROM images are aligned correctly (such that these ignored bits are 0). - -- - -- For the BBC the ROMs start in bank 8 (the first 8 banks are used by - -- the Spectrum project). The particular bank is selected by the sideways - -- ROM paging register, and bank 7 is used for the MOS. Recommended layout - -- is: - -- - -- 0 Sideways - -- 1 Sideways - -- 2 Sideways - SuperMMC (DFS) - -- 3 Sideways - BASIC - -- 4 Not used - -- 5 Not used - -- 6 Not used - -- 7 MOS - ROM_OFFSET : std_logic_vector(7 downto 0) := "00001000" - ); -port ( - -- Clocks - CLOCK_24 : in std_logic_vector(1 downto 0); - CLOCK_27 : in std_logic_vector(1 downto 0); - CLOCK_50 : in std_logic; - EXT_CLOCK : in std_logic; - - -- Switches - SW : in std_logic_vector(9 downto 0); - -- Buttons - KEY : in std_logic_vector(3 downto 0); - - -- 7 segment displays - HEX0 : out std_logic_vector(6 downto 0); - HEX1 : out std_logic_vector(6 downto 0); - HEX2 : out std_logic_vector(6 downto 0); - HEX3 : out std_logic_vector(6 downto 0); - -- Red LEDs - LEDR : out std_logic_vector(9 downto 0); - -- Green LEDs - LEDG : out std_logic_vector(7 downto 0); - - -- VGA - VGA_R : out std_logic_vector(3 downto 0); - VGA_G : out std_logic_vector(3 downto 0); - VGA_B : out std_logic_vector(3 downto 0); - VGA_HS : out std_logic; - VGA_VS : out std_logic; - - -- Serial - UART_RXD : in std_logic; - UART_TXD : out std_logic; - - -- PS/2 Keyboard - PS2_CLK : inout std_logic; - PS2_DAT : inout std_logic; - - -- I2C - I2C_SCLK : inout std_logic; - I2C_SDAT : inout std_logic; - - -- Audio - AUD_XCK : out std_logic; - AUD_BCLK : out std_logic; - AUD_ADCLRCK : out std_logic; - AUD_ADCDAT : in std_logic; - AUD_DACLRCK : out std_logic; - AUD_DACDAT : out std_logic; - - -- SRAM - SRAM_ADDR : out std_logic_vector(17 downto 0); - SRAM_DQ : inout std_logic_vector(15 downto 0); - SRAM_CE_N : out std_logic; - SRAM_OE_N : out std_logic; - SRAM_WE_N : out std_logic; - SRAM_UB_N : out std_logic; - SRAM_LB_N : out std_logic; - - -- SDRAM - DRAM_ADDR : out std_logic_vector(11 downto 0); - DRAM_DQ : inout std_logic_vector(15 downto 0); - DRAM_BA_0 : in std_logic; - DRAM_BA_1 : in std_logic; - DRAM_CAS_N : in std_logic; - DRAM_CKE : in std_logic; - DRAM_CLK : in std_logic; - DRAM_CS_N : in std_logic; - DRAM_LDQM : in std_logic; - DRAM_RAS_N : in std_logic; - DRAM_UDQM : in std_logic; - DRAM_WE_N : in std_logic; - - -- Flash - FL_ADDR : out std_logic_vector(21 downto 0); - FL_DQ : inout std_logic_vector(7 downto 0); - FL_RST_N : out std_logic; - FL_OE_N : out std_logic; - FL_WE_N : out std_logic; - FL_CE_N : out std_logic; - - -- SD card (SPI mode) - SD_nCS : out std_logic; - SD_MOSI : out std_logic; - SD_SCLK : out std_logic; - SD_MISO : in std_logic; - - -- GPIO - GPIO_0 : inout std_logic_vector(35 downto 0); - GPIO_1 : inout std_logic_vector(35 downto 0) - ); -end entity; - -architecture rtl of bbc_micro_de1 is - ------------------------------- --- PLL (32 MHz master clock) ------------------------------- - -component pll32 IS - PORT - ( - areset : IN STD_LOGIC := '0'; - inclk0 : IN STD_LOGIC := '0'; - c0 : OUT STD_LOGIC ; - locked : OUT STD_LOGIC - ); -end component; - ---------- --- CPU ---------- - -component T65 is - port( - Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 - Res_n : in std_logic; - Enable : in std_logic; - Clk : in std_logic; - Rdy : in std_logic; - Abort_n : in std_logic; - IRQ_n : in std_logic; - NMI_n : in std_logic; - SO_n : in std_logic; - R_W_n : out std_logic; - Sync : out std_logic; - EF : out std_logic; - MF : out std_logic; - XF : out std_logic; - ML_n : out std_logic; - VP_n : out std_logic; - VDA : out std_logic; - VPA : out std_logic; - A : out std_logic_vector(23 downto 0); - DI : in std_logic_vector(7 downto 0); - DO : out std_logic_vector(7 downto 0) - ); -end component; - ------------------ --- MC6845 CRTC ------------------ - -component mc6845 is -port ( - CLOCK : in std_logic; - CLKEN : in std_logic; - nRESET : in std_logic; - - -- Bus interface - ENABLE : in std_logic; - R_nW : in std_logic; - RS : in std_logic; - DI : in std_logic_vector(7 downto 0); - DO : out std_logic_vector(7 downto 0); - - -- Display interface - VSYNC : out std_logic; - HSYNC : out std_logic; - DE : out std_logic; - CURSOR : out std_logic; - LPSTB : in std_logic; - - -- Memory interface - MA : out std_logic_vector(13 downto 0); - RA : out std_logic_vector(4 downto 0) - ); -end component; - -------------------------- --- "VIDPROC" Video ULA -------------------------- - -component vidproc is -port ( - CLOCK : in std_logic; - -- Clock enable qualifies display cycles (interleaved with CPU cycles) - CLKEN : in std_logic; - nRESET : in std_logic; - - -- Clock enable output to CRTC - CLKEN_CRTC : out std_logic; - - -- Bus interface - ENABLE : in std_logic; - A0 : in std_logic; - -- CPU data bus (for register writes) - DI_CPU : in std_logic_vector(7 downto 0); - -- Display RAM data bus (for display data fetch) - DI_RAM : in std_logic_vector(7 downto 0); - - -- Control interface - nINVERT : in std_logic; - DISEN : in std_logic; - CURSOR : in std_logic; - - -- Video in (teletext mode) - R_IN : in std_logic; - G_IN : in std_logic; - B_IN : in std_logic; - - -- Video out - R : out std_logic; - G : out std_logic; - B : out std_logic - ); -end component; - --------------------------------- --- SAA5050 Teletext Generator --------------------------------- - -component saa5050 is -port ( - CLOCK : in std_logic; - -- 6 MHz dot clock enable - CLKEN : in std_logic; - -- Async reset - nRESET : in std_logic; - - -- Character data input (in the bus clock domain) - DI_CLOCK : in std_logic; - DI_CLKEN : in std_logic; - DI : in std_logic_vector(6 downto 0); - - -- Timing inputs - -- General line reset (not used) - GLR : in std_logic; -- /HSYNC - -- Data entry window - high during VSYNC. - -- Resets ROM row counter and drives 'flash' signal - DEW : in std_logic; -- VSYNC - -- Character rounding select - high during even field - CRS : in std_logic; -- FIELD - -- Load output shift register enable - high during active video - LOSE : in std_logic; -- DE - - -- Video out - R : out std_logic; - G : out std_logic; - B : out std_logic; - Y : out std_logic - ); -end component; - --------------- --- 6522 VIA --------------- - -component M6522 is - port ( - - I_RS : in std_logic_vector(3 downto 0); - I_DATA : in std_logic_vector(7 downto 0); - O_DATA : out std_logic_vector(7 downto 0); - O_DATA_OE_L : out std_logic; - - I_RW_L : in std_logic; - I_CS1 : in std_logic; - I_CS2_L : in std_logic; - - O_IRQ_L : out std_logic; -- note, not open drain - -- port a - I_CA1 : in std_logic; - I_CA2 : in std_logic; - O_CA2 : out std_logic; - O_CA2_OE_L : out std_logic; - - I_PA : in std_logic_vector(7 downto 0); - O_PA : out std_logic_vector(7 downto 0); - O_PA_OE_L : out std_logic_vector(7 downto 0); - - -- port b - I_CB1 : in std_logic; - O_CB1 : out std_logic; - O_CB1_OE_L : out std_logic; - - I_CB2 : in std_logic; - O_CB2 : out std_logic; - O_CB2_OE_L : out std_logic; - - I_PB : in std_logic_vector(7 downto 0); - O_PB : out std_logic_vector(7 downto 0); - O_PB_OE_L : out std_logic_vector(7 downto 0); - - -- FIXME: Revisit timing in this component. Does it really need a 4x clock? - I_P2_H : in std_logic; -- high for phase 2 clock ____----__ - RESET_L : in std_logic; - ENA_4 : in std_logic; -- clk enable (4x system clock rate) - CLK : in std_logic - ); -end component; - ------------------------------ --- PS/2 Keyboard Emulation ------------------------------ - -component keyboard is -port ( - CLOCK : in std_logic; - nRESET : in std_logic; - CLKEN_1MHZ : in std_logic; - - -- PS/2 interface - PS2_CLK : in std_logic; - PS2_DATA : in std_logic; - - -- If 1 then column is incremented automatically at - -- 1 MHz rate - AUTOSCAN : in std_logic; - - COLUMN : in std_logic_vector(3 downto 0); - ROW : in std_logic_vector(2 downto 0); - - -- 1 when currently selected key is down (AUTOSCAN disabled) - KEYPRESS : out std_logic; - -- 1 when any key is down (except row 0) - INT : out std_logic; - -- BREAK key output - 1 when pressed - BREAK_OUT : out std_logic; - - -- DIP switch inputs - DIP_SWITCH : in std_logic_vector(7 downto 0) - ); -end component; - ------------------------------ --- SN76489 sound generator ------------------------------ - -component sn76489_top is - - generic ( - clock_div_16_g : integer := 1 - ); - port ( - clock_i : in std_logic; - clock_en_i : in std_logic; - res_n_i : in std_logic; - ce_n_i : in std_logic; - we_n_i : in std_logic; - ready_o : out std_logic; - d_i : in std_logic_vector(0 to 7); - aout_o : out signed(0 to 7) - ); - -end component; - -component i2s_intf is -generic( - mclk_rate : positive := 12000000; - sample_rate : positive := 8000; - preamble : positive := 1; -- I2S - word_length : positive := 16 - ); - -port ( - -- 2x MCLK in (e.g. 24 MHz for WM8731 USB mode) - CLK : in std_logic; - nRESET : in std_logic; - - -- Parallel IO - PCM_INL : out std_logic_vector(word_length - 1 downto 0); - PCM_INR : out std_logic_vector(word_length - 1 downto 0); - PCM_OUTL : in std_logic_vector(word_length - 1 downto 0); - PCM_OUTR : in std_logic_vector(word_length - 1 downto 0); - - -- Codec interface (right justified mode) - -- MCLK is generated at half of the CLK input - I2S_MCLK : out std_logic; - -- LRCLK is equal to the sample rate and is synchronous to - -- MCLK. It must be related to MCLK by the oversampling ratio - -- given in the codec datasheet. - I2S_LRCLK : out std_logic; - - -- Data is shifted out on the falling edge of BCLK, sampled - -- on the rising edge. The bit rate is determined such that - -- it is fast enough to fit preamble + word_length bits into - -- each LRCLK half cycle. The last cycle of each word may be - -- stretched to fit to LRCLK. This is OK at least for the - -- WM8731 codec. - -- The first falling edge of each timeslot is always synchronised - -- with the LRCLK edge. - I2S_BCLK : out std_logic; - -- Output bitstream - I2S_DOUT : out std_logic; - -- Input bitstream - I2S_DIN : in std_logic - ); -end component; - -component i2c_loader is -generic ( - -- Address of slave to be loaded - device_address : integer := 16#1a#; - -- Number of retries to allow before stopping - num_retries : integer := 0; - -- Length of clock divider in bits. Resulting bus frequency is - -- CLK/2^(log2_divider + 2) - log2_divider : integer := 6 -); - -port ( - CLK : in std_logic; - nRESET : in std_logic; - - I2C_SCL : inout std_logic; - I2C_SDA : inout std_logic; - - IS_DONE : out std_logic; - IS_ERROR : out std_logic - ); -end component; - -component debugger is -generic ( - -- Set this for a reasonable half flash duration relative to the - -- clock frequency - flash_divider : natural := 24 - ); -port ( - CLOCK : in std_logic; - nRESET : in std_logic; - -- CPU clock enable in - CLKEN_IN : in std_logic; - -- Gated clock enable back out to CPU - CLKEN_OUT : out std_logic; - -- CPU IRQ in - nIRQ_IN : in std_logic; - -- Gated IRQ back out to CPU (no interrupts when single stepping) - nIRQ_OUT : out std_logic; - - -- CPU - A_CPU : in std_logic_vector(15 downto 0); - R_nW : in std_logic; - SYNC : in std_logic; - - -- Aux bus input for display in hex - AUX_BUS : in std_logic_vector(15 downto 0); - - -- Controls - -- RUN or HALT CPU - RUN : in std_logic; - -- Push button to single-step in HALT mode - nSTEP : in std_logic; - -- Push button to cycle display mode - nMODE : in std_logic; - -- Push button to cycle display digit in edit mode - nDIGIT : in std_logic; - -- Push button to cycle digit value in edit mode - nSET : in std_logic; - - -- Output to display - DIGIT3 : out std_logic_vector(6 downto 0); - DIGIT2 : out std_logic_vector(6 downto 0); - DIGIT1 : out std_logic_vector(6 downto 0); - DIGIT0 : out std_logic_vector(6 downto 0); - - LED_BREAKPOINT : out std_logic; - LED_WATCHPOINT : out std_logic - ); -end component; - -------------- --- Signals -------------- - --- Master clock - 32 MHz -signal pll_reset : std_logic; -signal pll_locked : std_logic; -signal clock : std_logic; -signal hard_reset_n : std_logic; -signal reset_n : std_logic; - --- Clock enable counter --- CPU and video cycles are interleaved. The CPU runs at 2 MHz (every 16th --- cycle) and the video subsystem is enabled on every odd cycle. -signal clken_counter : unsigned(4 downto 0); -signal cpu_cycle : std_logic; -- Qualifies all 2 MHz cycles -signal cpu_cycle_mask : std_logic; -- Set to mask CPU cycles until 1 MHz cycle is complete -signal cpu_clken : std_logic; -- 2 MHz cycles in which the CPU is enabled -signal cpu_debug_clken : std_logic; -- CPU clken return from hardware debugger --- IO cycles are out of phase with the CPU -signal vid_clken : std_logic; -- 16 MHz video cycles -signal mhz4_clken : std_logic; -- Used by 6522 -signal mhz2_clken : std_logic; -- Used for latching CPU address for clock stretch -signal mhz1_clken : std_logic; -- 1 MHz bus and associated peripherals, 6522 phase 2 --- SAA5050 needs a 6 MHz clock enable relative to a 24 MHz clock -signal ttxt_clken_counter : unsigned(1 downto 0); -signal ttxt_clken : std_logic; - --- Debugger connections -signal debug_irq_in_n : std_logic; -signal debug_aux : std_logic_vector(15 downto 0); - --- CPU signals -signal cpu_mode : std_logic_vector(1 downto 0); -signal cpu_ready : std_logic; -signal cpu_abort_n : std_logic; -signal cpu_irq_n : std_logic; -signal cpu_nmi_n : std_logic; -signal cpu_so_n : std_logic; -signal cpu_r_nw : std_logic; -signal cpu_sync : std_logic; -signal cpu_ef : std_logic; -signal cpu_mf : std_logic; -signal cpu_xf : std_logic; -signal cpu_ml_n : std_logic; -signal cpu_vp_n : std_logic; -signal cpu_vda : std_logic; -signal cpu_vpa : std_logic; -signal cpu_a : std_logic_vector(23 downto 0); -signal cpu_di : std_logic_vector(7 downto 0); -signal cpu_do : std_logic_vector(7 downto 0); - --- CRTC signals -signal crtc_clken : std_logic; -signal crtc_do : std_logic_vector(7 downto 0); -signal crtc_vsync : std_logic; -signal crtc_hsync : std_logic; -signal crtc_de : std_logic; -signal crtc_cursor : std_logic; -signal crtc_lpstb : std_logic := '0'; -signal crtc_ma : std_logic_vector(13 downto 0); -signal crtc_ra : std_logic_vector(4 downto 0); - --- Decoded display address after address translation for hardware --- scrolling -signal display_a : std_logic_vector(14 downto 0); - --- "VIDPROC" signals -signal vidproc_invert_n : std_logic; -signal vidproc_disen : std_logic; -signal r_in : std_logic; -signal g_in : std_logic; -signal b_in : std_logic; -signal r_out : std_logic; -signal g_out : std_logic; -signal b_out : std_logic; - --- SAA5050 signals -signal ttxt_glr : std_logic; -signal ttxt_dew : std_logic; -signal ttxt_crs : std_logic; -signal ttxt_lose : std_logic; -signal ttxt_r : std_logic; -signal ttxt_g : std_logic; -signal ttxt_b : std_logic; -signal ttxt_y : std_logic; - --- System VIA signals -signal sys_via_do : std_logic_vector(7 downto 0); -signal sys_via_do_oe_n : std_logic; -signal sys_via_irq_n : std_logic; -signal sys_via_ca1_in : std_logic := '0'; -signal sys_via_ca2_in : std_logic := '0'; -signal sys_via_ca2_out : std_logic; -signal sys_via_ca2_oe_n : std_logic; -signal sys_via_pa_in : std_logic_vector(7 downto 0); -signal sys_via_pa_out : std_logic_vector(7 downto 0); -signal sys_via_pa_oe_n : std_logic_vector(7 downto 0); -signal sys_via_cb1_in : std_logic := '0'; -signal sys_via_cb1_out : std_logic; -signal sys_via_cb1_oe_n : std_logic; -signal sys_via_cb2_in : std_logic := '0'; -signal sys_via_cb2_out : std_logic; -signal sys_via_cb2_oe_n : std_logic; -signal sys_via_pb_in : std_logic_vector(7 downto 0); -signal sys_via_pb_out : std_logic_vector(7 downto 0); -signal sys_via_pb_oe_n : std_logic_vector(7 downto 0); - --- User VIA signals -signal user_via_do : std_logic_vector(7 downto 0); -signal user_via_do_oe_n : std_logic; -signal user_via_irq_n : std_logic; -signal user_via_ca1_in : std_logic := '0'; -signal user_via_ca2_in : std_logic := '0'; -signal user_via_ca2_out : std_logic; -signal user_via_ca2_oe_n : std_logic; -signal user_via_pa_in : std_logic_vector(7 downto 0); -signal user_via_pa_out : std_logic_vector(7 downto 0); -signal user_via_pa_oe_n : std_logic_vector(7 downto 0); -signal user_via_cb1_in : std_logic := '0'; -signal user_via_cb1_out : std_logic; -signal user_via_cb1_oe_n : std_logic; -signal user_via_cb2_in : std_logic := '0'; -signal user_via_cb2_out : std_logic; -signal user_via_cb2_oe_n : std_logic; -signal user_via_pb_in : std_logic_vector(7 downto 0); -signal user_via_pb_out : std_logic_vector(7 downto 0); -signal user_via_pb_oe_n : std_logic_vector(7 downto 0); - --- IC32 latch on System VIA -signal ic32 : std_logic_vector(7 downto 0); -signal sound_enable_n : std_logic; -signal speech_read_n : std_logic; -signal speech_write_n : std_logic; -signal keyb_enable_n : std_logic; -signal disp_addr_offs : std_logic_vector(1 downto 0); -signal caps_lock_led_n : std_logic; -signal shift_lock_led_n : std_logic; - --- Keyboard -signal keyb_column : std_logic_vector(3 downto 0); -signal keyb_row : std_logic_vector(2 downto 0); -signal keyb_out : std_logic; -signal keyb_int : std_logic; -signal keyb_break : std_logic; - --- Sound generator -signal sound_ready : std_logic; -signal sound_di : std_logic_vector(7 downto 0); -signal sound_ao : signed(7 downto 0); -signal pcm_inl : std_logic_vector(15 downto 0); -signal pcm_inr : std_logic_vector(15 downto 0); - --- Memory enables -signal ram_enable : std_logic; -- 0x0000 -signal rom_enable : std_logic; -- 0x8000 (BASIC/sideways ROMs) -signal mos_enable : std_logic; -- 0xC000 --- IO region enables -signal io_fred : std_logic; -- 0xFC00 (1 MHz bus) -signal io_jim : std_logic; -- 0xFD00 (1 MHz bus) -signal io_sheila : std_logic; -- 0xFE00 (System peripherals) --- SHIELA -signal crtc_enable : std_logic; -- 0xFE00-FE07 -signal acia_enable : std_logic; -- 0xFE08-FE0F -signal serproc_enable : std_logic; -- 0xFE10-FE1F -signal vidproc_enable : std_logic; -- 0xFE20-FE2F -signal romsel_enable : std_logic; -- 0xFE30-FE3F -signal sys_via_enable : std_logic; -- 0xFE40-FE5F -signal user_via_enable : std_logic; -- 0xFE60-FE7F -signal fddc_enable : std_logic; -- 0xFE80-FE9F -signal adlc_enable : std_logic; -- 0xFEA0-FEBF (Econet) -signal adc_enable : std_logic; -- 0xFEC0-FEDF -signal tube_enable : std_logic; -- 0xFEE0-FEFF - --- ROM select latch -signal romsel : std_logic_vector(3 downto 0); - -signal mhz1_enable : std_logic; -- Set for access to any 1 MHz peripheral - -begin - ------------------------- - -- COMPONENT INSTANCES - ------------------------- - - -- 32 MHz master clock - pll: pll32 port map ( - pll_reset, - CLOCK_24(0), - clock, - pll_locked ); - - -- Hardware debugger block (single-step, breakpoints) - debug: debugger port map ( - clock, - hard_reset_n, - cpu_clken, - cpu_debug_clken, - debug_irq_in_n, - cpu_irq_n, - cpu_a(15 downto 0), cpu_r_nw, cpu_sync, - debug_aux, - SW(8), -- RUN - KEY(3), -- STEP - KEY(2), -- MODE - KEY(1), -- DIGIT - KEY(0), -- SET - HEX3, HEX2, HEX1, HEX0, - LEDR(3), -- BREAKPOINT - LEDR(2) -- WATCHPOINT - ); - - -- 6502 CPU - cpu : T65 port map ( - cpu_mode, - reset_n, - cpu_debug_clken, - clock, - cpu_ready, - cpu_abort_n, - cpu_irq_n, - cpu_nmi_n, - cpu_so_n, - cpu_r_nw, - cpu_sync, - cpu_ef, - cpu_mf, - cpu_xf, - cpu_ml_n, - cpu_vp_n, - cpu_vda, - cpu_vpa, - cpu_a, - cpu_di, - cpu_do ); - - crtc : mc6845 port map ( - clock, - crtc_clken, - reset_n, - crtc_enable, - cpu_r_nw, - cpu_a(0), - cpu_do, - crtc_do, - crtc_vsync, - crtc_hsync, - crtc_de, - crtc_cursor, - crtc_lpstb, - crtc_ma, - crtc_ra ); - - video_ula : vidproc port map ( - clock, - vid_clken, - reset_n, - crtc_clken, - vidproc_enable, - cpu_a(0), - cpu_do, - SRAM_DQ(7 downto 0), - vidproc_invert_n, - vidproc_disen, - crtc_cursor, - r_in, g_in, b_in, - r_out, g_out, b_out - ); - - teletext : saa5050 port map ( - CLOCK_24(0), -- This runs at 6 MHz, which we can't derive from the 32 MHz clock - ttxt_clken, - reset_n, - clock, -- Data input is synchronised from the bus clock domain - vid_clken, - SRAM_DQ(6 downto 0), - ttxt_glr, - ttxt_dew, - ttxt_crs, - ttxt_lose, - ttxt_r, ttxt_g, ttxt_b, ttxt_y - ); - - -- System VIA - system_via : m6522 port map ( - cpu_a(3 downto 0), - cpu_do, - sys_via_do, - sys_via_do_oe_n, - cpu_r_nw, - sys_via_enable, - '0', -- nCS2 - sys_via_irq_n, - sys_via_ca1_in, - sys_via_ca2_in, - sys_via_ca2_out, - sys_via_ca2_oe_n, - sys_via_pa_in, - sys_via_pa_out, - sys_via_pa_oe_n, - sys_via_cb1_in, - sys_via_cb1_out, - sys_via_cb1_oe_n, - sys_via_cb2_in, - sys_via_cb2_out, - sys_via_cb2_oe_n, - sys_via_pb_in, - sys_via_pb_out, - sys_via_pb_oe_n, - mhz1_clken, - hard_reset_n, -- System VIA is reset by power on reset only - mhz4_clken, - clock - ); - - -- User VIA - user_via : m6522 port map ( - cpu_a(3 downto 0), - cpu_do, - user_via_do, - user_via_do_oe_n, - cpu_r_nw, - user_via_enable, - '0', -- nCS2 - user_via_irq_n, - user_via_ca1_in, - user_via_ca2_in, - user_via_ca2_out, - user_via_ca2_oe_n, - user_via_pa_in, - user_via_pa_out, - user_via_pa_oe_n, - user_via_cb1_in, - user_via_cb1_out, - user_via_cb1_oe_n, - user_via_cb2_in, - user_via_cb2_out, - user_via_cb2_oe_n, - user_via_pb_in, - user_via_pb_out, - user_via_pb_oe_n, - mhz1_clken, - reset_n, - mhz4_clken, - clock - ); - - -- Keyboard - keyb : keyboard port map ( - clock, hard_reset_n, mhz1_clken, - PS2_CLK, PS2_DAT, - keyb_enable_n, - keyb_column, - keyb_row, - keyb_out, - keyb_int, - keyb_break, - SW(7 downto 0) - ); - - -- Sound generator (and drive logic for I2S codec) - sound : sn76489_top port map ( - clock, mhz4_clken, - reset_n, '0', sound_enable_n, - sound_ready, sound_di, - sound_ao - ); - i2s : i2s_intf port map ( - CLOCK_24(0), reset_n, - pcm_inl, pcm_inr, - std_logic_vector(sound_ao) & "00000000", - std_logic_vector(sound_ao) & "00000000", - AUD_XCK, AUD_DACLRCK, - AUD_BCLK, AUD_DACDAT, AUD_ADCDAT - ); - i2c : i2c_loader - generic map ( - log2_divider => 7 - ) - port map ( - clock, reset_n, - I2C_SCLK, I2C_SDAT, - LEDR(5), -- IS_DONE - LEDR(4) -- IS_ERROR - ); - - -- Asynchronous reset - -- PLL is reset by external reset switch - pll_reset <= not SW(9); - -- Keyboard and System VIA are reset by external reset switch or PLL being out of lock - hard_reset_n <= not (pll_reset or not pll_locked); - -- Rest of system is reset by all of the above plus the keyboard BREAK key - reset_n <= hard_reset_n and not keyb_break; - - -- Clock enable generation - 32 MHz clock split into 32 cycles - -- CPU is on 0 and 16 (but can be masked by 1 MHz bus accesses) - -- Video is on all odd cycles (16 MHz) - -- 1 MHz cycles are on cycle 31 (1 MHz) - vid_clken <= clken_counter(0); -- 1,3,5... - mhz4_clken <= clken_counter(0) and clken_counter(1) and clken_counter(2); -- 7/15/23/31 - mhz2_clken <= mhz4_clken and clken_counter(3); -- 15/31 - mhz1_clken <= mhz2_clken and clken_counter(4); -- 31 - cpu_cycle <= not (clken_counter(0) or clken_counter(1) or clken_counter(2) or clken_counter(3)); -- 0/16 - cpu_clken <= cpu_cycle and not cpu_cycle_mask; - - clk_gen: process(clock,reset_n) - begin - if reset_n = '0' then - clken_counter <= (others => '0'); - elsif rising_edge(clock) then - clken_counter <= clken_counter + 1; - end if; - end process; - - cycle_stretch: process(clock,reset_n) - begin - if reset_n = '0' then - cpu_cycle_mask <= '0'; - elsif rising_edge(clock) and mhz2_clken = '1' then - if mhz1_enable = '1' and cpu_cycle_mask = '0' then - -- Block CPU cycles until 1 MHz cycle has completed - cpu_cycle_mask <= '1'; - end if; - if mhz1_clken = '1' then - -- CPU can run again - -- FIXME: This may not be correct in terms of CPU cycles, but it - -- should work - cpu_cycle_mask <= '0'; - end if; - end if; - end process; - - ttxt_clk_gen: process(CLOCK_24(0),reset_n) - begin - if reset_n = '0' then - ttxt_clken_counter <= (others => '0'); - elsif rising_edge(CLOCK_24(0)) then - ttxt_clken_counter <= ttxt_clken_counter + 1; - end if; - end process; - - -- 6 MHz clock enable for SAA5050 - ttxt_clken <= '1' when ttxt_clken_counter = 0 else '0'; - - -- CPU configuration and fixed signals - cpu_mode <= "00"; -- 6502 - cpu_ready <= '1'; - cpu_abort_n <= '1'; - cpu_nmi_n <= '1'; - cpu_so_n <= '1'; - - -- Address decoding - -- 0x0000 = 32 KB SRAM - -- 0x8000 = 16 KB BASIC/Sideways ROMs - -- 0xC000 = 16 KB MOS ROM - -- - -- IO regions are mapped into a hole in the MOS. There are three regions: - -- 0xFC00 = FRED - -- 0xFD00 = JIM - -- 0xFE00 = SHEILA - ram_enable <= not cpu_a(15); - rom_enable <= cpu_a(15) and not cpu_a(14); - mos_enable <= cpu_a(15) and cpu_a(14) and not (io_fred or io_jim or io_sheila); - io_fred <= '1' when cpu_a(15 downto 8) = "11111100" else '0'; - io_jim <= '1' when cpu_a(15 downto 8) = "11111101" else '0'; - io_sheila <= '1' when cpu_a(15 downto 8) = "11111110" else '0'; - -- The following IO regions are accessed at 1 MHz and hence will stall the - -- CPU accordingly - mhz1_enable <= io_fred or io_jim or - adc_enable or sys_via_enable or user_via_enable or - serproc_enable or acia_enable or crtc_enable; - - -- SHEILA address demux - -- All the system peripherals are mapped into this page as follows: - -- 0xFE00 - 0xFE07 = MC6845 CRTC - -- 0xFE08 - 0xFE0F = MC6850 ACIA (Serial/Tape) - -- 0xFE10 - 0xFE1F = Serial ULA - -- 0xFE20 - 0xFE2F = Video ULA - -- 0xFE30 - 0xFE3F = Paged ROM select latch - -- 0xFE40 - 0xFE5F = System VIA (6522) - -- 0xFE60 - 0xFE7F = User VIA (6522) - -- 0xFE80 - 0xFE9F = 8271 Floppy disc controller - -- 0xFEA0 - 0xFEBF = 68B54 ADLC for Econet - -- 0xFEC0 - 0xFEDF = uPD7002 ADC - -- 0xFEE0 - 0xFEFF = Tube ULA - process(cpu_a,io_sheila) - begin - -- All regions normally de-selected - crtc_enable <= '0'; - acia_enable <= '0'; - serproc_enable <= '0'; - vidproc_enable <= '0'; - romsel_enable <= '0'; - sys_via_enable <= '0'; - user_via_enable <= '0'; - fddc_enable <= '0'; - adlc_enable <= '0'; - adc_enable <= '0'; - tube_enable <= '0'; - - if io_sheila = '1' then - case cpu_a(7 downto 5) is - when "000" => - -- 0xFE00 - if cpu_a(4) = '0' then - if cpu_a(3) = '0' then - -- 0xFE00 - crtc_enable <= '1'; - else - -- 0xFE08 - acia_enable <= '1'; - end if; - else - -- 0xFE10 - serproc_enable <= '1'; - end if; - when "001" => - -- 0xFE20 - if cpu_a(4) = '0' then - -- 0xFE20 - vidproc_enable <= '1'; - else - -- 0xFE30 - romsel_enable <= '1'; - end if; - when "010" => sys_via_enable <= '1'; -- 0xFE40 - when "011" => user_via_enable <= '1'; -- 0xFE60 - when "100" => fddc_enable <= '1'; -- 0xFE80 - when "101" => adlc_enable <= '1'; -- 0xFEA0 - when "110" => adc_enable <= '1'; -- 0xFEC0 - when "111" => tube_enable <= '1'; -- 0xFEE0 - when others => - null; - end case; - end if; - end process; - - -- CPU data bus mux and interrupts - cpu_di <= - SRAM_DQ(7 downto 0) when ram_enable = '1' else - FL_DQ when rom_enable = '1' else - FL_DQ when mos_enable = '1' else - crtc_do when crtc_enable = '1' else - "00000010" when acia_enable = '1' else - sys_via_do when sys_via_enable = '1' else - user_via_do when user_via_enable = '1' else - (others => '0'); -- un-decoded locations are pulled down by RP1 - debug_irq_in_n <= sys_via_irq_n and user_via_irq_n; -- route IRQ through debugger - --cpu_irq_n <= sys_via_irq_n and user_via_irq_n; - - -- ROMs are in external flash and split into 16K slots (since this also suits other - -- computers that might be run on the same board). - -- The first 8 slots are allocated for use here, and the first 4 are decoded as - -- the sideways ROMs. Slot 7 is used for the MOS. - FL_RST_N <= reset_n; - FL_CE_N <= '0'; - FL_OE_N <= '0'; - FL_WE_N <= '1'; - FL_ADDR(21 downto 17) <= ROM_OFFSET(7 downto 3); - FL_ADDR(16 downto 14) <= - "111" when mos_enable = '1' else - "0" & romsel(1 downto 0); - FL_ADDR(13 downto 0) <= cpu_a(13 downto 0); - - -- SRAM bus - SRAM_UB_N <= '1'; - SRAM_LB_N <= '0'; - SRAM_CE_N <= '0'; - SRAM_OE_N <= '0'; - SRAM_DQ(15 downto 8) <= (others => '0'); - - -- Synchronous outputs to SRAM - process(clock,reset_n) - variable ram_write : std_logic; - begin - ram_write := ram_enable and not cpu_r_nw; - - if reset_n = '0' then - SRAM_WE_N <= '1'; - SRAM_DQ(7 downto 0) <= (others => 'Z'); - elsif rising_edge(clock) then - -- Default to inputs - SRAM_DQ(7 downto 0) <= (others => 'Z'); - - -- Register SRAM signals to outputs (clock must be at least 2x CPU clock) - if vid_clken = '1' then - -- Fetch data from previous CPU cycle - SRAM_WE_N <= not ram_write; - SRAM_ADDR <= "00" & cpu_a(15 downto 0); - if ram_write = '1' then - SRAM_DQ(7 downto 0) <= cpu_do; - end if; - else - -- Fetch data from previous display cycle - SRAM_WE_N <= '1'; - SRAM_ADDR <= "000" & display_a; - end if; - end if; - end process; - - -- Address translation logic for calculation of display address - process(crtc_ma,crtc_ra,disp_addr_offs) - variable aa : unsigned(3 downto 0); - begin - if crtc_ma(12) = '0' then - -- No adjustment - aa := unsigned(crtc_ma(11 downto 8)); - else - -- Address adjusted according to screen mode to compensate for - -- wrap at 0x8000. - case disp_addr_offs is - when "00" => - -- Mode 3 - restart at 0x4000 - aa := unsigned(crtc_ma(11 downto 8)) + 8; - when "01" => - -- Mode 6 - restart at 0x6000 - aa := unsigned(crtc_ma(11 downto 8)) + 12; - when "10" => - -- Mode 0,1,2 - restart at 0x3000 - aa := unsigned(crtc_ma(11 downto 8)) + 6; - when "11" => - -- Mode 4,5 - restart at 0x5800 - aa := unsigned(crtc_ma(11 downto 8)) + 11; - when others => - null; - end case; - end if; - - if crtc_ma(13) = '0' then - -- HI RES - display_a <= std_logic_vector(aa(3 downto 0)) & crtc_ma(7 downto 0) & crtc_ra(2 downto 0); - else - -- TTX VDU - display_a <= std_logic(aa(3)) & "1111" & crtc_ma(9 downto 0); - end if; - end process; - - -- VIDPROC - vidproc_invert_n <= '1'; - vidproc_disen <= crtc_de and not crtc_ra(3); -- DISEN is masked off by RA(3) for MODEs 3 and 6 - r_in <= ttxt_r; - g_in <= ttxt_g; - b_in <= ttxt_b; - - -- SAA5050 - ttxt_glr <= not crtc_hsync; - ttxt_dew <= crtc_vsync; - ttxt_crs <= not crtc_ra(0); - ttxt_lose <= crtc_de; - - -- CRTC drives video out (CSYNC on HSYNC output, VSYNC high) - VGA_HS <= not (crtc_hsync xor crtc_vsync); - VGA_VS <= '1'; - VGA_R <= r_out & r_out & r_out & r_out; - VGA_G <= g_out & g_out & g_out & g_out; - VGA_B <= b_out & b_out & b_out & b_out; - - -- Connections to System VIA - -- ADC - sys_via_cb1_in <= '1'; -- /EOC - -- CRTC - sys_via_ca1_in <= crtc_vsync; - sys_via_cb2_in <= crtc_lpstb; - -- Keyboard - sys_via_ca2_in <= keyb_int; - sys_via_pa_in(7) <= keyb_out; - sys_via_pa_in(6 downto 0) <= sys_via_pa_out(6 downto 0); -- Must loop back output pins or keyboard won't work - keyb_column <= sys_via_pa_out(3 downto 0); - keyb_row <= sys_via_pa_out(6 downto 4); - -- Sound - sound_di <= sys_via_pa_out; - -- Others (idle until missing bits implemented) - sys_via_pb_in(7 downto 4) <= (others => '1'); - - -- Connections to User VIA (user port is output on green LEDs) - user_via_ca1_in <= '1'; -- Pulled up - --LEDG <= user_via_pb_out; - - -- MMBEEB - user_via_cb1_in <= user_via_pb_out(1); - SD_SCLK <= user_via_pb_out(1); -- SCLK - SD_MOSI <= user_via_pb_out(0); -- SDO - SD_nCS <= '0'; -- CS - user_via_cb2_in <= SD_MISO; -- SDI - user_via_pb_in <= user_via_pb_out; - - -- ROM select latch - process(clock,reset_n) - begin - if reset_n = '0' then - romsel <= (others => '0'); - elsif rising_edge(clock) then - if romsel_enable = '1' and cpu_r_nw = '0' then - romsel <= cpu_do(3 downto 0); - end if; - end if; - end process; - - -- IC32 latch - sound_enable_n <= ic32(0); - speech_write_n <= ic32(1); - speech_read_n <= ic32(2); - keyb_enable_n <= ic32(3); - disp_addr_offs <= ic32(5 downto 4); - caps_lock_led_n <= ic32(6); - shift_lock_led_n <= ic32(7); - - process(clock,reset_n) - variable bit_num : integer; - begin - bit_num := to_integer(unsigned(sys_via_pb_out(2 downto 0))); - - if reset_n = '0' then - ic32 <= (others => '0'); - elsif rising_edge(clock) then - ic32(bit_num) <= sys_via_pb_out(3); - end if; - end process; - - -- Keyboard LEDs - LEDR(0) <= not caps_lock_led_n; - LEDR(1) <= not shift_lock_led_n; - - ----------------- - -- DEBUG STUFF - ----------------- - - GPIO_0(0) <= not (crtc_hsync xor crtc_vsync); - GPIO_0(1) <= crtc_de; - -end architecture; +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- BBC B Micro +-- +-- Terasic DE1 top-level +-- +-- (C) 2011 Mike Stirling + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +-- Generic top-level entity for Altera DE1 board +entity bbc_micro_de1 is +generic ( + -- ROM offset + -- The 4MB Flash is used in 16KB banks as a simple mechanism for + -- different machines to address different parts of the ROM, saving + -- on re-flashing each time a new machine is run on the board. + -- This generic sets the upper 8 address bits. + -- Note that the lower bits may be ignored by the implementation, + -- e.g. where ROMs are bigger than 16K or where multiple banks + -- are required. In this case it is important to ensure that the + -- ROM images are aligned correctly (such that these ignored bits are 0). + -- + -- For the BBC the ROMs start in bank 8 (the first 8 banks are used by + -- the Spectrum project). The particular bank is selected by the sideways + -- ROM paging register, and bank 7 is used for the MOS. Recommended layout + -- is: + -- + -- 0 Sideways + -- 1 Sideways + -- 2 Sideways - SuperMMC (DFS) + -- 3 Sideways - BASIC + -- 4 Not used + -- 5 Not used + -- 6 Not used + -- 7 MOS + ROM_OFFSET : std_logic_vector(7 downto 0) := "00001000" + ); +port ( + -- Clocks + CLOCK_24 : in std_logic_vector(1 downto 0); + CLOCK_27 : in std_logic_vector(1 downto 0); + CLOCK_50 : in std_logic; + EXT_CLOCK : in std_logic; + + -- Switches + SW : in std_logic_vector(9 downto 0); + -- Buttons + KEY : in std_logic_vector(3 downto 0); + + -- 7 segment displays + HEX0 : out std_logic_vector(6 downto 0); + HEX1 : out std_logic_vector(6 downto 0); + HEX2 : out std_logic_vector(6 downto 0); + HEX3 : out std_logic_vector(6 downto 0); + -- Red LEDs + LEDR : out std_logic_vector(9 downto 0); + -- Green LEDs + LEDG : out std_logic_vector(7 downto 0); + + -- VGA + VGA_R : out std_logic_vector(3 downto 0); + VGA_G : out std_logic_vector(3 downto 0); + VGA_B : out std_logic_vector(3 downto 0); + VGA_HS : out std_logic; + VGA_VS : out std_logic; + + -- Serial + UART_RXD : in std_logic; + UART_TXD : out std_logic; + + -- PS/2 Keyboard + PS2_CLK : inout std_logic; + PS2_DAT : inout std_logic; + + -- I2C + I2C_SCLK : inout std_logic; + I2C_SDAT : inout std_logic; + + -- Audio + AUD_XCK : out std_logic; + AUD_BCLK : out std_logic; + AUD_ADCLRCK : out std_logic; + AUD_ADCDAT : in std_logic; + AUD_DACLRCK : out std_logic; + AUD_DACDAT : out std_logic; + + -- SRAM + SRAM_ADDR : out std_logic_vector(17 downto 0); + SRAM_DQ : inout std_logic_vector(15 downto 0); + SRAM_CE_N : out std_logic; + SRAM_OE_N : out std_logic; + SRAM_WE_N : out std_logic; + SRAM_UB_N : out std_logic; + SRAM_LB_N : out std_logic; + + -- SDRAM + DRAM_ADDR : out std_logic_vector(11 downto 0); + DRAM_DQ : inout std_logic_vector(15 downto 0); + DRAM_BA_0 : in std_logic; + DRAM_BA_1 : in std_logic; + DRAM_CAS_N : in std_logic; + DRAM_CKE : in std_logic; + DRAM_CLK : in std_logic; + DRAM_CS_N : in std_logic; + DRAM_LDQM : in std_logic; + DRAM_RAS_N : in std_logic; + DRAM_UDQM : in std_logic; + DRAM_WE_N : in std_logic; + + -- Flash + FL_ADDR : out std_logic_vector(21 downto 0); + FL_DQ : inout std_logic_vector(7 downto 0); + FL_RST_N : out std_logic; + FL_OE_N : out std_logic; + FL_WE_N : out std_logic; + FL_CE_N : out std_logic; + + -- SD card (SPI mode) + SD_nCS : out std_logic; + SD_MOSI : out std_logic; + SD_SCLK : out std_logic; + SD_MISO : in std_logic; + + -- GPIO + GPIO_0 : inout std_logic_vector(35 downto 0); + GPIO_1 : inout std_logic_vector(35 downto 0) + ); +end entity; + +architecture rtl of bbc_micro_de1 is + +------------------------------ +-- PLL (32 MHz master clock) +------------------------------ + +component pll32 IS + PORT + ( + areset : IN STD_LOGIC := '0'; + inclk0 : IN STD_LOGIC := '0'; + c0 : OUT STD_LOGIC ; + locked : OUT STD_LOGIC + ); +end component; + +--------- +-- CPU +--------- + +component T65 is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 + Res_n : in std_logic; + Enable : in std_logic; + Clk : in std_logic; + Rdy : in std_logic; + Abort_n : in std_logic; + IRQ_n : in std_logic; + NMI_n : in std_logic; + SO_n : in std_logic; + R_W_n : out std_logic; + Sync : out std_logic; + EF : out std_logic; + MF : out std_logic; + XF : out std_logic; + ML_n : out std_logic; + VP_n : out std_logic; + VDA : out std_logic; + VPA : out std_logic; + A : out std_logic_vector(23 downto 0); + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0) + ); +end component; + +----------------- +-- MC6845 CRTC +----------------- + +component mc6845 is +port ( + CLOCK : in std_logic; + CLKEN : in std_logic; + nRESET : in std_logic; + + -- Bus interface + ENABLE : in std_logic; + R_nW : in std_logic; + RS : in std_logic; + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0); + + -- Display interface + VSYNC : out std_logic; + HSYNC : out std_logic; + DE : out std_logic; + CURSOR : out std_logic; + LPSTB : in std_logic; + + -- Memory interface + MA : out std_logic_vector(13 downto 0); + RA : out std_logic_vector(4 downto 0) + ); +end component; + +------------------------- +-- "VIDPROC" Video ULA +------------------------- + +component vidproc is +port ( + CLOCK : in std_logic; + -- Clock enable qualifies display cycles (interleaved with CPU cycles) + CLKEN : in std_logic; + nRESET : in std_logic; + + -- Clock enable output to CRTC + CLKEN_CRTC : out std_logic; + + -- Bus interface + ENABLE : in std_logic; + A0 : in std_logic; + -- CPU data bus (for register writes) + DI_CPU : in std_logic_vector(7 downto 0); + -- Display RAM data bus (for display data fetch) + DI_RAM : in std_logic_vector(7 downto 0); + + -- Control interface + nINVERT : in std_logic; + DISEN : in std_logic; + CURSOR : in std_logic; + + -- Video in (teletext mode) + R_IN : in std_logic; + G_IN : in std_logic; + B_IN : in std_logic; + + -- Video out + R : out std_logic; + G : out std_logic; + B : out std_logic + ); +end component; + +-------------------------------- +-- SAA5050 Teletext Generator +-------------------------------- + +component saa5050 is +port ( + CLOCK : in std_logic; + -- 6 MHz dot clock enable + CLKEN : in std_logic; + -- Async reset + nRESET : in std_logic; + + -- Character data input (in the bus clock domain) + DI_CLOCK : in std_logic; + DI_CLKEN : in std_logic; + DI : in std_logic_vector(6 downto 0); + + -- Timing inputs + -- General line reset (not used) + GLR : in std_logic; -- /HSYNC + -- Data entry window - high during VSYNC. + -- Resets ROM row counter and drives 'flash' signal + DEW : in std_logic; -- VSYNC + -- Character rounding select - high during even field + CRS : in std_logic; -- FIELD + -- Load output shift register enable - high during active video + LOSE : in std_logic; -- DE + + -- Video out + R : out std_logic; + G : out std_logic; + B : out std_logic; + Y : out std_logic + ); +end component; + +-------------- +-- 6522 VIA +-------------- + +component M6522 is + port ( + + I_RS : in std_logic_vector(3 downto 0); + I_DATA : in std_logic_vector(7 downto 0); + O_DATA : out std_logic_vector(7 downto 0); + O_DATA_OE_L : out std_logic; + + I_RW_L : in std_logic; + I_CS1 : in std_logic; + I_CS2_L : in std_logic; + + O_IRQ_L : out std_logic; -- note, not open drain + -- port a + I_CA1 : in std_logic; + I_CA2 : in std_logic; + O_CA2 : out std_logic; + O_CA2_OE_L : out std_logic; + + I_PA : in std_logic_vector(7 downto 0); + O_PA : out std_logic_vector(7 downto 0); + O_PA_OE_L : out std_logic_vector(7 downto 0); + + -- port b + I_CB1 : in std_logic; + O_CB1 : out std_logic; + O_CB1_OE_L : out std_logic; + + I_CB2 : in std_logic; + O_CB2 : out std_logic; + O_CB2_OE_L : out std_logic; + + I_PB : in std_logic_vector(7 downto 0); + O_PB : out std_logic_vector(7 downto 0); + O_PB_OE_L : out std_logic_vector(7 downto 0); + + -- FIXME: Revisit timing in this component. Does it really need a 4x clock? + I_P2_H : in std_logic; -- high for phase 2 clock ____----__ + RESET_L : in std_logic; + ENA_4 : in std_logic; -- clk enable (4x system clock rate) + CLK : in std_logic + ); +end component; + +----------------------------- +-- PS/2 Keyboard Emulation +----------------------------- + +component keyboard is +port ( + CLOCK : in std_logic; + nRESET : in std_logic; + CLKEN_1MHZ : in std_logic; + + -- PS/2 interface + PS2_CLK : in std_logic; + PS2_DATA : in std_logic; + + -- If 1 then column is incremented automatically at + -- 1 MHz rate + AUTOSCAN : in std_logic; + + COLUMN : in std_logic_vector(3 downto 0); + ROW : in std_logic_vector(2 downto 0); + + -- 1 when currently selected key is down (AUTOSCAN disabled) + KEYPRESS : out std_logic; + -- 1 when any key is down (except row 0) + INT : out std_logic; + -- BREAK key output - 1 when pressed + BREAK_OUT : out std_logic; + + -- DIP switch inputs + DIP_SWITCH : in std_logic_vector(7 downto 0) + ); +end component; + +----------------------------- +-- SN76489 sound generator +----------------------------- + +component sn76489_top is + + generic ( + clock_div_16_g : integer := 1 + ); + port ( + clock_i : in std_logic; + clock_en_i : in std_logic; + res_n_i : in std_logic; + ce_n_i : in std_logic; + we_n_i : in std_logic; + ready_o : out std_logic; + d_i : in std_logic_vector(0 to 7); + aout_o : out signed(0 to 7) + ); + +end component; + +component i2s_intf is +generic( + mclk_rate : positive := 12000000; + sample_rate : positive := 8000; + preamble : positive := 1; -- I2S + word_length : positive := 16 + ); + +port ( + -- 2x MCLK in (e.g. 24 MHz for WM8731 USB mode) + CLK : in std_logic; + nRESET : in std_logic; + + -- Parallel IO + PCM_INL : out std_logic_vector(word_length - 1 downto 0); + PCM_INR : out std_logic_vector(word_length - 1 downto 0); + PCM_OUTL : in std_logic_vector(word_length - 1 downto 0); + PCM_OUTR : in std_logic_vector(word_length - 1 downto 0); + + -- Codec interface (right justified mode) + -- MCLK is generated at half of the CLK input + I2S_MCLK : out std_logic; + -- LRCLK is equal to the sample rate and is synchronous to + -- MCLK. It must be related to MCLK by the oversampling ratio + -- given in the codec datasheet. + I2S_LRCLK : out std_logic; + + -- Data is shifted out on the falling edge of BCLK, sampled + -- on the rising edge. The bit rate is determined such that + -- it is fast enough to fit preamble + word_length bits into + -- each LRCLK half cycle. The last cycle of each word may be + -- stretched to fit to LRCLK. This is OK at least for the + -- WM8731 codec. + -- The first falling edge of each timeslot is always synchronised + -- with the LRCLK edge. + I2S_BCLK : out std_logic; + -- Output bitstream + I2S_DOUT : out std_logic; + -- Input bitstream + I2S_DIN : in std_logic + ); +end component; + +component i2c_loader is +generic ( + -- Address of slave to be loaded + device_address : integer := 16#1a#; + -- Number of retries to allow before stopping + num_retries : integer := 0; + -- Length of clock divider in bits. Resulting bus frequency is + -- CLK/2^(log2_divider + 2) + log2_divider : integer := 6 +); + +port ( + CLK : in std_logic; + nRESET : in std_logic; + + I2C_SCL : inout std_logic; + I2C_SDA : inout std_logic; + + IS_DONE : out std_logic; + IS_ERROR : out std_logic + ); +end component; + +component debugger is +generic ( + -- Set this for a reasonable half flash duration relative to the + -- clock frequency + flash_divider : natural := 24 + ); +port ( + CLOCK : in std_logic; + nRESET : in std_logic; + -- CPU clock enable in + CLKEN_IN : in std_logic; + -- Gated clock enable back out to CPU + CLKEN_OUT : out std_logic; + -- CPU IRQ in + nIRQ_IN : in std_logic; + -- Gated IRQ back out to CPU (no interrupts when single stepping) + nIRQ_OUT : out std_logic; + + -- CPU + A_CPU : in std_logic_vector(15 downto 0); + R_nW : in std_logic; + SYNC : in std_logic; + + -- Aux bus input for display in hex + AUX_BUS : in std_logic_vector(15 downto 0); + + -- Controls + -- RUN or HALT CPU + RUN : in std_logic; + -- Push button to single-step in HALT mode + nSTEP : in std_logic; + -- Push button to cycle display mode + nMODE : in std_logic; + -- Push button to cycle display digit in edit mode + nDIGIT : in std_logic; + -- Push button to cycle digit value in edit mode + nSET : in std_logic; + + -- Output to display + DIGIT3 : out std_logic_vector(6 downto 0); + DIGIT2 : out std_logic_vector(6 downto 0); + DIGIT1 : out std_logic_vector(6 downto 0); + DIGIT0 : out std_logic_vector(6 downto 0); + + LED_BREAKPOINT : out std_logic; + LED_WATCHPOINT : out std_logic + ); +end component; + +------------- +-- Signals +------------- + +-- Master clock - 32 MHz +signal pll_reset : std_logic; +signal pll_locked : std_logic; +signal clock : std_logic; +signal hard_reset_n : std_logic; +signal reset_n : std_logic; + +-- Clock enable counter +-- CPU and video cycles are interleaved. The CPU runs at 2 MHz (every 16th +-- cycle) and the video subsystem is enabled on every odd cycle. +signal clken_counter : unsigned(4 downto 0); +signal cpu_cycle : std_logic; -- Qualifies all 2 MHz cycles +signal cpu_cycle_mask : std_logic; -- Set to mask CPU cycles until 1 MHz cycle is complete +signal cpu_clken : std_logic; -- 2 MHz cycles in which the CPU is enabled +signal cpu_debug_clken : std_logic; -- CPU clken return from hardware debugger +-- IO cycles are out of phase with the CPU +signal vid_clken : std_logic; -- 16 MHz video cycles +signal mhz4_clken : std_logic; -- Used by 6522 +signal mhz2_clken : std_logic; -- Used for latching CPU address for clock stretch +signal mhz1_clken : std_logic; -- 1 MHz bus and associated peripherals, 6522 phase 2 +-- SAA5050 needs a 6 MHz clock enable relative to a 24 MHz clock +signal ttxt_clken_counter : unsigned(1 downto 0); +signal ttxt_clken : std_logic; + +-- Debugger connections +signal debug_irq_in_n : std_logic; +signal debug_aux : std_logic_vector(15 downto 0); + +-- CPU signals +signal cpu_mode : std_logic_vector(1 downto 0); +signal cpu_ready : std_logic; +signal cpu_abort_n : std_logic; +signal cpu_irq_n : std_logic; +signal cpu_nmi_n : std_logic; +signal cpu_so_n : std_logic; +signal cpu_r_nw : std_logic; +signal cpu_sync : std_logic; +signal cpu_ef : std_logic; +signal cpu_mf : std_logic; +signal cpu_xf : std_logic; +signal cpu_ml_n : std_logic; +signal cpu_vp_n : std_logic; +signal cpu_vda : std_logic; +signal cpu_vpa : std_logic; +signal cpu_a : std_logic_vector(23 downto 0); +signal cpu_di : std_logic_vector(7 downto 0); +signal cpu_do : std_logic_vector(7 downto 0); + +-- CRTC signals +signal crtc_clken : std_logic; +signal crtc_do : std_logic_vector(7 downto 0); +signal crtc_vsync : std_logic; +signal crtc_hsync : std_logic; +signal crtc_de : std_logic; +signal crtc_cursor : std_logic; +signal crtc_lpstb : std_logic := '0'; +signal crtc_ma : std_logic_vector(13 downto 0); +signal crtc_ra : std_logic_vector(4 downto 0); + +-- Decoded display address after address translation for hardware +-- scrolling +signal display_a : std_logic_vector(14 downto 0); + +-- "VIDPROC" signals +signal vidproc_invert_n : std_logic; +signal vidproc_disen : std_logic; +signal r_in : std_logic; +signal g_in : std_logic; +signal b_in : std_logic; +signal r_out : std_logic; +signal g_out : std_logic; +signal b_out : std_logic; + +-- SAA5050 signals +signal ttxt_glr : std_logic; +signal ttxt_dew : std_logic; +signal ttxt_crs : std_logic; +signal ttxt_lose : std_logic; +signal ttxt_r : std_logic; +signal ttxt_g : std_logic; +signal ttxt_b : std_logic; +signal ttxt_y : std_logic; + +-- System VIA signals +signal sys_via_do : std_logic_vector(7 downto 0); +signal sys_via_do_oe_n : std_logic; +signal sys_via_irq_n : std_logic; +signal sys_via_ca1_in : std_logic := '0'; +signal sys_via_ca2_in : std_logic := '0'; +signal sys_via_ca2_out : std_logic; +signal sys_via_ca2_oe_n : std_logic; +signal sys_via_pa_in : std_logic_vector(7 downto 0); +signal sys_via_pa_out : std_logic_vector(7 downto 0); +signal sys_via_pa_oe_n : std_logic_vector(7 downto 0); +signal sys_via_cb1_in : std_logic := '0'; +signal sys_via_cb1_out : std_logic; +signal sys_via_cb1_oe_n : std_logic; +signal sys_via_cb2_in : std_logic := '0'; +signal sys_via_cb2_out : std_logic; +signal sys_via_cb2_oe_n : std_logic; +signal sys_via_pb_in : std_logic_vector(7 downto 0); +signal sys_via_pb_out : std_logic_vector(7 downto 0); +signal sys_via_pb_oe_n : std_logic_vector(7 downto 0); + +-- User VIA signals +signal user_via_do : std_logic_vector(7 downto 0); +signal user_via_do_oe_n : std_logic; +signal user_via_irq_n : std_logic; +signal user_via_ca1_in : std_logic := '0'; +signal user_via_ca2_in : std_logic := '0'; +signal user_via_ca2_out : std_logic; +signal user_via_ca2_oe_n : std_logic; +signal user_via_pa_in : std_logic_vector(7 downto 0); +signal user_via_pa_out : std_logic_vector(7 downto 0); +signal user_via_pa_oe_n : std_logic_vector(7 downto 0); +signal user_via_cb1_in : std_logic := '0'; +signal user_via_cb1_out : std_logic; +signal user_via_cb1_oe_n : std_logic; +signal user_via_cb2_in : std_logic := '0'; +signal user_via_cb2_out : std_logic; +signal user_via_cb2_oe_n : std_logic; +signal user_via_pb_in : std_logic_vector(7 downto 0); +signal user_via_pb_out : std_logic_vector(7 downto 0); +signal user_via_pb_oe_n : std_logic_vector(7 downto 0); + +-- IC32 latch on System VIA +signal ic32 : std_logic_vector(7 downto 0); +signal sound_enable_n : std_logic; +signal speech_read_n : std_logic; +signal speech_write_n : std_logic; +signal keyb_enable_n : std_logic; +signal disp_addr_offs : std_logic_vector(1 downto 0); +signal caps_lock_led_n : std_logic; +signal shift_lock_led_n : std_logic; + +-- Keyboard +signal keyb_column : std_logic_vector(3 downto 0); +signal keyb_row : std_logic_vector(2 downto 0); +signal keyb_out : std_logic; +signal keyb_int : std_logic; +signal keyb_break : std_logic; + +-- Sound generator +signal sound_ready : std_logic; +signal sound_di : std_logic_vector(7 downto 0); +signal sound_ao : signed(7 downto 0); +signal pcm_inl : std_logic_vector(15 downto 0); +signal pcm_inr : std_logic_vector(15 downto 0); + +-- Memory enables +signal ram_enable : std_logic; -- 0x0000 +signal rom_enable : std_logic; -- 0x8000 (BASIC/sideways ROMs) +signal mos_enable : std_logic; -- 0xC000 +-- IO region enables +signal io_fred : std_logic; -- 0xFC00 (1 MHz bus) +signal io_jim : std_logic; -- 0xFD00 (1 MHz bus) +signal io_sheila : std_logic; -- 0xFE00 (System peripherals) +-- SHIELA +signal crtc_enable : std_logic; -- 0xFE00-FE07 +signal acia_enable : std_logic; -- 0xFE08-FE0F +signal serproc_enable : std_logic; -- 0xFE10-FE1F +signal vidproc_enable : std_logic; -- 0xFE20-FE2F +signal romsel_enable : std_logic; -- 0xFE30-FE3F +signal sys_via_enable : std_logic; -- 0xFE40-FE5F +signal user_via_enable : std_logic; -- 0xFE60-FE7F +signal fddc_enable : std_logic; -- 0xFE80-FE9F +signal adlc_enable : std_logic; -- 0xFEA0-FEBF (Econet) +signal adc_enable : std_logic; -- 0xFEC0-FEDF +signal tube_enable : std_logic; -- 0xFEE0-FEFF + +-- ROM select latch +signal romsel : std_logic_vector(3 downto 0); + +signal mhz1_enable : std_logic; -- Set for access to any 1 MHz peripheral + +begin + ------------------------- + -- COMPONENT INSTANCES + ------------------------- + + -- 32 MHz master clock + pll: pll32 port map ( + pll_reset, + CLOCK_24(0), + clock, + pll_locked ); + + -- Hardware debugger block (single-step, breakpoints) + debug: debugger port map ( + clock, + hard_reset_n, + cpu_clken, + cpu_debug_clken, + debug_irq_in_n, + cpu_irq_n, + cpu_a(15 downto 0), cpu_r_nw, cpu_sync, + debug_aux, + SW(8), -- RUN + KEY(3), -- STEP + KEY(2), -- MODE + KEY(1), -- DIGIT + KEY(0), -- SET + HEX3, HEX2, HEX1, HEX0, + LEDR(3), -- BREAKPOINT + LEDR(2) -- WATCHPOINT + ); + + -- 6502 CPU + cpu : T65 port map ( + cpu_mode, + reset_n, + cpu_debug_clken, + clock, + cpu_ready, + cpu_abort_n, + cpu_irq_n, + cpu_nmi_n, + cpu_so_n, + cpu_r_nw, + cpu_sync, + cpu_ef, + cpu_mf, + cpu_xf, + cpu_ml_n, + cpu_vp_n, + cpu_vda, + cpu_vpa, + cpu_a, + cpu_di, + cpu_do ); + + crtc : mc6845 port map ( + clock, + crtc_clken, + reset_n, + crtc_enable, + cpu_r_nw, + cpu_a(0), + cpu_do, + crtc_do, + crtc_vsync, + crtc_hsync, + crtc_de, + crtc_cursor, + crtc_lpstb, + crtc_ma, + crtc_ra ); + + video_ula : vidproc port map ( + clock, + vid_clken, + reset_n, + crtc_clken, + vidproc_enable, + cpu_a(0), + cpu_do, + SRAM_DQ(7 downto 0), + vidproc_invert_n, + vidproc_disen, + crtc_cursor, + r_in, g_in, b_in, + r_out, g_out, b_out + ); + + teletext : saa5050 port map ( + CLOCK_24(0), -- This runs at 6 MHz, which we can't derive from the 32 MHz clock + ttxt_clken, + reset_n, + clock, -- Data input is synchronised from the bus clock domain + vid_clken, + SRAM_DQ(6 downto 0), + ttxt_glr, + ttxt_dew, + ttxt_crs, + ttxt_lose, + ttxt_r, ttxt_g, ttxt_b, ttxt_y + ); + + -- System VIA + system_via : m6522 port map ( + cpu_a(3 downto 0), + cpu_do, + sys_via_do, + sys_via_do_oe_n, + cpu_r_nw, + sys_via_enable, + '0', -- nCS2 + sys_via_irq_n, + sys_via_ca1_in, + sys_via_ca2_in, + sys_via_ca2_out, + sys_via_ca2_oe_n, + sys_via_pa_in, + sys_via_pa_out, + sys_via_pa_oe_n, + sys_via_cb1_in, + sys_via_cb1_out, + sys_via_cb1_oe_n, + sys_via_cb2_in, + sys_via_cb2_out, + sys_via_cb2_oe_n, + sys_via_pb_in, + sys_via_pb_out, + sys_via_pb_oe_n, + mhz1_clken, + hard_reset_n, -- System VIA is reset by power on reset only + mhz4_clken, + clock + ); + + -- User VIA + user_via : m6522 port map ( + cpu_a(3 downto 0), + cpu_do, + user_via_do, + user_via_do_oe_n, + cpu_r_nw, + user_via_enable, + '0', -- nCS2 + user_via_irq_n, + user_via_ca1_in, + user_via_ca2_in, + user_via_ca2_out, + user_via_ca2_oe_n, + user_via_pa_in, + user_via_pa_out, + user_via_pa_oe_n, + user_via_cb1_in, + user_via_cb1_out, + user_via_cb1_oe_n, + user_via_cb2_in, + user_via_cb2_out, + user_via_cb2_oe_n, + user_via_pb_in, + user_via_pb_out, + user_via_pb_oe_n, + mhz1_clken, + reset_n, + mhz4_clken, + clock + ); + + -- Keyboard + keyb : keyboard port map ( + clock, hard_reset_n, mhz1_clken, + PS2_CLK, PS2_DAT, + keyb_enable_n, + keyb_column, + keyb_row, + keyb_out, + keyb_int, + keyb_break, + SW(7 downto 0) + ); + + -- Sound generator (and drive logic for I2S codec) + sound : sn76489_top port map ( + clock, mhz4_clken, + reset_n, '0', sound_enable_n, + sound_ready, sound_di, + sound_ao + ); + i2s : i2s_intf port map ( + CLOCK_24(0), reset_n, + pcm_inl, pcm_inr, + std_logic_vector(sound_ao) & "00000000", + std_logic_vector(sound_ao) & "00000000", + AUD_XCK, AUD_DACLRCK, + AUD_BCLK, AUD_DACDAT, AUD_ADCDAT + ); + i2c : i2c_loader + generic map ( + log2_divider => 7 + ) + port map ( + clock, reset_n, + I2C_SCLK, I2C_SDAT, + LEDR(5), -- IS_DONE + LEDR(4) -- IS_ERROR + ); + + -- Asynchronous reset + -- PLL is reset by external reset switch + pll_reset <= not SW(9); + -- Keyboard and System VIA are reset by external reset switch or PLL being out of lock + hard_reset_n <= not (pll_reset or not pll_locked); + -- Rest of system is reset by all of the above plus the keyboard BREAK key + reset_n <= hard_reset_n and not keyb_break; + + -- Clock enable generation - 32 MHz clock split into 32 cycles + -- CPU is on 0 and 16 (but can be masked by 1 MHz bus accesses) + -- Video is on all odd cycles (16 MHz) + -- 1 MHz cycles are on cycle 31 (1 MHz) + vid_clken <= clken_counter(0); -- 1,3,5... + mhz4_clken <= clken_counter(0) and clken_counter(1) and clken_counter(2); -- 7/15/23/31 + mhz2_clken <= mhz4_clken and clken_counter(3); -- 15/31 + mhz1_clken <= mhz2_clken and clken_counter(4); -- 31 + cpu_cycle <= not (clken_counter(0) or clken_counter(1) or clken_counter(2) or clken_counter(3)); -- 0/16 + cpu_clken <= cpu_cycle and not cpu_cycle_mask; + + clk_gen: process(clock,reset_n) + begin + if reset_n = '0' then + clken_counter <= (others => '0'); + elsif rising_edge(clock) then + clken_counter <= clken_counter + 1; + end if; + end process; + + cycle_stretch: process(clock,reset_n) + begin + if reset_n = '0' then + cpu_cycle_mask <= '0'; + elsif rising_edge(clock) and mhz2_clken = '1' then + if mhz1_enable = '1' and cpu_cycle_mask = '0' then + -- Block CPU cycles until 1 MHz cycle has completed + cpu_cycle_mask <= '1'; + end if; + if mhz1_clken = '1' then + -- CPU can run again + -- FIXME: This may not be correct in terms of CPU cycles, but it + -- should work + cpu_cycle_mask <= '0'; + end if; + end if; + end process; + + ttxt_clk_gen: process(CLOCK_24(0),reset_n) + begin + if reset_n = '0' then + ttxt_clken_counter <= (others => '0'); + elsif rising_edge(CLOCK_24(0)) then + ttxt_clken_counter <= ttxt_clken_counter + 1; + end if; + end process; + + -- 6 MHz clock enable for SAA5050 + ttxt_clken <= '1' when ttxt_clken_counter = 0 else '0'; + + -- CPU configuration and fixed signals + cpu_mode <= "00"; -- 6502 + cpu_ready <= '1'; + cpu_abort_n <= '1'; + cpu_nmi_n <= '1'; + cpu_so_n <= '1'; + + -- Address decoding + -- 0x0000 = 32 KB SRAM + -- 0x8000 = 16 KB BASIC/Sideways ROMs + -- 0xC000 = 16 KB MOS ROM + -- + -- IO regions are mapped into a hole in the MOS. There are three regions: + -- 0xFC00 = FRED + -- 0xFD00 = JIM + -- 0xFE00 = SHEILA + ram_enable <= not cpu_a(15); + rom_enable <= cpu_a(15) and not cpu_a(14); + mos_enable <= cpu_a(15) and cpu_a(14) and not (io_fred or io_jim or io_sheila); + io_fred <= '1' when cpu_a(15 downto 8) = "11111100" else '0'; + io_jim <= '1' when cpu_a(15 downto 8) = "11111101" else '0'; + io_sheila <= '1' when cpu_a(15 downto 8) = "11111110" else '0'; + -- The following IO regions are accessed at 1 MHz and hence will stall the + -- CPU accordingly + mhz1_enable <= io_fred or io_jim or + adc_enable or sys_via_enable or user_via_enable or + serproc_enable or acia_enable or crtc_enable; + + -- SHEILA address demux + -- All the system peripherals are mapped into this page as follows: + -- 0xFE00 - 0xFE07 = MC6845 CRTC + -- 0xFE08 - 0xFE0F = MC6850 ACIA (Serial/Tape) + -- 0xFE10 - 0xFE1F = Serial ULA + -- 0xFE20 - 0xFE2F = Video ULA + -- 0xFE30 - 0xFE3F = Paged ROM select latch + -- 0xFE40 - 0xFE5F = System VIA (6522) + -- 0xFE60 - 0xFE7F = User VIA (6522) + -- 0xFE80 - 0xFE9F = 8271 Floppy disc controller + -- 0xFEA0 - 0xFEBF = 68B54 ADLC for Econet + -- 0xFEC0 - 0xFEDF = uPD7002 ADC + -- 0xFEE0 - 0xFEFF = Tube ULA + process(cpu_a,io_sheila) + begin + -- All regions normally de-selected + crtc_enable <= '0'; + acia_enable <= '0'; + serproc_enable <= '0'; + vidproc_enable <= '0'; + romsel_enable <= '0'; + sys_via_enable <= '0'; + user_via_enable <= '0'; + fddc_enable <= '0'; + adlc_enable <= '0'; + adc_enable <= '0'; + tube_enable <= '0'; + + if io_sheila = '1' then + case cpu_a(7 downto 5) is + when "000" => + -- 0xFE00 + if cpu_a(4) = '0' then + if cpu_a(3) = '0' then + -- 0xFE00 + crtc_enable <= '1'; + else + -- 0xFE08 + acia_enable <= '1'; + end if; + else + -- 0xFE10 + serproc_enable <= '1'; + end if; + when "001" => + -- 0xFE20 + if cpu_a(4) = '0' then + -- 0xFE20 + vidproc_enable <= '1'; + else + -- 0xFE30 + romsel_enable <= '1'; + end if; + when "010" => sys_via_enable <= '1'; -- 0xFE40 + when "011" => user_via_enable <= '1'; -- 0xFE60 + when "100" => fddc_enable <= '1'; -- 0xFE80 + when "101" => adlc_enable <= '1'; -- 0xFEA0 + when "110" => adc_enable <= '1'; -- 0xFEC0 + when "111" => tube_enable <= '1'; -- 0xFEE0 + when others => + null; + end case; + end if; + end process; + + -- CPU data bus mux and interrupts + cpu_di <= + SRAM_DQ(7 downto 0) when ram_enable = '1' else + FL_DQ when rom_enable = '1' else + FL_DQ when mos_enable = '1' else + crtc_do when crtc_enable = '1' else + "00000010" when acia_enable = '1' else + sys_via_do when sys_via_enable = '1' else + user_via_do when user_via_enable = '1' else + (others => '0'); -- un-decoded locations are pulled down by RP1 + debug_irq_in_n <= sys_via_irq_n and user_via_irq_n; -- route IRQ through debugger + --cpu_irq_n <= sys_via_irq_n and user_via_irq_n; + + -- ROMs are in external flash and split into 16K slots (since this also suits other + -- computers that might be run on the same board). + -- The first 8 slots are allocated for use here, and the first 4 are decoded as + -- the sideways ROMs. Slot 7 is used for the MOS. + FL_RST_N <= reset_n; + FL_CE_N <= '0'; + FL_OE_N <= '0'; + FL_WE_N <= '1'; + FL_ADDR(21 downto 17) <= ROM_OFFSET(7 downto 3); + FL_ADDR(16 downto 14) <= + "111" when mos_enable = '1' else + "0" & romsel(1 downto 0); + FL_ADDR(13 downto 0) <= cpu_a(13 downto 0); + + -- SRAM bus + SRAM_UB_N <= '1'; + SRAM_LB_N <= '0'; + SRAM_CE_N <= '0'; + SRAM_OE_N <= '0'; + SRAM_DQ(15 downto 8) <= (others => '0'); + + -- Synchronous outputs to SRAM + process(clock,reset_n) + variable ram_write : std_logic; + begin + ram_write := ram_enable and not cpu_r_nw; + + if reset_n = '0' then + SRAM_WE_N <= '1'; + SRAM_DQ(7 downto 0) <= (others => 'Z'); + elsif rising_edge(clock) then + -- Default to inputs + SRAM_DQ(7 downto 0) <= (others => 'Z'); + + -- Register SRAM signals to outputs (clock must be at least 2x CPU clock) + if vid_clken = '1' then + -- Fetch data from previous CPU cycle + SRAM_WE_N <= not ram_write; + SRAM_ADDR <= "00" & cpu_a(15 downto 0); + if ram_write = '1' then + SRAM_DQ(7 downto 0) <= cpu_do; + end if; + else + -- Fetch data from previous display cycle + SRAM_WE_N <= '1'; + SRAM_ADDR <= "000" & display_a; + end if; + end if; + end process; + + -- Address translation logic for calculation of display address + process(crtc_ma,crtc_ra,disp_addr_offs) + variable aa : unsigned(3 downto 0); + begin + if crtc_ma(12) = '0' then + -- No adjustment + aa := unsigned(crtc_ma(11 downto 8)); + else + -- Address adjusted according to screen mode to compensate for + -- wrap at 0x8000. + case disp_addr_offs is + when "00" => + -- Mode 3 - restart at 0x4000 + aa := unsigned(crtc_ma(11 downto 8)) + 8; + when "01" => + -- Mode 6 - restart at 0x6000 + aa := unsigned(crtc_ma(11 downto 8)) + 12; + when "10" => + -- Mode 0,1,2 - restart at 0x3000 + aa := unsigned(crtc_ma(11 downto 8)) + 6; + when "11" => + -- Mode 4,5 - restart at 0x5800 + aa := unsigned(crtc_ma(11 downto 8)) + 11; + when others => + null; + end case; + end if; + + if crtc_ma(13) = '0' then + -- HI RES + display_a <= std_logic_vector(aa(3 downto 0)) & crtc_ma(7 downto 0) & crtc_ra(2 downto 0); + else + -- TTX VDU + display_a <= std_logic(aa(3)) & "1111" & crtc_ma(9 downto 0); + end if; + end process; + + -- VIDPROC + vidproc_invert_n <= '1'; + vidproc_disen <= crtc_de and not crtc_ra(3); -- DISEN is masked off by RA(3) for MODEs 3 and 6 + r_in <= ttxt_r; + g_in <= ttxt_g; + b_in <= ttxt_b; + + -- SAA5050 + ttxt_glr <= not crtc_hsync; + ttxt_dew <= crtc_vsync; + ttxt_crs <= not crtc_ra(0); + ttxt_lose <= crtc_de; + + -- CRTC drives video out (CSYNC on HSYNC output, VSYNC high) + VGA_HS <= not (crtc_hsync xor crtc_vsync); + VGA_VS <= '1'; + VGA_R <= r_out & r_out & r_out & r_out; + VGA_G <= g_out & g_out & g_out & g_out; + VGA_B <= b_out & b_out & b_out & b_out; + + -- Connections to System VIA + -- ADC + sys_via_cb1_in <= '1'; -- /EOC + -- CRTC + sys_via_ca1_in <= crtc_vsync; + sys_via_cb2_in <= crtc_lpstb; + -- Keyboard + sys_via_ca2_in <= keyb_int; + sys_via_pa_in(7) <= keyb_out; + sys_via_pa_in(6 downto 0) <= sys_via_pa_out(6 downto 0); -- Must loop back output pins or keyboard won't work + keyb_column <= sys_via_pa_out(3 downto 0); + keyb_row <= sys_via_pa_out(6 downto 4); + -- Sound + sound_di <= sys_via_pa_out; + -- Others (idle until missing bits implemented) + sys_via_pb_in(7 downto 4) <= (others => '1'); + + -- Connections to User VIA (user port is output on green LEDs) + user_via_ca1_in <= '1'; -- Pulled up + --LEDG <= user_via_pb_out; + + -- MMBEEB + user_via_cb1_in <= user_via_pb_out(1); + SD_SCLK <= user_via_pb_out(1); -- SCLK + SD_MOSI <= user_via_pb_out(0); -- SDO + SD_nCS <= '0'; -- CS + user_via_cb2_in <= SD_MISO; -- SDI + user_via_pb_in <= user_via_pb_out; + + -- ROM select latch + process(clock,reset_n) + begin + if reset_n = '0' then + romsel <= (others => '0'); + elsif rising_edge(clock) then + if romsel_enable = '1' and cpu_r_nw = '0' then + romsel <= cpu_do(3 downto 0); + end if; + end if; + end process; + + -- IC32 latch + sound_enable_n <= ic32(0); + speech_write_n <= ic32(1); + speech_read_n <= ic32(2); + keyb_enable_n <= ic32(3); + disp_addr_offs <= ic32(5 downto 4); + caps_lock_led_n <= ic32(6); + shift_lock_led_n <= ic32(7); + + process(clock,reset_n) + variable bit_num : integer; + begin + bit_num := to_integer(unsigned(sys_via_pb_out(2 downto 0))); + + if reset_n = '0' then + ic32 <= (others => '0'); + elsif rising_edge(clock) then + ic32(bit_num) <= sys_via_pb_out(3); + end if; + end process; + + -- Keyboard LEDs + LEDR(0) <= not caps_lock_led_n; + LEDR(1) <= not shift_lock_led_n; + + ----------------- + -- DEBUG STUFF + ----------------- + + GPIO_0(0) <= not (crtc_hsync xor crtc_vsync); + GPIO_0(1) <= crtc_de; + +end architecture; diff --git a/bbc_micro_de1_tb.vhd b/bbc_micro_de1_tb.vhd index 82012ec..9197958 100644 --- a/bbc_micro_de1_tb.vhd +++ b/bbc_micro_de1_tb.vhd @@ -1,299 +1,299 @@ --- BBC Micro for Altera DE1 --- --- Copyright (c) 2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - -entity bbc_micro_tb is -end entity; - -architecture tb of bbc_micro_tb is -component bbc_micro_de1 is -port ( - -- Clocks - CLOCK_24 : in std_logic_vector(1 downto 0); - CLOCK_27 : in std_logic_vector(1 downto 0); - CLOCK_50 : in std_logic; - EXT_CLOCK : in std_logic; - - -- Switches - SW : in std_logic_vector(9 downto 0); - -- Buttons - KEY : in std_logic_vector(3 downto 0); - - -- 7 segment displays - HEX0 : out std_logic_vector(6 downto 0); - HEX1 : out std_logic_vector(6 downto 0); - HEX2 : out std_logic_vector(6 downto 0); - HEX3 : out std_logic_vector(6 downto 0); - -- Red LEDs - LEDR : out std_logic_vector(9 downto 0); - -- Green LEDs - LEDG : out std_logic_vector(7 downto 0); - - -- VGA - VGA_R : out std_logic_vector(3 downto 0); - VGA_G : out std_logic_vector(3 downto 0); - VGA_B : out std_logic_vector(3 downto 0); - VGA_HS : out std_logic; - VGA_VS : out std_logic; - - -- Serial - UART_RXD : in std_logic; - UART_TXD : out std_logic; - - -- PS/2 Keyboard - PS2_CLK : inout std_logic; - PS2_DAT : inout std_logic; - - -- I2C - I2C_SCLK : inout std_logic; - I2C_SDAT : inout std_logic; - - -- Audio - AUD_XCK : out std_logic; - AUD_BCLK : out std_logic; - AUD_ADCLRCK : out std_logic; - AUD_ADCDAT : in std_logic; - AUD_DACLRCK : out std_logic; - AUD_DACDAT : out std_logic; - - -- SRAM - SRAM_ADDR : out std_logic_vector(17 downto 0); - SRAM_DQ : inout std_logic_vector(15 downto 0); - SRAM_CE_N : out std_logic; - SRAM_OE_N : out std_logic; - SRAM_WE_N : out std_logic; - SRAM_UB_N : out std_logic; - SRAM_LB_N : out std_logic; - - -- SDRAM - DRAM_ADDR : out std_logic_vector(11 downto 0); - DRAM_DQ : inout std_logic_vector(15 downto 0); - DRAM_BA_0 : in std_logic; - DRAM_BA_1 : in std_logic; - DRAM_CAS_N : in std_logic; - DRAM_CKE : in std_logic; - DRAM_CLK : in std_logic; - DRAM_CS_N : in std_logic; - DRAM_LDQM : in std_logic; - DRAM_RAS_N : in std_logic; - DRAM_UDQM : in std_logic; - DRAM_WE_N : in std_logic; - - -- Flash - FL_ADDR : out std_logic_vector(21 downto 0); - FL_DQ : inout std_logic_vector(7 downto 0); - FL_RST_N : in std_logic; - FL_OE_N : in std_logic; - FL_WE_N : in std_logic; - - -- GPIO - GPIO_0 : inout std_logic_vector(35 downto 0); - GPIO_1 : inout std_logic_vector(35 downto 0) - ); -end component; - - -signal clock_24 : std_logic_vector(1 downto 0) := "00"; -signal clock_27 : std_logic_vector(1 downto 0) := "00"; -signal clock_50 : std_logic := '0'; -signal ext_clock : std_logic := '0'; -signal sw : std_logic_vector(9 downto 0); -signal key : std_logic_vector(3 downto 0); -signal hex0 : std_logic_vector(6 downto 0); -signal hex1 : std_logic_vector(6 downto 0); -signal hex2 : std_logic_vector(6 downto 0); -signal hex3 : std_logic_vector(6 downto 0); -signal ledr : std_logic_vector(9 downto 0); -signal ledg : std_logic_vector(7 downto 0); -signal vga_r : std_logic_vector(3 downto 0); -signal vga_g : std_logic_vector(3 downto 0); -signal vga_b : std_logic_vector(3 downto 0); -signal vga_hs : std_logic; -signal vga_vs : std_logic; -signal uart_rxd : std_logic; -signal uart_txd : std_logic; -signal ps2_clk : std_logic; -signal ps2_dat : std_logic; -signal i2c_sclk : std_logic; -signal i2c_sdat : std_logic; -signal aud_xck : std_logic; -signal aud_bclk : std_logic; -signal aud_adclrck : std_logic; -signal aud_adcdat : std_logic; -signal aud_daclrck : std_logic; -signal aud_dacdat : std_logic; -signal sram_addr : std_logic_vector(17 downto 0); -signal sram_dq : std_logic_vector(15 downto 0); -signal sram_ce_n : std_logic; -signal sram_oe_n : std_logic; -signal sram_we_n : std_logic; -signal sram_ub_n : std_logic; -signal sram_lb_n : std_logic; -signal dram_addr : std_logic_vector(11 downto 0); -signal dram_dq : std_logic_vector(15 downto 0); -signal dram_ba_0 : std_logic; -signal dram_ba_1 : std_logic; -signal dram_cas_n : std_logic; -signal dram_cke : std_logic; -signal dram_clk : std_logic; -signal dram_cs_n : std_logic; -signal dram_ldqm : std_logic; -signal dram_ras_n : std_logic; -signal dram_udqm : std_logic; -signal dram_we_n : std_logic; -signal fl_addr : std_logic_vector(21 downto 0); -signal fl_dq : std_logic_vector(7 downto 0); -signal fl_rst_n : std_logic; -signal fl_oe_n : std_logic; -signal fl_we_n : std_logic; -signal gpio_0 : std_logic_vector(35 downto 0); -signal gpio_1 : std_logic_vector(35 downto 0); - -signal n_reset : std_logic := '0'; -signal n_slow : std_logic := '1'; - -type ram_t is array(0 to 65535) of std_logic_vector(15 downto 0); -signal ram : ram_t; -signal ram_a : std_logic_vector(15 downto 0); -begin - - uut: bbc_micro_de1 port map ( - clock_24, - clock_27, - clock_50, - ext_clock, - sw, - key, - hex0, - hex1, - hex2, - hex3, - ledr, - ledg, - vga_r, - vga_g, - vga_b, - vga_hs, - vga_vs, - uart_rxd, - uart_txd, - ps2_clk, - ps2_dat, - i2c_sclk, - i2c_sdat, - aud_xck, - aud_bclk, - aud_adclrck, - aud_adcdat, - aud_daclrck, - aud_dacdat, - sram_addr, - sram_dq, - sram_ce_n, - sram_oe_n, - sram_we_n, - sram_ub_n, - sram_lb_n, - dram_addr, - dram_dq, - dram_ba_0, - dram_ba_1, - dram_cas_n, - dram_cke, - dram_clk, - dram_cs_n, - dram_ldqm, - dram_ras_n, - dram_udqm, - dram_we_n, - fl_addr, - fl_dq, - fl_rst_n, - fl_oe_n, - fl_we_n, - gpio_0, - gpio_1 - ); - - sw <= n_reset & n_slow & "00000101"; - clock_50 <= not clock_50 after 10 ns; - clock_27(0) <= not clock_27(0) after 18.5 ns; - clock_27(1) <= not clock_27(1) after 18.5 ns; - clock_24(0) <= not clock_24(0) after 20.8 ns; - clock_24(1) <= not clock_24(1) after 20.8 ns; - - reset: process - begin - wait for 100 ns; - n_reset <= '1'; - end process; - - sram: process(sram_addr,sram_dq,sram_ce_n,sram_oe_n,sram_we_n,sram_ub_n,sram_lb_n) - begin - if sram_ce_n = '0' then - if sram_oe_n = '0' and sram_we_n = '1' then - if sram_ub_n = '0' then - sram_dq(15 downto 8) <= ram(to_integer(unsigned(sram_addr(15 downto 0))))(15 downto 8); - else - sram_dq(15 downto 8) <= (others => 'Z'); - end if; - if sram_lb_n = '0' then - sram_dq(7 downto 0) <= ram(to_integer(unsigned(sram_addr(15 downto 0))))(7 downto 0); - else - sram_dq(7 downto 0) <= (others => 'Z'); - end if; - else - sram_dq(15 downto 0) <= (others => 'Z'); - if sram_we_n = '0' then - if sram_ub_n = '0' then - ram(to_integer(unsigned(sram_addr(15 downto 0))))(15 downto 8) <= sram_dq(15 downto 8); - end if; - if sram_lb_n = '0' then - ram(to_integer(unsigned(sram_addr(15 downto 0))))(7 downto 0) <= sram_dq(7 downto 0); - end if; - end if; - end if; - else - sram_dq <= (others => 'Z'); - end if; - end process; - - -end architecture; +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity bbc_micro_tb is +end entity; + +architecture tb of bbc_micro_tb is +component bbc_micro_de1 is +port ( + -- Clocks + CLOCK_24 : in std_logic_vector(1 downto 0); + CLOCK_27 : in std_logic_vector(1 downto 0); + CLOCK_50 : in std_logic; + EXT_CLOCK : in std_logic; + + -- Switches + SW : in std_logic_vector(9 downto 0); + -- Buttons + KEY : in std_logic_vector(3 downto 0); + + -- 7 segment displays + HEX0 : out std_logic_vector(6 downto 0); + HEX1 : out std_logic_vector(6 downto 0); + HEX2 : out std_logic_vector(6 downto 0); + HEX3 : out std_logic_vector(6 downto 0); + -- Red LEDs + LEDR : out std_logic_vector(9 downto 0); + -- Green LEDs + LEDG : out std_logic_vector(7 downto 0); + + -- VGA + VGA_R : out std_logic_vector(3 downto 0); + VGA_G : out std_logic_vector(3 downto 0); + VGA_B : out std_logic_vector(3 downto 0); + VGA_HS : out std_logic; + VGA_VS : out std_logic; + + -- Serial + UART_RXD : in std_logic; + UART_TXD : out std_logic; + + -- PS/2 Keyboard + PS2_CLK : inout std_logic; + PS2_DAT : inout std_logic; + + -- I2C + I2C_SCLK : inout std_logic; + I2C_SDAT : inout std_logic; + + -- Audio + AUD_XCK : out std_logic; + AUD_BCLK : out std_logic; + AUD_ADCLRCK : out std_logic; + AUD_ADCDAT : in std_logic; + AUD_DACLRCK : out std_logic; + AUD_DACDAT : out std_logic; + + -- SRAM + SRAM_ADDR : out std_logic_vector(17 downto 0); + SRAM_DQ : inout std_logic_vector(15 downto 0); + SRAM_CE_N : out std_logic; + SRAM_OE_N : out std_logic; + SRAM_WE_N : out std_logic; + SRAM_UB_N : out std_logic; + SRAM_LB_N : out std_logic; + + -- SDRAM + DRAM_ADDR : out std_logic_vector(11 downto 0); + DRAM_DQ : inout std_logic_vector(15 downto 0); + DRAM_BA_0 : in std_logic; + DRAM_BA_1 : in std_logic; + DRAM_CAS_N : in std_logic; + DRAM_CKE : in std_logic; + DRAM_CLK : in std_logic; + DRAM_CS_N : in std_logic; + DRAM_LDQM : in std_logic; + DRAM_RAS_N : in std_logic; + DRAM_UDQM : in std_logic; + DRAM_WE_N : in std_logic; + + -- Flash + FL_ADDR : out std_logic_vector(21 downto 0); + FL_DQ : inout std_logic_vector(7 downto 0); + FL_RST_N : in std_logic; + FL_OE_N : in std_logic; + FL_WE_N : in std_logic; + + -- GPIO + GPIO_0 : inout std_logic_vector(35 downto 0); + GPIO_1 : inout std_logic_vector(35 downto 0) + ); +end component; + + +signal clock_24 : std_logic_vector(1 downto 0) := "00"; +signal clock_27 : std_logic_vector(1 downto 0) := "00"; +signal clock_50 : std_logic := '0'; +signal ext_clock : std_logic := '0'; +signal sw : std_logic_vector(9 downto 0); +signal key : std_logic_vector(3 downto 0); +signal hex0 : std_logic_vector(6 downto 0); +signal hex1 : std_logic_vector(6 downto 0); +signal hex2 : std_logic_vector(6 downto 0); +signal hex3 : std_logic_vector(6 downto 0); +signal ledr : std_logic_vector(9 downto 0); +signal ledg : std_logic_vector(7 downto 0); +signal vga_r : std_logic_vector(3 downto 0); +signal vga_g : std_logic_vector(3 downto 0); +signal vga_b : std_logic_vector(3 downto 0); +signal vga_hs : std_logic; +signal vga_vs : std_logic; +signal uart_rxd : std_logic; +signal uart_txd : std_logic; +signal ps2_clk : std_logic; +signal ps2_dat : std_logic; +signal i2c_sclk : std_logic; +signal i2c_sdat : std_logic; +signal aud_xck : std_logic; +signal aud_bclk : std_logic; +signal aud_adclrck : std_logic; +signal aud_adcdat : std_logic; +signal aud_daclrck : std_logic; +signal aud_dacdat : std_logic; +signal sram_addr : std_logic_vector(17 downto 0); +signal sram_dq : std_logic_vector(15 downto 0); +signal sram_ce_n : std_logic; +signal sram_oe_n : std_logic; +signal sram_we_n : std_logic; +signal sram_ub_n : std_logic; +signal sram_lb_n : std_logic; +signal dram_addr : std_logic_vector(11 downto 0); +signal dram_dq : std_logic_vector(15 downto 0); +signal dram_ba_0 : std_logic; +signal dram_ba_1 : std_logic; +signal dram_cas_n : std_logic; +signal dram_cke : std_logic; +signal dram_clk : std_logic; +signal dram_cs_n : std_logic; +signal dram_ldqm : std_logic; +signal dram_ras_n : std_logic; +signal dram_udqm : std_logic; +signal dram_we_n : std_logic; +signal fl_addr : std_logic_vector(21 downto 0); +signal fl_dq : std_logic_vector(7 downto 0); +signal fl_rst_n : std_logic; +signal fl_oe_n : std_logic; +signal fl_we_n : std_logic; +signal gpio_0 : std_logic_vector(35 downto 0); +signal gpio_1 : std_logic_vector(35 downto 0); + +signal n_reset : std_logic := '0'; +signal n_slow : std_logic := '1'; + +type ram_t is array(0 to 65535) of std_logic_vector(15 downto 0); +signal ram : ram_t; +signal ram_a : std_logic_vector(15 downto 0); +begin + + uut: bbc_micro_de1 port map ( + clock_24, + clock_27, + clock_50, + ext_clock, + sw, + key, + hex0, + hex1, + hex2, + hex3, + ledr, + ledg, + vga_r, + vga_g, + vga_b, + vga_hs, + vga_vs, + uart_rxd, + uart_txd, + ps2_clk, + ps2_dat, + i2c_sclk, + i2c_sdat, + aud_xck, + aud_bclk, + aud_adclrck, + aud_adcdat, + aud_daclrck, + aud_dacdat, + sram_addr, + sram_dq, + sram_ce_n, + sram_oe_n, + sram_we_n, + sram_ub_n, + sram_lb_n, + dram_addr, + dram_dq, + dram_ba_0, + dram_ba_1, + dram_cas_n, + dram_cke, + dram_clk, + dram_cs_n, + dram_ldqm, + dram_ras_n, + dram_udqm, + dram_we_n, + fl_addr, + fl_dq, + fl_rst_n, + fl_oe_n, + fl_we_n, + gpio_0, + gpio_1 + ); + + sw <= n_reset & n_slow & "00000101"; + clock_50 <= not clock_50 after 10 ns; + clock_27(0) <= not clock_27(0) after 18.5 ns; + clock_27(1) <= not clock_27(1) after 18.5 ns; + clock_24(0) <= not clock_24(0) after 20.8 ns; + clock_24(1) <= not clock_24(1) after 20.8 ns; + + reset: process + begin + wait for 100 ns; + n_reset <= '1'; + end process; + + sram: process(sram_addr,sram_dq,sram_ce_n,sram_oe_n,sram_we_n,sram_ub_n,sram_lb_n) + begin + if sram_ce_n = '0' then + if sram_oe_n = '0' and sram_we_n = '1' then + if sram_ub_n = '0' then + sram_dq(15 downto 8) <= ram(to_integer(unsigned(sram_addr(15 downto 0))))(15 downto 8); + else + sram_dq(15 downto 8) <= (others => 'Z'); + end if; + if sram_lb_n = '0' then + sram_dq(7 downto 0) <= ram(to_integer(unsigned(sram_addr(15 downto 0))))(7 downto 0); + else + sram_dq(7 downto 0) <= (others => 'Z'); + end if; + else + sram_dq(15 downto 0) <= (others => 'Z'); + if sram_we_n = '0' then + if sram_ub_n = '0' then + ram(to_integer(unsigned(sram_addr(15 downto 0))))(15 downto 8) <= sram_dq(15 downto 8); + end if; + if sram_lb_n = '0' then + ram(to_integer(unsigned(sram_addr(15 downto 0))))(7 downto 0) <= sram_dq(7 downto 0); + end if; + end if; + end if; + else + sram_dq <= (others => 'Z'); + end if; + end process; + + +end architecture; diff --git a/debugger.vhd b/debugger.vhd index 1d78bd5..a7a9d7d 100644 --- a/debugger.vhd +++ b/debugger.vhd @@ -1,300 +1,300 @@ --- BBC Micro for Altera DE1 --- --- Copyright (c) 2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- --- General purpose hardware debugger --- --- (C) 2011 Mike Stirling --- - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - -entity debugger is -generic ( - -- Set this for a reasonable half flash duration relative to the - -- clock frequency - flash_divider : natural := 24 - ); -port ( - CLOCK : in std_logic; - nRESET : in std_logic; - -- CPU clock enable in - CLKEN_IN : in std_logic; - -- Gated clock enable back out to CPU - CLKEN_OUT : out std_logic; - -- CPU IRQ in - nIRQ_IN : in std_logic; - -- Gated IRQ back out to CPU (no interrupts when single stepping) - nIRQ_OUT : out std_logic; - - -- CPU - A_CPU : in std_logic_vector(15 downto 0); - R_nW : in std_logic; - SYNC : in std_logic; - - -- Aux bus input for display in hex - AUX_BUS : in std_logic_vector(15 downto 0); - - -- Controls - -- RUN or HALT CPU - RUN : in std_logic; - -- Push button to single-step in HALT mode - nSTEP : in std_logic; - -- Push button to cycle display mode - nMODE : in std_logic; - -- Push button to cycle display digit in edit mode - nDIGIT : in std_logic; - -- Push button to cycle digit value in edit mode - nSET : in std_logic; - - -- Output to display - DIGIT3 : out std_logic_vector(6 downto 0); - DIGIT2 : out std_logic_vector(6 downto 0); - DIGIT1 : out std_logic_vector(6 downto 0); - DIGIT0 : out std_logic_vector(6 downto 0); - - LED_BREAKPOINT : out std_logic; - LED_WATCHPOINT : out std_logic - ); -end entity; - -architecture rtl of debugger is - -component seg7 is -port ( - D : in std_logic_vector(3 downto 0); - Q : out std_logic_vector(6 downto 0) -); -end component; - --- Current display mode -type mode_t is (modeAddress,modeBreak,modeWatch,modeAux); -signal mode : mode_t; --- Current edit digit -signal digit : unsigned(1 downto 0); --- For flashing selected digit -signal counter : unsigned(flash_divider-1 downto 0); -signal flash : std_logic; --- Selected breakpoint address (stop on instruction fetch) -signal breakpoint : std_logic_vector(15 downto 0); --- Selected watchpoint address (stop on write) -signal watchpoint : std_logic_vector(15 downto 0); --- Address of last instruction fetch -signal instr_addr : std_logic_vector(15 downto 0); --- Break flags -signal halt : std_logic; --- Set when a request to resume has been received but before --- the CPU has run -signal resuming : std_logic; - --- Display interface -signal a_display : std_logic_vector(15 downto 0); -signal d3_display : std_logic_vector(6 downto 0); -signal d2_display : std_logic_vector(6 downto 0); -signal d1_display : std_logic_vector(6 downto 0); -signal d0_display : std_logic_vector(6 downto 0); - --- Registered button inputs -signal r_step_n : std_logic; -signal r_mode_n : std_logic; -signal r_digit_n : std_logic; -signal r_set_n : std_logic; - -begin - -- Mask CPU clock enable - CLKEN_OUT <= CLKEN_IN and not halt; - -- Mask interrupt - nIRQ_OUT <= nIRQ_IN or not RUN; - - -- Route selected address to display - a_display <= instr_addr when mode = modeAddress else - breakpoint when mode = modeBreak else - watchpoint when mode = modeWatch else - AUX_BUS when mode = modeAux else - (others => '0'); - - -- Generate display digits from binary - d3 : seg7 port map (a_display(15 downto 12),d3_display); - d2 : seg7 port map (a_display(11 downto 8),d2_display); - d1 : seg7 port map (a_display(7 downto 4),d1_display); - d0 : seg7 port map (a_display(3 downto 0),d0_display); - - -- Flash selected digit in edit modes - DIGIT3 <= d3_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "11") else "1111111"; - DIGIT2 <= d2_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "10") else "1111111"; - DIGIT1 <= d1_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "01") else "1111111"; - DIGIT0 <= d0_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "00") else "1111111"; - - -- Show mode on LEDs - LED_BREAKPOINT <= '1' when mode = modeBreak or mode = modeAux else '0'; - LED_WATCHPOINT <= '1' when mode = modeWatch or mode = modeAux else '0'; - - -- Flash counter - process(CLOCK,nRESET) - begin - if nRESET = '0' then - counter <= (others => '0'); - flash <= '0'; - elsif rising_edge(CLOCK) then - counter <= counter + 1; - if counter = 0 then - flash <= not flash; - end if; - end if; - end process; - - -- Register buttons, select input mode and digit - process(CLOCK,nRESET) - begin - if nRESET = '0' then - r_mode_n <= '1'; - r_digit_n <= '1'; - r_set_n <= '1'; - mode <= modeAddress; - digit <= (others => '0'); - elsif rising_edge(CLOCK) then - -- Register buttons - r_mode_n <= nMODE; - r_digit_n <= nDIGIT; - r_set_n <= nSET; - - if r_mode_n = '1' and nMODE = '0' then - -- Increment mode - if mode = modeAddress then - mode <= modeBreak; - elsif mode = modeBreak then - mode <= modeWatch; - elsif mode = modeWatch then - mode <= modeAux; - else - mode <= modeAddress; - end if; - end if; - if r_digit_n = '1' and nDIGIT = '0' then - -- Increment digit - digit <= digit + 1; - end if; - end if; - end process; - - -- Set watchpoint address - process(CLOCK,nRESET) - begin - if nRESET = '0' then - watchpoint <= (others => '1'); - elsif rising_edge(CLOCK) and mode = modeWatch then - if r_set_n = '1' and nSET = '0' then - -- Increment selected digit on each button press - case digit is - when "00" => watchpoint(3 downto 0) <= std_logic_vector(unsigned(watchpoint(3 downto 0)) + 1); - when "01" => watchpoint(7 downto 4) <= std_logic_vector(unsigned(watchpoint(7 downto 4)) + 1); - when "10" => watchpoint(11 downto 8) <= std_logic_vector(unsigned(watchpoint(11 downto 8)) + 1); - when "11" => watchpoint(15 downto 12) <= std_logic_vector(unsigned(watchpoint(15 downto 12)) + 1); - when others => null; - end case; - end if; - end if; - end process; - - -- Set breakpoint address - process(CLOCK,nRESET) - begin - if nRESET = '0' then - breakpoint <= (others => '1'); - elsif rising_edge(CLOCK) and mode = modeBreak then - if r_set_n = '1' and nSET = '0' then - -- Increment selected digit on each button press - case digit is - when "00" => breakpoint(3 downto 0) <= std_logic_vector(unsigned(breakpoint(3 downto 0)) + 1); - when "01" => breakpoint(7 downto 4) <= std_logic_vector(unsigned(breakpoint(7 downto 4)) + 1); - when "10" => breakpoint(11 downto 8) <= std_logic_vector(unsigned(breakpoint(11 downto 8)) + 1); - when "11" => breakpoint(15 downto 12) <= std_logic_vector(unsigned(breakpoint(15 downto 12)) + 1); - - when others => null; - end case; - end if; - end if; - end process; - - -- CPU control logic - process(CLOCK,nRESET) - begin - if nRESET = '0' then - r_step_n <= '1'; - halt <= '0'; - resuming <= '0'; - instr_addr <= (others => '0'); - elsif rising_edge(CLOCK) then - -- Register single-step button - r_step_n <= nSTEP; - - -- Once the CPU has run we can trigger a new halt - if CLKEN_IN = '1' then - resuming <= '0'; - end if; - - if SYNC = '1' then - -- Latch address of instruction fetch - instr_addr <= A_CPU; - end if; - - -- Check for halt conditions if we are not resuming from a previous halt - if resuming = '0' then - if RUN = '0' and SYNC = '1' then - -- If not in RUN mode then halt on any instruction fetch - -- (single-step) - halt <= '1'; - end if; - if A_CPU = breakpoint and SYNC = '1' then - -- Halt CPU when instruction fetched from breakpoint address - halt <= '1'; - end if; - if A_CPU = watchpoint and SYNC = '0' and R_nW = '0' then - -- Halt CPU when data write to watchpoint address - halt <= '1'; - end if; - end if; - - -- Resume or single step when user presses "STEP" button - if r_step_n = '1' and nSTEP = '0' then - resuming <= '1'; - halt <= '0'; - end if; - end if; - end process; -end architecture; +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- +-- General purpose hardware debugger +-- +-- (C) 2011 Mike Stirling +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity debugger is +generic ( + -- Set this for a reasonable half flash duration relative to the + -- clock frequency + flash_divider : natural := 24 + ); +port ( + CLOCK : in std_logic; + nRESET : in std_logic; + -- CPU clock enable in + CLKEN_IN : in std_logic; + -- Gated clock enable back out to CPU + CLKEN_OUT : out std_logic; + -- CPU IRQ in + nIRQ_IN : in std_logic; + -- Gated IRQ back out to CPU (no interrupts when single stepping) + nIRQ_OUT : out std_logic; + + -- CPU + A_CPU : in std_logic_vector(15 downto 0); + R_nW : in std_logic; + SYNC : in std_logic; + + -- Aux bus input for display in hex + AUX_BUS : in std_logic_vector(15 downto 0); + + -- Controls + -- RUN or HALT CPU + RUN : in std_logic; + -- Push button to single-step in HALT mode + nSTEP : in std_logic; + -- Push button to cycle display mode + nMODE : in std_logic; + -- Push button to cycle display digit in edit mode + nDIGIT : in std_logic; + -- Push button to cycle digit value in edit mode + nSET : in std_logic; + + -- Output to display + DIGIT3 : out std_logic_vector(6 downto 0); + DIGIT2 : out std_logic_vector(6 downto 0); + DIGIT1 : out std_logic_vector(6 downto 0); + DIGIT0 : out std_logic_vector(6 downto 0); + + LED_BREAKPOINT : out std_logic; + LED_WATCHPOINT : out std_logic + ); +end entity; + +architecture rtl of debugger is + +component seg7 is +port ( + D : in std_logic_vector(3 downto 0); + Q : out std_logic_vector(6 downto 0) +); +end component; + +-- Current display mode +type mode_t is (modeAddress,modeBreak,modeWatch,modeAux); +signal mode : mode_t; +-- Current edit digit +signal digit : unsigned(1 downto 0); +-- For flashing selected digit +signal counter : unsigned(flash_divider-1 downto 0); +signal flash : std_logic; +-- Selected breakpoint address (stop on instruction fetch) +signal breakpoint : std_logic_vector(15 downto 0); +-- Selected watchpoint address (stop on write) +signal watchpoint : std_logic_vector(15 downto 0); +-- Address of last instruction fetch +signal instr_addr : std_logic_vector(15 downto 0); +-- Break flags +signal halt : std_logic; +-- Set when a request to resume has been received but before +-- the CPU has run +signal resuming : std_logic; + +-- Display interface +signal a_display : std_logic_vector(15 downto 0); +signal d3_display : std_logic_vector(6 downto 0); +signal d2_display : std_logic_vector(6 downto 0); +signal d1_display : std_logic_vector(6 downto 0); +signal d0_display : std_logic_vector(6 downto 0); + +-- Registered button inputs +signal r_step_n : std_logic; +signal r_mode_n : std_logic; +signal r_digit_n : std_logic; +signal r_set_n : std_logic; + +begin + -- Mask CPU clock enable + CLKEN_OUT <= CLKEN_IN and not halt; + -- Mask interrupt + nIRQ_OUT <= nIRQ_IN or not RUN; + + -- Route selected address to display + a_display <= instr_addr when mode = modeAddress else + breakpoint when mode = modeBreak else + watchpoint when mode = modeWatch else + AUX_BUS when mode = modeAux else + (others => '0'); + + -- Generate display digits from binary + d3 : seg7 port map (a_display(15 downto 12),d3_display); + d2 : seg7 port map (a_display(11 downto 8),d2_display); + d1 : seg7 port map (a_display(7 downto 4),d1_display); + d0 : seg7 port map (a_display(3 downto 0),d0_display); + + -- Flash selected digit in edit modes + DIGIT3 <= d3_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "11") else "1111111"; + DIGIT2 <= d2_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "10") else "1111111"; + DIGIT1 <= d1_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "01") else "1111111"; + DIGIT0 <= d0_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "00") else "1111111"; + + -- Show mode on LEDs + LED_BREAKPOINT <= '1' when mode = modeBreak or mode = modeAux else '0'; + LED_WATCHPOINT <= '1' when mode = modeWatch or mode = modeAux else '0'; + + -- Flash counter + process(CLOCK,nRESET) + begin + if nRESET = '0' then + counter <= (others => '0'); + flash <= '0'; + elsif rising_edge(CLOCK) then + counter <= counter + 1; + if counter = 0 then + flash <= not flash; + end if; + end if; + end process; + + -- Register buttons, select input mode and digit + process(CLOCK,nRESET) + begin + if nRESET = '0' then + r_mode_n <= '1'; + r_digit_n <= '1'; + r_set_n <= '1'; + mode <= modeAddress; + digit <= (others => '0'); + elsif rising_edge(CLOCK) then + -- Register buttons + r_mode_n <= nMODE; + r_digit_n <= nDIGIT; + r_set_n <= nSET; + + if r_mode_n = '1' and nMODE = '0' then + -- Increment mode + if mode = modeAddress then + mode <= modeBreak; + elsif mode = modeBreak then + mode <= modeWatch; + elsif mode = modeWatch then + mode <= modeAux; + else + mode <= modeAddress; + end if; + end if; + if r_digit_n = '1' and nDIGIT = '0' then + -- Increment digit + digit <= digit + 1; + end if; + end if; + end process; + + -- Set watchpoint address + process(CLOCK,nRESET) + begin + if nRESET = '0' then + watchpoint <= (others => '1'); + elsif rising_edge(CLOCK) and mode = modeWatch then + if r_set_n = '1' and nSET = '0' then + -- Increment selected digit on each button press + case digit is + when "00" => watchpoint(3 downto 0) <= std_logic_vector(unsigned(watchpoint(3 downto 0)) + 1); + when "01" => watchpoint(7 downto 4) <= std_logic_vector(unsigned(watchpoint(7 downto 4)) + 1); + when "10" => watchpoint(11 downto 8) <= std_logic_vector(unsigned(watchpoint(11 downto 8)) + 1); + when "11" => watchpoint(15 downto 12) <= std_logic_vector(unsigned(watchpoint(15 downto 12)) + 1); + when others => null; + end case; + end if; + end if; + end process; + + -- Set breakpoint address + process(CLOCK,nRESET) + begin + if nRESET = '0' then + breakpoint <= (others => '1'); + elsif rising_edge(CLOCK) and mode = modeBreak then + if r_set_n = '1' and nSET = '0' then + -- Increment selected digit on each button press + case digit is + when "00" => breakpoint(3 downto 0) <= std_logic_vector(unsigned(breakpoint(3 downto 0)) + 1); + when "01" => breakpoint(7 downto 4) <= std_logic_vector(unsigned(breakpoint(7 downto 4)) + 1); + when "10" => breakpoint(11 downto 8) <= std_logic_vector(unsigned(breakpoint(11 downto 8)) + 1); + when "11" => breakpoint(15 downto 12) <= std_logic_vector(unsigned(breakpoint(15 downto 12)) + 1); + + when others => null; + end case; + end if; + end if; + end process; + + -- CPU control logic + process(CLOCK,nRESET) + begin + if nRESET = '0' then + r_step_n <= '1'; + halt <= '0'; + resuming <= '0'; + instr_addr <= (others => '0'); + elsif rising_edge(CLOCK) then + -- Register single-step button + r_step_n <= nSTEP; + + -- Once the CPU has run we can trigger a new halt + if CLKEN_IN = '1' then + resuming <= '0'; + end if; + + if SYNC = '1' then + -- Latch address of instruction fetch + instr_addr <= A_CPU; + end if; + + -- Check for halt conditions if we are not resuming from a previous halt + if resuming = '0' then + if RUN = '0' and SYNC = '1' then + -- If not in RUN mode then halt on any instruction fetch + -- (single-step) + halt <= '1'; + end if; + if A_CPU = breakpoint and SYNC = '1' then + -- Halt CPU when instruction fetched from breakpoint address + halt <= '1'; + end if; + if A_CPU = watchpoint and SYNC = '0' and R_nW = '0' then + -- Halt CPU when data write to watchpoint address + halt <= '1'; + end if; + end if; + + -- Resume or single step when user presses "STEP" button + if r_step_n = '1' and nSTEP = '0' then + resuming <= '1'; + halt <= '0'; + end if; + end if; + end process; +end architecture; diff --git a/i2c_loader.vhd b/i2c_loader.vhd index 35da643..61bdd22 100644 --- a/i2c_loader.vhd +++ b/i2c_loader.vhd @@ -1,304 +1,304 @@ --- ZX Spectrum for Altera DE1 --- --- Copyright (c) 2009-2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.STD_LOGIC_ARITH.ALL; -use IEEE.STD_LOGIC_UNSIGNED.ALL; -use IEEE.STD_LOGIC_MISC.ALL; -- for AND_REDUCE -use IEEE.NUMERIC_STD.ALL; - -entity i2c_loader is -generic ( - -- Address of slave to be loaded - device_address : integer := 16#1a#; - -- Number of retries to allow before stopping - num_retries : integer := 0; - -- Length of clock divider in bits. Resulting bus frequency is - -- CLK/2^(log2_divider + 2) - log2_divider : integer := 6 -); - -port ( - CLK : in std_logic; - nRESET : in std_logic; - - I2C_SCL : inout std_logic; - I2C_SDA : inout std_logic; - - IS_DONE : out std_logic; - IS_ERROR : out std_logic - ); -end i2c_loader; - -architecture i2c_loader_arch of i2c_loader is -type regs is array(0 to 19) of std_logic_vector(7 downto 0); -constant init_regs : regs := ( - -- Left line in, 0dB, unmute - X"00", X"17", - -- Right line in, 0dB, unmute - X"02", X"17", - -- Left headphone out, 0dB - X"04", X"79", - -- Right headphone out, 0dB - X"06", X"79", - -- Audio path, DAC enabled, Line in, Bypass off, mic unmuted - X"08", X"10", - -- Digital path, Unmute, HP filter enabled - X"0A", X"00", - -- Power down mic, clkout and xtal osc - X"0C", X"62", - -- Format 16-bit I2S, no bit inversion or phase changes - X"0E", X"02", - -- Sampling control, 8 kHz USB mode (MCLK = 250fs * 6) - X"10", X"0D", - -- Activate - X"12", X"01" - ); --- Number of bursts (i.e. total number of registers) -constant burst_length : positive := 2; --- Number of bytes to transfer per burst -constant num_bursts : positive := (init_regs'length / burst_length); - -type state_t is (Idle, Start, Data, Ack, Stop, Pause, Done); -signal state : state_t; -signal phase : std_logic_vector(1 downto 0); -subtype nbit_t is integer range 0 to 7; -signal nbit : nbit_t; -subtype nbyte_t is integer range 0 to burst_length; -- +1 for address byte -signal nbyte : nbyte_t; -subtype thisbyte_t is integer range 0 to init_regs'length; -- +1 for "done" -signal thisbyte : thisbyte_t; -subtype retries_t is integer range 0 to num_retries; -signal retries : retries_t; - -signal clken : std_logic; -signal divider : std_logic_vector(log2_divider-1 downto 0); -signal shiftreg : std_logic_vector(7 downto 0); -signal scl_out : std_logic; -signal sda_out : std_logic; -signal nak : std_logic; -begin - -- Create open-drain outputs for I2C bus - I2C_SCL <= '0' when scl_out = '0' else 'Z'; - I2C_SDA <= '0' when sda_out = '0' else 'Z'; - -- Status outputs are driven both ways - IS_DONE <= '1' when state = Done else '0'; - IS_ERROR <= nak; - - -- Generate clock enable for desired bus speed - clken <= AND_REDUCE(divider); - process(nRESET,CLK) - begin - if nRESET = '0' then - divider <= (others => '0'); - elsif falling_edge(CLK) then - divider <= divider + '1'; - end if; - end process; - - -- The I2C loader process - process(nRESET,CLK) - begin - if nRESET = '0' then - scl_out <= '1'; - sda_out <= '1'; - state <= Idle; - phase <= "00"; - nbit <= 0; - nbyte <= 0; - thisbyte <= 0; - shiftreg <= (others => '0'); - nak <= '0'; -- No error - retries <= num_retries; - elsif rising_edge(CLK) and clken = '1' then - -- Next phase by default - phase <= phase + 1; - - -- STATE: IDLE - if state = Idle then - -- Start loading the device registers straight away - -- A 'GO' bit could be polled here if required - state <= Start; - phase <= "00"; - scl_out <= '1'; - sda_out <= '1'; - - -- STATE: START - elsif state = Start then - -- Generate START condition - case phase is - when "00" => - -- Drop SDA first - sda_out <= '0'; - when "10" => - -- Then drop SCL - scl_out <= '0'; - when "11" => - -- Advance to next state - -- Shift register loaded with device slave address - state <= Data; - nbit <= 7; - shiftreg <= std_logic_vector(to_unsigned(device_address,7)) & '0'; -- writing - nbyte <= burst_length; - when others => - null; - end case; - - -- STATE: DATA - elsif state = Data then - -- Generate data - case phase is - when "00" => - -- Drop SCL - scl_out <= '0'; - when "01" => - -- Output data and shift (MSb first) - sda_out <= shiftreg(7); - shiftreg <= shiftreg(6 downto 0) & '0'; - when "10" => - -- Raise SCL - scl_out <= '1'; - when "11" => - -- Next bit or advance to next state when done - if nbit = 0 then - state <= Ack; - else - nbit <= nbit - 1; - end if; - when others => - null; - end case; - - -- STATE: ACK - elsif state = Ack then - -- Generate ACK clock and check for error condition - case phase is - when "00" => - -- Drop SCL - scl_out <= '0'; - when "01" => - -- Float data - sda_out <= '1'; - when "10" => - -- Sample ack bit - nak <= I2C_SDA; - if I2C_SDA = '1' then - -- Error - nbyte <= 0; -- Close this burst and skip remaining registers - thisbyte <= init_regs'length; - else - -- Hold ACK to avoid spurious stops - this seems to fix a - -- problem with the Wolfson codec which releases the ACK - -- right on the falling edge of the clock pulse. It looks like - -- the device interprets this is a STOP condition and then fails - -- to acknowledge the next byte. We can avoid this by holding the - -- ACK condition for a little longer. - sda_out <= '0'; - end if; - -- Raise SCL - scl_out <= '1'; - when "11" => - -- Advance to next state - if nbyte = 0 then - -- No more bytes in this burst - generate a STOP - state <= Stop; - else - -- Generate next byte - state <= Data; - nbit <= 7; - shiftreg <= init_regs(thisbyte); - nbyte <= nbyte - 1; - thisbyte <= thisbyte + 1; - end if; - when others => - null; - end case; - - -- STATE: STOP - elsif state = Stop then - -- Generate STOP condition - case phase is - when "00" => - -- Drop SCL first - scl_out <= '0'; - when "01" => - -- Drop SDA - sda_out <= '0'; - when "10" => - -- Raise SCL - scl_out <= '1'; - when "11" => - if thisbyte = init_regs'length then - -- All registers done, advance to finished state. This will - -- bring SDA high while SCL is still high, completing the STOP - -- condition - state <= Done; - else - -- Load the next register after a short delay - state <= Pause; - end if; - when others => - null; - end case; - - -- STATE: PAUSE - elsif state = Pause then - -- Delay for one cycle of 'phase' then start the next burst - scl_out <= '1'; - sda_out <= '1'; - if phase = "11" then - state <= Start; - end if; - - -- STATE: DONE - else - -- Finished - scl_out <= '1'; - sda_out <= '1'; - - if nak = '1' and retries > 0 then - -- We can retry in the event of a NAK in case the - -- slave got out of sync for some reason - retries <= retries - 1; - state <= Idle; - end if; - end if; - end if; - end process; -end i2c_loader_arch; - +-- ZX Spectrum for Altera DE1 +-- +-- Copyright (c) 2009-2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.STD_LOGIC_ARITH.ALL; +use IEEE.STD_LOGIC_UNSIGNED.ALL; +use IEEE.STD_LOGIC_MISC.ALL; -- for AND_REDUCE +use IEEE.NUMERIC_STD.ALL; + +entity i2c_loader is +generic ( + -- Address of slave to be loaded + device_address : integer := 16#1a#; + -- Number of retries to allow before stopping + num_retries : integer := 0; + -- Length of clock divider in bits. Resulting bus frequency is + -- CLK/2^(log2_divider + 2) + log2_divider : integer := 6 +); + +port ( + CLK : in std_logic; + nRESET : in std_logic; + + I2C_SCL : inout std_logic; + I2C_SDA : inout std_logic; + + IS_DONE : out std_logic; + IS_ERROR : out std_logic + ); +end i2c_loader; + +architecture i2c_loader_arch of i2c_loader is +type regs is array(0 to 19) of std_logic_vector(7 downto 0); +constant init_regs : regs := ( + -- Left line in, 0dB, unmute + X"00", X"17", + -- Right line in, 0dB, unmute + X"02", X"17", + -- Left headphone out, 0dB + X"04", X"79", + -- Right headphone out, 0dB + X"06", X"79", + -- Audio path, DAC enabled, Line in, Bypass off, mic unmuted + X"08", X"10", + -- Digital path, Unmute, HP filter enabled + X"0A", X"00", + -- Power down mic, clkout and xtal osc + X"0C", X"62", + -- Format 16-bit I2S, no bit inversion or phase changes + X"0E", X"02", + -- Sampling control, 8 kHz USB mode (MCLK = 250fs * 6) + X"10", X"0D", + -- Activate + X"12", X"01" + ); +-- Number of bursts (i.e. total number of registers) +constant burst_length : positive := 2; +-- Number of bytes to transfer per burst +constant num_bursts : positive := (init_regs'length / burst_length); + +type state_t is (Idle, Start, Data, Ack, Stop, Pause, Done); +signal state : state_t; +signal phase : std_logic_vector(1 downto 0); +subtype nbit_t is integer range 0 to 7; +signal nbit : nbit_t; +subtype nbyte_t is integer range 0 to burst_length; -- +1 for address byte +signal nbyte : nbyte_t; +subtype thisbyte_t is integer range 0 to init_regs'length; -- +1 for "done" +signal thisbyte : thisbyte_t; +subtype retries_t is integer range 0 to num_retries; +signal retries : retries_t; + +signal clken : std_logic; +signal divider : std_logic_vector(log2_divider-1 downto 0); +signal shiftreg : std_logic_vector(7 downto 0); +signal scl_out : std_logic; +signal sda_out : std_logic; +signal nak : std_logic; +begin + -- Create open-drain outputs for I2C bus + I2C_SCL <= '0' when scl_out = '0' else 'Z'; + I2C_SDA <= '0' when sda_out = '0' else 'Z'; + -- Status outputs are driven both ways + IS_DONE <= '1' when state = Done else '0'; + IS_ERROR <= nak; + + -- Generate clock enable for desired bus speed + clken <= AND_REDUCE(divider); + process(nRESET,CLK) + begin + if nRESET = '0' then + divider <= (others => '0'); + elsif falling_edge(CLK) then + divider <= divider + '1'; + end if; + end process; + + -- The I2C loader process + process(nRESET,CLK) + begin + if nRESET = '0' then + scl_out <= '1'; + sda_out <= '1'; + state <= Idle; + phase <= "00"; + nbit <= 0; + nbyte <= 0; + thisbyte <= 0; + shiftreg <= (others => '0'); + nak <= '0'; -- No error + retries <= num_retries; + elsif rising_edge(CLK) and clken = '1' then + -- Next phase by default + phase <= phase + 1; + + -- STATE: IDLE + if state = Idle then + -- Start loading the device registers straight away + -- A 'GO' bit could be polled here if required + state <= Start; + phase <= "00"; + scl_out <= '1'; + sda_out <= '1'; + + -- STATE: START + elsif state = Start then + -- Generate START condition + case phase is + when "00" => + -- Drop SDA first + sda_out <= '0'; + when "10" => + -- Then drop SCL + scl_out <= '0'; + when "11" => + -- Advance to next state + -- Shift register loaded with device slave address + state <= Data; + nbit <= 7; + shiftreg <= std_logic_vector(to_unsigned(device_address,7)) & '0'; -- writing + nbyte <= burst_length; + when others => + null; + end case; + + -- STATE: DATA + elsif state = Data then + -- Generate data + case phase is + when "00" => + -- Drop SCL + scl_out <= '0'; + when "01" => + -- Output data and shift (MSb first) + sda_out <= shiftreg(7); + shiftreg <= shiftreg(6 downto 0) & '0'; + when "10" => + -- Raise SCL + scl_out <= '1'; + when "11" => + -- Next bit or advance to next state when done + if nbit = 0 then + state <= Ack; + else + nbit <= nbit - 1; + end if; + when others => + null; + end case; + + -- STATE: ACK + elsif state = Ack then + -- Generate ACK clock and check for error condition + case phase is + when "00" => + -- Drop SCL + scl_out <= '0'; + when "01" => + -- Float data + sda_out <= '1'; + when "10" => + -- Sample ack bit + nak <= I2C_SDA; + if I2C_SDA = '1' then + -- Error + nbyte <= 0; -- Close this burst and skip remaining registers + thisbyte <= init_regs'length; + else + -- Hold ACK to avoid spurious stops - this seems to fix a + -- problem with the Wolfson codec which releases the ACK + -- right on the falling edge of the clock pulse. It looks like + -- the device interprets this is a STOP condition and then fails + -- to acknowledge the next byte. We can avoid this by holding the + -- ACK condition for a little longer. + sda_out <= '0'; + end if; + -- Raise SCL + scl_out <= '1'; + when "11" => + -- Advance to next state + if nbyte = 0 then + -- No more bytes in this burst - generate a STOP + state <= Stop; + else + -- Generate next byte + state <= Data; + nbit <= 7; + shiftreg <= init_regs(thisbyte); + nbyte <= nbyte - 1; + thisbyte <= thisbyte + 1; + end if; + when others => + null; + end case; + + -- STATE: STOP + elsif state = Stop then + -- Generate STOP condition + case phase is + when "00" => + -- Drop SCL first + scl_out <= '0'; + when "01" => + -- Drop SDA + sda_out <= '0'; + when "10" => + -- Raise SCL + scl_out <= '1'; + when "11" => + if thisbyte = init_regs'length then + -- All registers done, advance to finished state. This will + -- bring SDA high while SCL is still high, completing the STOP + -- condition + state <= Done; + else + -- Load the next register after a short delay + state <= Pause; + end if; + when others => + null; + end case; + + -- STATE: PAUSE + elsif state = Pause then + -- Delay for one cycle of 'phase' then start the next burst + scl_out <= '1'; + sda_out <= '1'; + if phase = "11" then + state <= Start; + end if; + + -- STATE: DONE + else + -- Finished + scl_out <= '1'; + sda_out <= '1'; + + if nak = '1' and retries > 0 then + -- We can retry in the event of a NAK in case the + -- slave got out of sync for some reason + retries <= retries - 1; + state <= Idle; + end if; + end if; + end if; + end process; +end i2c_loader_arch; + diff --git a/i2s_intf.vhd b/i2s_intf.vhd index e15ce2c..49b6efb 100644 --- a/i2s_intf.vhd +++ b/i2s_intf.vhd @@ -1,37 +1,37 @@ -- ZX Spectrum for Altera DE1 -- --- Copyright (c) 2009-2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- Copyright (c) 2009-2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -- POSSIBILITY OF SUCH DAMAGE. -- diff --git a/keyboard.vhd b/keyboard.vhd index c0b8603..cba4054 100644 --- a/keyboard.vhd +++ b/keyboard.vhd @@ -1,294 +1,294 @@ --- BBC Micro for Altera DE1 --- --- Copyright (c) 2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- BBC keyboard implementation with interface to PS/2 --- --- (C) 2011 Mike Stirling --- - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - -entity keyboard is -port ( - CLOCK : in std_logic; - nRESET : in std_logic; - CLKEN_1MHZ : in std_logic; - - -- PS/2 interface - PS2_CLK : in std_logic; - PS2_DATA : in std_logic; - - -- If 1 then column is incremented automatically at - -- 1 MHz rate - AUTOSCAN : in std_logic; - - COLUMN : in std_logic_vector(3 downto 0); - ROW : in std_logic_vector(2 downto 0); - - -- 1 when currently selected key is down (AUTOSCAN disabled) - KEYPRESS : out std_logic; - -- 1 when any key is down (except row 0) - INT : out std_logic; - -- BREAK key output - 1 when pressed - BREAK_OUT : out std_logic; - - -- DIP switch inputs - DIP_SWITCH : in std_logic_vector(7 downto 0) - ); -end entity; - -architecture rtl of keyboard is - --- PS/2 interface -component ps2_intf is -generic (filter_length : positive := 8); -port( - CLK : in std_logic; - nRESET : in std_logic; - - -- PS/2 interface (could be bi-dir) - PS2_CLK : in std_logic; - PS2_DATA : in std_logic; - - -- Byte-wide data interface - only valid for one clock - -- so must be latched externally if required - DATA : out std_logic_vector(7 downto 0); - VALID : out std_logic; - ERROR : out std_logic - ); -end component; - --- Interface to PS/2 block -signal keyb_data : std_logic_vector(7 downto 0); -signal keyb_valid : std_logic; -signal keyb_error : std_logic; - --- Internal signals -type key_matrix is array(0 to 15) of std_logic_vector(7 downto 0); -signal keys : key_matrix; -signal col : unsigned(3 downto 0); -signal release : std_logic; -signal extended : std_logic; -begin - - ps2 : ps2_intf port map ( - CLOCK, nRESET, - PS2_CLK, PS2_DATA, - keyb_data, keyb_valid, keyb_error - ); - - -- Column counts automatically when AUTOSCAN is enabled, otherwise - -- value is loaded from external input - process(CLOCK,nRESET) - begin - if nRESET = '0' then - col <= (others => '0'); - elsif rising_edge(CLOCK) then - if AUTOSCAN = '0' then - -- If autoscan disabled then transfer current COLUMN to counter - -- immediately (don't wait for next 1 MHz cycle) - col <= unsigned(COLUMN); - elsif CLKEN_1MHZ = '1' then - -- Otherwise increment the counter once per 1 MHz tick - col <= col + 1; - end if; - end if; - end process; - - -- Generate interrupt if any key in currently scanned column is pressed - -- (apart from in row 0). Output selected key status if autoscan disabled. - process(keys,col,ROW,AUTOSCAN) - variable k : std_logic_vector(7 downto 0); - begin - -- Shortcut to current key column - k := keys(to_integer(col)); - - -- Interrupt if any key pressed in rows 1 to 7. - INT <= k(7) or k(6) or k(5) or k(4) or k(3) or k(2) or k(1); - - -- Determine which key is pressed - -- Inhibit output during auto-scan - if AUTOSCAN = '0' then - KEYPRESS <= k(to_integer(unsigned(ROW))); - else - KEYPRESS <= '0'; - end if; - end process; - - -- Decode PS/2 data - process(CLOCK,nRESET) - begin - if nRESET = '0' then - release <= '0'; - extended <= '0'; - - BREAK_OUT <= '0'; - - keys(0) <= (others => '0'); - keys(1) <= (others => '0'); - keys(2) <= (others => '0'); - keys(3) <= (others => '0'); - keys(4) <= (others => '0'); - keys(5) <= (others => '0'); - keys(6) <= (others => '0'); - keys(7) <= (others => '0'); - keys(8) <= (others => '0'); - keys(9) <= (others => '0'); - -- These non-existent rows are used in the BBC master - keys(10) <= (others => '0'); - keys(11) <= (others => '0'); - keys(12) <= (others => '0'); - keys(13) <= (others => '0'); - keys(14) <= (others => '0'); - keys(15) <= (others => '0'); - elsif rising_edge(CLOCK) then - -- Copy DIP switches through to row 0 - keys(2)(0) <= DIP_SWITCH(7); - keys(3)(0) <= DIP_SWITCH(6); - keys(4)(0) <= DIP_SWITCH(5); - keys(5)(0) <= DIP_SWITCH(4); - keys(6)(0) <= DIP_SWITCH(3); - keys(7)(0) <= DIP_SWITCH(2); - keys(8)(0) <= DIP_SWITCH(1); - keys(9)(0) <= DIP_SWITCH(0); - - if keyb_valid = '1' then - -- Decode keyboard input - if keyb_data = X"e0" then - -- Extended key code follows - extended <= '1'; - elsif keyb_data = X"f0" then - -- Release code follows - release <= '1'; - else - -- Cancel extended/release flags for next time - release <= '0'; - extended <= '0'; - - -- Decode scan codes - case keyb_data is - when X"12" => keys(0)(0) <= not release; -- Left SHIFT - when X"59" => keys(0)(0) <= not release; -- Right SHIFT - when X"15" => keys(0)(1) <= not release; -- Q - when X"09" => keys(0)(2) <= not release; -- F10 (F0) - when X"16" => keys(0)(3) <= not release; -- 1 - when X"58" => keys(0)(4) <= not release; -- CAPS LOCK - when X"11" => keys(0)(5) <= not release; -- LEFT ALT (SHIFT LOCK) - when X"0D" => keys(0)(6) <= not release; -- TAB - when X"76" => keys(0)(7) <= not release; -- ESCAPE - when X"14" => keys(1)(0) <= not release; -- LEFT/RIGHT CTRL (CTRL) - when X"26" => keys(1)(1) <= not release; -- 3 - when X"1D" => keys(1)(2) <= not release; -- W - when X"1E" => keys(1)(3) <= not release; -- 2 - when X"1C" => keys(1)(4) <= not release; -- A - when X"1B" => keys(1)(5) <= not release; -- S - when X"1A" => keys(1)(6) <= not release; -- Z - when X"05" => keys(1)(7) <= not release; -- F1 - when X"25" => keys(2)(1) <= not release; -- 4 - when X"24" => keys(2)(2) <= not release; -- E - when X"23" => keys(2)(3) <= not release; -- D - when X"22" => keys(2)(4) <= not release; -- X - when X"21" => keys(2)(5) <= not release; -- C - when X"29" => keys(2)(6) <= not release; -- SPACE - when X"06" => keys(2)(7) <= not release; -- F2 - when X"2E" => keys(3)(1) <= not release; -- 5 - when X"2C" => keys(3)(2) <= not release; -- T - when X"2D" => keys(3)(3) <= not release; -- R - when X"2B" => keys(3)(4) <= not release; -- F - when X"34" => keys(3)(5) <= not release; -- G - when X"2A" => keys(3)(6) <= not release; -- V - when X"04" => keys(3)(7) <= not release; -- F3 - when X"0C" => keys(4)(1) <= not release; -- F4 - when X"3D" => keys(4)(2) <= not release; -- 7 - when X"36" => keys(4)(3) <= not release; -- 6 - when X"35" => keys(4)(4) <= not release; -- Y - when X"33" => keys(4)(5) <= not release; -- H - when X"32" => keys(4)(6) <= not release; -- B - when X"03" => keys(4)(7) <= not release; -- F5 - when X"3E" => keys(5)(1) <= not release; -- 8 - when X"43" => keys(5)(2) <= not release; -- I - when X"3C" => keys(5)(3) <= not release; -- U - when X"3B" => keys(5)(4) <= not release; -- J - when X"31" => keys(5)(5) <= not release; -- N - when X"3A" => keys(5)(6) <= not release; -- M - when X"0B" => keys(5)(7) <= not release; -- F6 - when X"83" => keys(6)(1) <= not release; -- F7 - when X"46" => keys(6)(2) <= not release; -- 9 - when X"44" => keys(6)(3) <= not release; -- O - when X"42" => keys(6)(4) <= not release; -- K - when X"4B" => keys(6)(5) <= not release; -- L - when X"41" => keys(6)(6) <= not release; -- , - when X"0A" => keys(6)(7) <= not release; -- F8 - when X"4E" => keys(7)(1) <= not release; -- - - when X"45" => keys(7)(2) <= not release; -- 0 - when X"4D" => keys(7)(3) <= not release; -- P - when X"0E" => keys(7)(4) <= not release; -- ` (@) - when X"4C" => keys(7)(5) <= not release; -- ; - when X"49" => keys(7)(6) <= not release; -- . - when X"01" => keys(7)(7) <= not release; -- F9 - when X"55" => keys(8)(1) <= not release; -- = (^) - when X"5D" => keys(8)(2) <= not release; -- # (_) - when X"54" => keys(8)(3) <= not release; -- [ - when X"52" => keys(8)(4) <= not release; -- ' - when X"5B" => keys(8)(5) <= not release; -- ] - when X"4A" => keys(8)(6) <= not release; -- / - when X"61" => keys(8)(7) <= not release; -- \ - when X"6B" => keys(9)(1) <= not release; -- LEFT - when X"72" => keys(9)(2) <= not release; -- DOWN - when X"75" => keys(9)(3) <= not release; -- UP - when X"5A" => keys(9)(4) <= not release; -- RETURN - when X"66" => keys(9)(5) <= not release; -- BACKSPACE (DELETE) - when X"69" => keys(9)(6) <= not release; -- END (COPY) - when X"74" => keys(9)(7) <= not release; -- RIGHT - - -- F12 is used for the BREAK key, which in the real BBC asserts - -- reset. Here we pass this out to the top level which may - -- optionally OR it in to the system reset - when X"07" => BREAK_OUT <= not release; -- F12 (BREAK) - - when others => null; - end case; - - end if; - end if; - end if; - end process; - -end architecture; - - +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- BBC keyboard implementation with interface to PS/2 +-- +-- (C) 2011 Mike Stirling +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity keyboard is +port ( + CLOCK : in std_logic; + nRESET : in std_logic; + CLKEN_1MHZ : in std_logic; + + -- PS/2 interface + PS2_CLK : in std_logic; + PS2_DATA : in std_logic; + + -- If 1 then column is incremented automatically at + -- 1 MHz rate + AUTOSCAN : in std_logic; + + COLUMN : in std_logic_vector(3 downto 0); + ROW : in std_logic_vector(2 downto 0); + + -- 1 when currently selected key is down (AUTOSCAN disabled) + KEYPRESS : out std_logic; + -- 1 when any key is down (except row 0) + INT : out std_logic; + -- BREAK key output - 1 when pressed + BREAK_OUT : out std_logic; + + -- DIP switch inputs + DIP_SWITCH : in std_logic_vector(7 downto 0) + ); +end entity; + +architecture rtl of keyboard is + +-- PS/2 interface +component ps2_intf is +generic (filter_length : positive := 8); +port( + CLK : in std_logic; + nRESET : in std_logic; + + -- PS/2 interface (could be bi-dir) + PS2_CLK : in std_logic; + PS2_DATA : in std_logic; + + -- Byte-wide data interface - only valid for one clock + -- so must be latched externally if required + DATA : out std_logic_vector(7 downto 0); + VALID : out std_logic; + ERROR : out std_logic + ); +end component; + +-- Interface to PS/2 block +signal keyb_data : std_logic_vector(7 downto 0); +signal keyb_valid : std_logic; +signal keyb_error : std_logic; + +-- Internal signals +type key_matrix is array(0 to 15) of std_logic_vector(7 downto 0); +signal keys : key_matrix; +signal col : unsigned(3 downto 0); +signal release : std_logic; +signal extended : std_logic; +begin + + ps2 : ps2_intf port map ( + CLOCK, nRESET, + PS2_CLK, PS2_DATA, + keyb_data, keyb_valid, keyb_error + ); + + -- Column counts automatically when AUTOSCAN is enabled, otherwise + -- value is loaded from external input + process(CLOCK,nRESET) + begin + if nRESET = '0' then + col <= (others => '0'); + elsif rising_edge(CLOCK) then + if AUTOSCAN = '0' then + -- If autoscan disabled then transfer current COLUMN to counter + -- immediately (don't wait for next 1 MHz cycle) + col <= unsigned(COLUMN); + elsif CLKEN_1MHZ = '1' then + -- Otherwise increment the counter once per 1 MHz tick + col <= col + 1; + end if; + end if; + end process; + + -- Generate interrupt if any key in currently scanned column is pressed + -- (apart from in row 0). Output selected key status if autoscan disabled. + process(keys,col,ROW,AUTOSCAN) + variable k : std_logic_vector(7 downto 0); + begin + -- Shortcut to current key column + k := keys(to_integer(col)); + + -- Interrupt if any key pressed in rows 1 to 7. + INT <= k(7) or k(6) or k(5) or k(4) or k(3) or k(2) or k(1); + + -- Determine which key is pressed + -- Inhibit output during auto-scan + if AUTOSCAN = '0' then + KEYPRESS <= k(to_integer(unsigned(ROW))); + else + KEYPRESS <= '0'; + end if; + end process; + + -- Decode PS/2 data + process(CLOCK,nRESET) + begin + if nRESET = '0' then + release <= '0'; + extended <= '0'; + + BREAK_OUT <= '0'; + + keys(0) <= (others => '0'); + keys(1) <= (others => '0'); + keys(2) <= (others => '0'); + keys(3) <= (others => '0'); + keys(4) <= (others => '0'); + keys(5) <= (others => '0'); + keys(6) <= (others => '0'); + keys(7) <= (others => '0'); + keys(8) <= (others => '0'); + keys(9) <= (others => '0'); + -- These non-existent rows are used in the BBC master + keys(10) <= (others => '0'); + keys(11) <= (others => '0'); + keys(12) <= (others => '0'); + keys(13) <= (others => '0'); + keys(14) <= (others => '0'); + keys(15) <= (others => '0'); + elsif rising_edge(CLOCK) then + -- Copy DIP switches through to row 0 + keys(2)(0) <= DIP_SWITCH(7); + keys(3)(0) <= DIP_SWITCH(6); + keys(4)(0) <= DIP_SWITCH(5); + keys(5)(0) <= DIP_SWITCH(4); + keys(6)(0) <= DIP_SWITCH(3); + keys(7)(0) <= DIP_SWITCH(2); + keys(8)(0) <= DIP_SWITCH(1); + keys(9)(0) <= DIP_SWITCH(0); + + if keyb_valid = '1' then + -- Decode keyboard input + if keyb_data = X"e0" then + -- Extended key code follows + extended <= '1'; + elsif keyb_data = X"f0" then + -- Release code follows + release <= '1'; + else + -- Cancel extended/release flags for next time + release <= '0'; + extended <= '0'; + + -- Decode scan codes + case keyb_data is + when X"12" => keys(0)(0) <= not release; -- Left SHIFT + when X"59" => keys(0)(0) <= not release; -- Right SHIFT + when X"15" => keys(0)(1) <= not release; -- Q + when X"09" => keys(0)(2) <= not release; -- F10 (F0) + when X"16" => keys(0)(3) <= not release; -- 1 + when X"58" => keys(0)(4) <= not release; -- CAPS LOCK + when X"11" => keys(0)(5) <= not release; -- LEFT ALT (SHIFT LOCK) + when X"0D" => keys(0)(6) <= not release; -- TAB + when X"76" => keys(0)(7) <= not release; -- ESCAPE + when X"14" => keys(1)(0) <= not release; -- LEFT/RIGHT CTRL (CTRL) + when X"26" => keys(1)(1) <= not release; -- 3 + when X"1D" => keys(1)(2) <= not release; -- W + when X"1E" => keys(1)(3) <= not release; -- 2 + when X"1C" => keys(1)(4) <= not release; -- A + when X"1B" => keys(1)(5) <= not release; -- S + when X"1A" => keys(1)(6) <= not release; -- Z + when X"05" => keys(1)(7) <= not release; -- F1 + when X"25" => keys(2)(1) <= not release; -- 4 + when X"24" => keys(2)(2) <= not release; -- E + when X"23" => keys(2)(3) <= not release; -- D + when X"22" => keys(2)(4) <= not release; -- X + when X"21" => keys(2)(5) <= not release; -- C + when X"29" => keys(2)(6) <= not release; -- SPACE + when X"06" => keys(2)(7) <= not release; -- F2 + when X"2E" => keys(3)(1) <= not release; -- 5 + when X"2C" => keys(3)(2) <= not release; -- T + when X"2D" => keys(3)(3) <= not release; -- R + when X"2B" => keys(3)(4) <= not release; -- F + when X"34" => keys(3)(5) <= not release; -- G + when X"2A" => keys(3)(6) <= not release; -- V + when X"04" => keys(3)(7) <= not release; -- F3 + when X"0C" => keys(4)(1) <= not release; -- F4 + when X"3D" => keys(4)(2) <= not release; -- 7 + when X"36" => keys(4)(3) <= not release; -- 6 + when X"35" => keys(4)(4) <= not release; -- Y + when X"33" => keys(4)(5) <= not release; -- H + when X"32" => keys(4)(6) <= not release; -- B + when X"03" => keys(4)(7) <= not release; -- F5 + when X"3E" => keys(5)(1) <= not release; -- 8 + when X"43" => keys(5)(2) <= not release; -- I + when X"3C" => keys(5)(3) <= not release; -- U + when X"3B" => keys(5)(4) <= not release; -- J + when X"31" => keys(5)(5) <= not release; -- N + when X"3A" => keys(5)(6) <= not release; -- M + when X"0B" => keys(5)(7) <= not release; -- F6 + when X"83" => keys(6)(1) <= not release; -- F7 + when X"46" => keys(6)(2) <= not release; -- 9 + when X"44" => keys(6)(3) <= not release; -- O + when X"42" => keys(6)(4) <= not release; -- K + when X"4B" => keys(6)(5) <= not release; -- L + when X"41" => keys(6)(6) <= not release; -- , + when X"0A" => keys(6)(7) <= not release; -- F8 + when X"4E" => keys(7)(1) <= not release; -- - + when X"45" => keys(7)(2) <= not release; -- 0 + when X"4D" => keys(7)(3) <= not release; -- P + when X"0E" => keys(7)(4) <= not release; -- ` (@) + when X"4C" => keys(7)(5) <= not release; -- ; + when X"49" => keys(7)(6) <= not release; -- . + when X"01" => keys(7)(7) <= not release; -- F9 + when X"55" => keys(8)(1) <= not release; -- = (^) + when X"5D" => keys(8)(2) <= not release; -- # (_) + when X"54" => keys(8)(3) <= not release; -- [ + when X"52" => keys(8)(4) <= not release; -- ' + when X"5B" => keys(8)(5) <= not release; -- ] + when X"4A" => keys(8)(6) <= not release; -- / + when X"61" => keys(8)(7) <= not release; -- \ + when X"6B" => keys(9)(1) <= not release; -- LEFT + when X"72" => keys(9)(2) <= not release; -- DOWN + when X"75" => keys(9)(3) <= not release; -- UP + when X"5A" => keys(9)(4) <= not release; -- RETURN + when X"66" => keys(9)(5) <= not release; -- BACKSPACE (DELETE) + when X"69" => keys(9)(6) <= not release; -- END (COPY) + when X"74" => keys(9)(7) <= not release; -- RIGHT + + -- F12 is used for the BREAK key, which in the real BBC asserts + -- reset. Here we pass this out to the top level which may + -- optionally OR it in to the system reset + when X"07" => BREAK_OUT <= not release; -- F12 (BREAK) + + when others => null; + end case; + + end if; + end if; + end if; + end process; + +end architecture; + + diff --git a/m6522.vhd b/m6522.vhd index e01ed10..5c0d341 100644 --- a/m6522.vhd +++ b/m6522.vhd @@ -1,886 +1,886 @@ --- --- A simulation model of VIC20 hardware --- Copyright (c) MikeJ - March 2003 --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written permission. --- --- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- You are responsible for any legal issues arising from your use of this code. --- --- The latest version of this file can be found at: www.fpgaarcade.com --- --- Email vic20@fpgaarcade.com --- --- --- Revision list --- --- version 002 fix from Mark McDougall, untested --- version 001 initial release --- not very sure about the shift register, documentation is a bit light. - -library ieee ; - use ieee.std_logic_1164.all ; - use ieee.std_logic_unsigned.all; - use ieee.numeric_std.all; - ---library UNISIM; --- use UNISIM.Vcomponents.all; - -entity M6522 is - port ( - - I_RS : in std_logic_vector(3 downto 0); - I_DATA : in std_logic_vector(7 downto 0); - O_DATA : out std_logic_vector(7 downto 0); - O_DATA_OE_L : out std_logic; - - I_RW_L : in std_logic; - I_CS1 : in std_logic; - I_CS2_L : in std_logic; - - O_IRQ_L : out std_logic; -- note, not open drain - -- port a - I_CA1 : in std_logic; - I_CA2 : in std_logic; - O_CA2 : out std_logic; - O_CA2_OE_L : out std_logic; - - I_PA : in std_logic_vector(7 downto 0); - O_PA : out std_logic_vector(7 downto 0); - O_PA_OE_L : out std_logic_vector(7 downto 0); - - -- port b - I_CB1 : in std_logic; - O_CB1 : out std_logic; - O_CB1_OE_L : out std_logic; - - I_CB2 : in std_logic; - O_CB2 : out std_logic; - O_CB2_OE_L : out std_logic; - - I_PB : in std_logic_vector(7 downto 0); - O_PB : out std_logic_vector(7 downto 0); - O_PB_OE_L : out std_logic_vector(7 downto 0); - - I_P2_H : in std_logic; -- high for phase 2 clock ____----__ - RESET_L : in std_logic; - ENA_4 : in std_logic; -- clk enable - CLK : in std_logic - ); -end; - -architecture RTL of M6522 is - - signal phase : std_logic_vector(1 downto 0); - signal p2_h_t1 : std_logic; - signal cs : std_logic; - - -- registers - signal r_ddra : std_logic_vector(7 downto 0); - signal r_ora : std_logic_vector(7 downto 0); - signal r_ira : std_logic_vector(7 downto 0); - - signal r_ddrb : std_logic_vector(7 downto 0); - signal r_orb : std_logic_vector(7 downto 0); - signal r_irb : std_logic_vector(7 downto 0); - - signal r_t1l_l : std_logic_vector(7 downto 0); - signal r_t1l_h : std_logic_vector(7 downto 0); - signal r_t2l_l : std_logic_vector(7 downto 0); - signal r_t2l_h : std_logic_vector(7 downto 0); -- not in real chip - signal r_sr : std_logic_vector(7 downto 0); - signal r_acr : std_logic_vector(7 downto 0); - signal r_pcr : std_logic_vector(7 downto 0); - signal r_ifr : std_logic_vector(7 downto 0); - signal r_ier : std_logic_vector(6 downto 0); - - signal sr_write_ena : boolean; - signal sr_read_ena : boolean; - signal ifr_write_ena : boolean; - signal ier_write_ena : boolean; - signal clear_irq : std_logic_vector(7 downto 0); - signal load_data : std_logic_vector(7 downto 0); - - -- timer 1 - signal t1c : std_logic_vector(15 downto 0); - signal t1c_active : boolean; - signal t1c_done : boolean; - signal t1_w_reset_int : boolean; - signal t1_r_reset_int : boolean; - signal t1_load_counter : boolean; - signal t1_reload_counter : boolean; - signal t1_toggle : std_logic; - signal t1_irq : std_logic := '0'; - - -- timer 2 - signal t2c : std_logic_vector(15 downto 0); - signal t2c_active : boolean; - signal t2c_done : boolean; - signal t2_pb6 : std_logic; - signal t2_pb6_t1 : std_logic; - signal t2_w_reset_int : boolean; - signal t2_r_reset_int : boolean; - signal t2_load_counter : boolean; - signal t2_reload_counter : boolean; - signal t2_irq : std_logic := '0'; - signal t2_sr_ena : boolean; - - -- shift reg - signal sr_cnt : std_logic_vector(3 downto 0); - signal sr_cb1_oe_l : std_logic; - signal sr_cb1_out : std_logic; - signal sr_drive_cb2 : std_logic; - signal sr_strobe : std_logic; - signal sr_strobe_t1 : std_logic; - signal sr_strobe_falling : boolean; - signal sr_strobe_rising : boolean; - signal sr_irq : std_logic; - signal sr_out : std_logic; - signal sr_off_delay : std_logic; - - -- io - signal w_orb_hs : std_logic; - signal w_ora_hs : std_logic; - signal r_irb_hs : std_logic; - signal r_ira_hs : std_logic; - - signal ca_hs_sr : std_logic; - signal ca_hs_pulse : std_logic; - signal cb_hs_sr : std_logic; - signal cb_hs_pulse : std_logic; - - signal cb1_in_mux : std_logic; - signal ca1_ip_reg : std_logic; - signal cb1_ip_reg : std_logic; - signal ca1_int : boolean; - signal cb1_int : boolean; - signal ca1_irq : std_logic; - signal cb1_irq : std_logic; - - signal ca2_ip_reg : std_logic; - signal cb2_ip_reg : std_logic; - signal ca2_int : boolean; - signal cb2_int : boolean; - signal ca2_irq : std_logic; - signal cb2_irq : std_logic; - - signal final_irq : std_logic; -begin - p_phase : process - begin - -- internal clock phase - wait until rising_edge(CLK); - if (ENA_4 = '1') then - p2_h_t1 <= I_P2_H; - if (p2_h_t1 = '0') and (I_P2_H = '1') then - phase <= "11"; - else - phase <= phase + "1"; - end if; - end if; - end process; - - p_cs : process(I_CS1, I_CS2_L, I_P2_H) - begin - cs <= '0'; - if (I_CS1 = '1') and (I_CS2_L = '0') and (I_P2_H = '1') then - cs <= '1'; - end if; - end process; - - -- peripheral control reg (pcr) - -- 0 ca1 interrupt control (0 +ve edge, 1 -ve edge) - -- 3..1 ca2 operation - -- 000 input -ve edge - -- 001 independend interrupt input -ve edge - -- 010 input +ve edge - -- 011 independend interrupt input +ve edge - -- 100 handshake output - -- 101 pulse output - -- 110 low output - -- 111 high output - -- 7..4 as 3..0 for cb1,cb2 - - -- auxiliary control reg (acr) - -- 0 input latch PA (0 disable, 1 enable) - -- 1 input latch PB (0 disable, 1 enable) - -- 4..2 shift reg control - -- 000 disable - -- 001 shift in using t2 - -- 010 shift in using o2 - -- 011 shift in using ext clk - -- 100 shift out free running t2 rate - -- 101 shift out using t2 - -- 101 shift out using o2 - -- 101 shift out using ext clk - -- 5 t2 timer control (0 timed interrupt, 1 count down with pulses on pb6) - -- 7..6 t1 timer control - -- 00 timed interrupt each time t1 is loaded pb7 disable - -- 01 continuous interrupts pb7 disable - -- 00 timed interrupt each time t1 is loaded pb7 one shot output - -- 01 continuous interrupts pb7 square wave output - -- - - p_write_reg_reset : process(RESET_L, CLK) - begin - if (RESET_L = '0') then - r_ora <= x"00"; r_orb <= x"00"; - r_ddra <= x"00"; r_ddrb <= x"00"; - r_acr <= x"00"; r_pcr <= x"00"; - - w_orb_hs <= '0'; - w_ora_hs <= '0'; - elsif rising_edge(CLK) then - if (ENA_4 = '1') then - w_orb_hs <= '0'; - w_ora_hs <= '0'; - if (cs = '1') and (I_RW_L = '0') then - case I_RS is - when x"0" => r_orb <= I_DATA; w_orb_hs <= '1'; - when x"1" => r_ora <= I_DATA; w_ora_hs <= '1'; - when x"2" => r_ddrb <= I_DATA; - when x"3" => r_ddra <= I_DATA; - - when x"B" => r_acr <= I_DATA; - when x"C" => r_pcr <= I_DATA; - when x"F" => r_ora <= I_DATA; - - when others => null; - end case; - end if; - - if (r_acr(7) = '1') and (t1_toggle = '1') then - r_orb(7) <= not r_orb(7); -- toggle - end if; - end if; - end if; - end process; - - p_write_reg : process - begin - wait until rising_edge(CLK); - if (ENA_4 = '1') then - t1_w_reset_int <= false; - t1_load_counter <= false; - - t2_w_reset_int <= false; - t2_load_counter <= false; - - load_data <= x"00"; - sr_write_ena <= false; - ifr_write_ena <= false; - ier_write_ena <= false; - - if (cs = '1') and (I_RW_L = '0') then - load_data <= I_DATA; - case I_RS is - when x"4" => r_t1l_l <= I_DATA; - when x"5" => r_t1l_h <= I_DATA; t1_w_reset_int <= true; - t1_load_counter <= true; - - when x"6" => r_t1l_l <= I_DATA; - when x"7" => r_t1l_h <= I_DATA; t1_w_reset_int <= true; - - when x"8" => r_t2l_l <= I_DATA; - when x"9" => r_t2l_h <= I_DATA; t2_w_reset_int <= true; - t2_load_counter <= true; - - when x"A" => sr_write_ena <= true; - when x"D" => ifr_write_ena <= true; - when x"E" => ier_write_ena <= true; - - when others => null; - end case; - end if; - end if; - end process; - - p_oe : process(cs, I_RW_L) - begin - O_DATA_OE_L <= '1'; - if (cs = '1') and (I_RW_L = '1') then - O_DATA_OE_L <= '0'; - end if; - end process; - - p_read : process - begin - wait until rising_edge(CLK); - - if ENA_4 = '1' then - t1_r_reset_int <= false; - t2_r_reset_int <= false; - sr_read_ena <= false; - r_irb_hs <= '0'; - r_ira_hs <= '0'; - - if (cs = '1') and (I_RW_L = '1') then - case I_RS is - --when x"0" => O_DATA <= r_irb; r_irb_hs <= '1'; - -- fix from Mark McDougall, untested - when x"0" => O_DATA <= (r_irb and not r_ddrb) or (r_orb and r_ddrb); r_irb_hs <= '1'; - when x"1" => O_DATA <= r_ira; r_ira_hs <= '1'; - when x"2" => O_DATA <= r_ddrb; - when x"3" => O_DATA <= r_ddra; - when x"4" => O_DATA <= t1c( 7 downto 0); t1_r_reset_int <= true; - when x"5" => O_DATA <= t1c(15 downto 8); - when x"6" => O_DATA <= r_t1l_l; - when x"7" => O_DATA <= r_t1l_h; - when x"8" => O_DATA <= t2c( 7 downto 0); t2_r_reset_int <= true; - when x"9" => O_DATA <= t2c(15 downto 8); - when x"A" => O_DATA <= r_sr; sr_read_ena <= true; - when x"B" => O_DATA <= r_acr; - when x"C" => O_DATA <= r_pcr; - when x"D" => O_DATA <= r_ifr; - when x"E" => O_DATA <= ('0' & r_ier); - when x"F" => O_DATA <= r_ira; - when others => null; - end case; - end if; - end if; - - end process; - -- - -- IO - -- - p_ca1_cb1_sel : process(sr_cb1_oe_l, sr_cb1_out, I_CB1) - begin - -- if the shift register is enabled, cb1 may be an output - -- in this case, we should listen to the CB1_OUT for the interrupt - if (sr_cb1_oe_l = '1') then - cb1_in_mux <= I_CB1; - else - cb1_in_mux <= sr_cb1_out; - end if; - end process; - - p_ca1_cb1_int : process(r_pcr, ca1_ip_reg, I_CA1, cb1_ip_reg, cb1_in_mux) - begin - if (r_pcr(0) = '0') then -- ca1 control - -- negative edge - ca1_int <= (ca1_ip_reg = '1') and (I_CA1 = '0'); - else - -- positive edge - ca1_int <= (ca1_ip_reg = '0') and (I_CA1 = '1'); - end if; - - if (r_pcr(4) = '0') then -- cb1 control - -- negative edge - cb1_int <= (cb1_ip_reg = '1') and (cb1_in_mux = '0'); - else - -- positive edge - cb1_int <= (cb1_ip_reg = '0') and (cb1_in_mux = '1'); - end if; - end process; - - p_ca2_cb2_int : process(r_pcr, ca2_ip_reg, I_CA2, cb2_ip_reg, I_CB2) - begin - ca2_int <= false; - if (r_pcr(3) = '0') then -- ca2 input - if (r_pcr(2) = '0') then -- ca2 edge - -- negative edge - ca2_int <= (ca2_ip_reg = '1') and (I_CA2 = '0'); - else - -- positive edge - ca2_int <= (ca2_ip_reg = '0') and (I_CA2 = '1'); - end if; - end if; - - cb2_int <= false; - if (r_pcr(7) = '0') then -- cb2 input - if (r_pcr(6) = '0') then -- cb2 edge - -- negative edge - cb2_int <= (cb2_ip_reg = '1') and (I_CB2 = '0'); - else - -- positive edge - cb2_int <= (cb2_ip_reg = '0') and (I_CB2 = '1'); - end if; - end if; - end process; - - p_ca2_cb2 : process(RESET_L, CLK) - begin - if (RESET_L = '0') then - O_CA2 <= '0'; - O_CA2_OE_L <= '1'; - O_CB2 <= '0'; - O_CB2_OE_L <= '1'; - - ca_hs_sr <= '0'; - ca_hs_pulse <= '0'; - cb_hs_sr <= '0'; - cb_hs_pulse <= '0'; - elsif rising_edge(CLK) then - if (ENA_4 = '1') then - -- ca - if (phase = "00") and ((w_ora_hs = '1') or (r_ira_hs = '1')) then - ca_hs_sr <= '1'; - elsif ca1_int then - ca_hs_sr <= '0'; - end if; - - if (phase = "00") then - ca_hs_pulse <= w_ora_hs or r_ira_hs; - end if; - - O_CA2_OE_L <= not r_pcr(3); -- ca2 output - case r_pcr(3 downto 1) is - when "000" => O_CA2 <= '0'; -- input - when "001" => O_CA2 <= '0'; -- input - when "010" => O_CA2 <= '0'; -- input - when "011" => O_CA2 <= '0'; -- input - when "100" => O_CA2 <= not (ca_hs_sr); -- handshake - when "101" => O_CA2 <= not (ca_hs_pulse); -- pulse - when "110" => O_CA2 <= '0'; -- low - when "111" => O_CA2 <= '1'; -- high - when others => null; - end case; - - -- cb - if (phase = "00") and (w_orb_hs = '1') then - cb_hs_sr <= '1'; - elsif cb1_int then - cb_hs_sr <= '0'; - end if; - - if (phase = "00") then - cb_hs_pulse <= w_orb_hs; - end if; - - O_CB2_OE_L <= not (r_pcr(7) or sr_drive_cb2); -- cb2 output or serial - if (sr_drive_cb2 = '1') then -- serial output - O_CB2 <= sr_out; - else - case r_pcr(7 downto 5) is - when "000" => O_CB2 <= '0'; -- input - when "001" => O_CB2 <= '0'; -- input - when "010" => O_CB2 <= '0'; -- input - when "011" => O_CB2 <= '0'; -- input - when "100" => O_CB2 <= not (cb_hs_sr); -- handshake - when "101" => O_CB2 <= not (cb_hs_pulse); -- pulse - when "110" => O_CB2 <= '0'; -- low - when "111" => O_CB2 <= '1'; -- high - when others => null; - end case; - end if; - end if; - end if; - end process; - O_CB1 <= sr_cb1_out; - O_CB1_OE_L <= sr_cb1_oe_l; - - p_ca_cb_irq : process(RESET_L, CLK) - begin - if (RESET_L = '0') then - ca1_irq <= '0'; - ca2_irq <= '0'; - cb1_irq <= '0'; - cb2_irq <= '0'; - elsif rising_edge(CLK) then - if (ENA_4 = '1') then - -- not pretty - if ca1_int then - ca1_irq <= '1'; - elsif (r_ira_hs = '1') or (w_ora_hs = '1') or (clear_irq(1) = '1') then - ca1_irq <= '0'; - end if; - - if ca2_int then - ca2_irq <= '1'; - else - if (((r_ira_hs = '1') or (w_ora_hs = '1')) and (r_pcr(1) = '0')) or - (clear_irq(0) = '1') then - ca2_irq <= '0'; - end if; - end if; - - if cb1_int then - cb1_irq <= '1'; - elsif (r_irb_hs = '1') or (w_orb_hs = '1') or (clear_irq(4) = '1') then - cb1_irq <= '0'; - end if; - - if cb2_int then - cb2_irq <= '1'; - else - if (((r_irb_hs = '1') or (w_orb_hs = '1')) and (r_pcr(5) = '0')) or - (clear_irq(3) = '1') then - cb2_irq <= '0'; - end if; - end if; - end if; - end if; - end process; - - p_input_reg : process(RESET_L, CLK) - begin - if (RESET_L = '0') then - ca1_ip_reg <= '0'; - cb1_ip_reg <= '0'; - - ca2_ip_reg <= '0'; - cb2_ip_reg <= '0'; - - r_ira <= x"00"; - r_irb <= x"00"; - - elsif rising_edge(CLK) then - if (ENA_4 = '1') then - -- we have a fast clock, so we can have input registers - ca1_ip_reg <= I_CA1; - cb1_ip_reg <= cb1_in_mux; - - ca2_ip_reg <= I_CA2; - cb2_ip_reg <= I_CB2; - - if (r_acr(0) = '0') then - r_ira <= I_PA; - else -- enable latching - if ca1_int then - r_ira <= I_PA; - end if; - end if; - - if (r_acr(1) = '0') then - r_irb <= I_PB; - else -- enable latching - if cb1_int then - r_irb <= I_PB; - end if; - end if; - end if; - end if; - end process; - - - p_buffers : process(r_ddra, r_ora, r_ddrb, r_acr, r_orb) - begin - -- data direction reg (ddr) 0 = input, 1 = output - O_PA <= r_ora; - O_PA_OE_L <= not r_ddra; - - if (r_acr(7) = '1') then -- not clear if r_ddrb(7) must be 1 as well - O_PB_OE_L(7) <= '0'; -- an output if under t1 control - else - O_PB_OE_L(7) <= not (r_ddrb(7)); - end if; - - O_PB_OE_L(6 downto 0) <= not r_ddrb(6 downto 0); - O_PB(7 downto 0) <= r_orb(7 downto 0); - - end process; - -- - -- Timer 1 - -- - p_timer1_done : process(t1c,phase,r_acr) - variable done : boolean; - begin - done := (t1c = x"0000"); - t1c_done <= done and (phase = "11"); - --if (phase = "11") then - t1_reload_counter <= done and (r_acr(6) = '1'); - --end if; - end process; - - p_timer1 : process - begin - wait until rising_edge(CLK); - if (ENA_4 = '1') then - if t1_load_counter or (t1_reload_counter and phase = "11") then - t1c( 7 downto 0) <= r_t1l_l; - t1c(15 downto 8) <= r_t1l_h; - elsif (phase="11") then - t1c <= t1c - "1"; - end if; - - if t1_load_counter or t1_reload_counter then - t1c_active <= true; - elsif t1c_done then - t1c_active <= false; - end if; - if RESET_L = '0' then - t1c_active <= false; - end if; - - t1_toggle <= '0'; - if t1c_active and t1c_done then - t1_toggle <= '1'; - t1_irq <= '1'; - elsif RESET_L = '0' or t1_w_reset_int or t1_r_reset_int or (clear_irq(6) = '1') then - t1_irq <= '0'; - end if; - end if; - end process; - -- - -- Timer2 - -- - p_timer2_pb6_input : process - begin - wait until rising_edge(CLK); - if (ENA_4 = '1') then - if (phase = "01") then -- leading edge p2_h - t2_pb6 <= I_PB(6); - t2_pb6_t1 <= t2_pb6; - end if; - end if; - end process; - - p_timer2_done : process(t2c,phase) - variable done : boolean; - begin - done := (t2c = x"0000"); - t2c_done <= done and (phase = "11"); - --if (phase = "11") then - t2_reload_counter <= done; - --end if; - end process; - - p_timer2 : process - variable ena : boolean; - begin - wait until rising_edge(CLK); - if (ENA_4 = '1') then - if (r_acr(5) = '0') then - ena := true; - else - ena := (t2_pb6_t1 = '1') and (t2_pb6 = '0'); -- falling edge - end if; - - if t2_load_counter or (t2_reload_counter and phase = "11") then - -- not sure if t2c_reload should be here. Does timer2 just continue to - -- count down, or is it reloaded ? Reloaded makes more sense if using - -- it to generate a clock for the shift register. - t2c( 7 downto 0) <= r_t2l_l; - t2c(15 downto 8) <= r_t2l_h; - else - if (phase="11") and ena then -- or count mode - t2c <= t2c - "1"; - end if; - end if; - - t2_sr_ena <= (t2c(7 downto 0) = x"00") and (phase = "11"); - - if t2_load_counter then - t2c_active <= true; - elsif t2c_done then - t2c_active <= false; - end if; - if RESET_L = '0' then - t2c_active <= false; - end if; - - if t2c_active and t2c_done then - t2_irq <= '1'; - elsif RESET_L = '0' or t2_w_reset_int or t2_r_reset_int or (clear_irq(5) = '1') then - t2_irq <= '0'; - end if; - end if; - end process; - -- - -- Shift Register - -- - p_sr : process(RESET_L, CLK) - variable dir_out : std_logic; - variable ena : std_logic; - variable cb1_op : std_logic; - variable cb1_ip : std_logic; - variable use_t2 : std_logic; - variable free_run : std_logic; - variable sr_count_ena : boolean; - begin - if (RESET_L = '0') then - r_sr <= x"00"; - sr_drive_cb2 <= '0'; - sr_cb1_oe_l <= '1'; - sr_cb1_out <= '0'; - sr_strobe <= '1'; - sr_cnt <= "0000"; - sr_irq <= '0'; - sr_out <= '1'; - sr_off_delay <= '0'; - elsif rising_edge(CLK) then - if (ENA_4 = '1') then - -- decode mode - dir_out := r_acr(4); -- output on cb2 - cb1_op := '0'; - cb1_ip := '0'; - use_t2 := '0'; - free_run := '0'; - - case r_acr(4 downto 2) is - when "000" => ena := '0'; cb1_ip := '1'; - when "001" => ena := '1'; cb1_op := '1'; use_t2 := '1'; - when "010" => ena := '1'; cb1_op := '1'; - when "011" => ena := '1'; cb1_ip := '1'; - when "100" => ena := '1'; use_t2 := '1'; free_run := '1'; - when "101" => ena := '1'; cb1_op := '1'; use_t2 := '1'; - when "110" => ena := '1'; - when "111" => ena := '1'; cb1_ip := '1'; - when others => null; - end case; - - -- clock select - -- SR still runs even in disabled mode (on rising edge of CB1). It - -- just doesn't generate any interrupts. - -- Ref BBC micro advanced user guide p409 - if (cb1_ip = '1') then - sr_strobe <= I_CB1; - else - if (sr_cnt(3) = '0') and (free_run = '0') then - sr_strobe <= '1'; - else - if ((use_t2 = '1') and t2_sr_ena) or - ((use_t2 = '0') and (phase = "00")) then - sr_strobe <= not sr_strobe; - end if; - end if; - end if; - - -- latch on rising edge, shift on falling edge - if sr_write_ena then - r_sr <= load_data; - else - if (dir_out = '0') then - -- input - if (sr_cnt(3) = '1') or (cb1_ip = '1') then - if sr_strobe_rising then - r_sr <= r_sr(6 downto 0) & I_CB2; - end if; - end if; - sr_out <= '1'; - else - -- output - if (sr_cnt(3) = '1') or (sr_off_delay = '1') or (cb1_ip = '1') or (free_run = '1') then - if sr_strobe_falling then - r_sr(7 downto 1) <= r_sr(6 downto 0); - r_sr(0) <= r_sr(7); - sr_out <= r_sr(7); - end if; - else - sr_out <= '1'; - end if; - end if; - end if; - - sr_count_ena := sr_strobe_rising; - - if sr_write_ena or sr_read_ena then - -- some documentation says sr bit in IFR must be set as well ? - sr_cnt <= "1000"; - elsif sr_count_ena and (sr_cnt(3) = '1') then - sr_cnt <= sr_cnt + "1"; - end if; - - if (phase = "00") then - sr_off_delay <= sr_cnt(3); -- give some hold time when shifting out - end if; - - if sr_count_ena and (sr_cnt = "1111") and (ena = '1') and (free_run = '0') then - sr_irq <= '1'; - elsif sr_write_ena or sr_read_ena or (clear_irq(2) = '1') then - sr_irq <= '0'; - end if; - - -- assign ops - sr_drive_cb2 <= dir_out; - sr_cb1_oe_l <= not cb1_op; - sr_cb1_out <= sr_strobe; - end if; - end if; - end process; - - p_sr_strobe_rise_fall : process - begin - wait until rising_edge(CLK); - if (ENA_4 = '1') then - sr_strobe_t1 <= sr_strobe; - sr_strobe_rising <= (sr_strobe_t1 = '0') and (sr_strobe = '1'); - sr_strobe_falling <= (sr_strobe_t1 = '1') and (sr_strobe = '0'); - end if; - end process; - -- - -- Interrupts - -- - p_ier : process(RESET_L, CLK) - begin - if (RESET_L = '0') then - r_ier <= "0000000"; - elsif rising_edge(CLK) then - if (ENA_4 = '1') then - if ier_write_ena then - if (load_data(7) = '1') then - -- set - r_ier <= r_ier or load_data(6 downto 0); - else - -- clear - r_ier <= r_ier and not load_data(6 downto 0); - end if; - end if; - end if; - end if; - end process; - - p_ifr : process(t1_irq, t2_irq, final_irq, ca1_irq, ca2_irq, sr_irq, - cb1_irq, cb2_irq) - begin - r_ifr(7) <= final_irq; - r_ifr(6) <= t1_irq; - r_ifr(5) <= t2_irq; - r_ifr(4) <= cb1_irq; - r_ifr(3) <= cb2_irq; - r_ifr(2) <= sr_irq; - r_ifr(1) <= ca1_irq; - r_ifr(0) <= ca2_irq; - - O_IRQ_L <= not final_irq; - end process; - - p_irq : process(RESET_L, CLK) - begin - if (RESET_L = '0') then - final_irq <= '0'; - elsif rising_edge(CLK) then - if (ENA_4 = '1') then - if ((r_ifr(6 downto 0) and r_ier(6 downto 0)) = "0000000") then - final_irq <= '0'; -- no interrupts - else - final_irq <= '1'; - end if; - end if; - end if; - end process; - - p_clear_irq : process(ifr_write_ena, load_data) - begin - clear_irq <= x"00"; - if ifr_write_ena then - clear_irq <= load_data; - end if; - end process; - -end architecture RTL; +-- +-- A simulation model of VIC20 hardware +-- Copyright (c) MikeJ - March 2003 +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- You are responsible for any legal issues arising from your use of this code. +-- +-- The latest version of this file can be found at: www.fpgaarcade.com +-- +-- Email vic20@fpgaarcade.com +-- +-- +-- Revision list +-- +-- version 002 fix from Mark McDougall, untested +-- version 001 initial release +-- not very sure about the shift register, documentation is a bit light. + +library ieee ; + use ieee.std_logic_1164.all ; + use ieee.std_logic_unsigned.all; + use ieee.numeric_std.all; + +--library UNISIM; +-- use UNISIM.Vcomponents.all; + +entity M6522 is + port ( + + I_RS : in std_logic_vector(3 downto 0); + I_DATA : in std_logic_vector(7 downto 0); + O_DATA : out std_logic_vector(7 downto 0); + O_DATA_OE_L : out std_logic; + + I_RW_L : in std_logic; + I_CS1 : in std_logic; + I_CS2_L : in std_logic; + + O_IRQ_L : out std_logic; -- note, not open drain + -- port a + I_CA1 : in std_logic; + I_CA2 : in std_logic; + O_CA2 : out std_logic; + O_CA2_OE_L : out std_logic; + + I_PA : in std_logic_vector(7 downto 0); + O_PA : out std_logic_vector(7 downto 0); + O_PA_OE_L : out std_logic_vector(7 downto 0); + + -- port b + I_CB1 : in std_logic; + O_CB1 : out std_logic; + O_CB1_OE_L : out std_logic; + + I_CB2 : in std_logic; + O_CB2 : out std_logic; + O_CB2_OE_L : out std_logic; + + I_PB : in std_logic_vector(7 downto 0); + O_PB : out std_logic_vector(7 downto 0); + O_PB_OE_L : out std_logic_vector(7 downto 0); + + I_P2_H : in std_logic; -- high for phase 2 clock ____----__ + RESET_L : in std_logic; + ENA_4 : in std_logic; -- clk enable + CLK : in std_logic + ); +end; + +architecture RTL of M6522 is + + signal phase : std_logic_vector(1 downto 0); + signal p2_h_t1 : std_logic; + signal cs : std_logic; + + -- registers + signal r_ddra : std_logic_vector(7 downto 0); + signal r_ora : std_logic_vector(7 downto 0); + signal r_ira : std_logic_vector(7 downto 0); + + signal r_ddrb : std_logic_vector(7 downto 0); + signal r_orb : std_logic_vector(7 downto 0); + signal r_irb : std_logic_vector(7 downto 0); + + signal r_t1l_l : std_logic_vector(7 downto 0); + signal r_t1l_h : std_logic_vector(7 downto 0); + signal r_t2l_l : std_logic_vector(7 downto 0); + signal r_t2l_h : std_logic_vector(7 downto 0); -- not in real chip + signal r_sr : std_logic_vector(7 downto 0); + signal r_acr : std_logic_vector(7 downto 0); + signal r_pcr : std_logic_vector(7 downto 0); + signal r_ifr : std_logic_vector(7 downto 0); + signal r_ier : std_logic_vector(6 downto 0); + + signal sr_write_ena : boolean; + signal sr_read_ena : boolean; + signal ifr_write_ena : boolean; + signal ier_write_ena : boolean; + signal clear_irq : std_logic_vector(7 downto 0); + signal load_data : std_logic_vector(7 downto 0); + + -- timer 1 + signal t1c : std_logic_vector(15 downto 0); + signal t1c_active : boolean; + signal t1c_done : boolean; + signal t1_w_reset_int : boolean; + signal t1_r_reset_int : boolean; + signal t1_load_counter : boolean; + signal t1_reload_counter : boolean; + signal t1_toggle : std_logic; + signal t1_irq : std_logic := '0'; + + -- timer 2 + signal t2c : std_logic_vector(15 downto 0); + signal t2c_active : boolean; + signal t2c_done : boolean; + signal t2_pb6 : std_logic; + signal t2_pb6_t1 : std_logic; + signal t2_w_reset_int : boolean; + signal t2_r_reset_int : boolean; + signal t2_load_counter : boolean; + signal t2_reload_counter : boolean; + signal t2_irq : std_logic := '0'; + signal t2_sr_ena : boolean; + + -- shift reg + signal sr_cnt : std_logic_vector(3 downto 0); + signal sr_cb1_oe_l : std_logic; + signal sr_cb1_out : std_logic; + signal sr_drive_cb2 : std_logic; + signal sr_strobe : std_logic; + signal sr_strobe_t1 : std_logic; + signal sr_strobe_falling : boolean; + signal sr_strobe_rising : boolean; + signal sr_irq : std_logic; + signal sr_out : std_logic; + signal sr_off_delay : std_logic; + + -- io + signal w_orb_hs : std_logic; + signal w_ora_hs : std_logic; + signal r_irb_hs : std_logic; + signal r_ira_hs : std_logic; + + signal ca_hs_sr : std_logic; + signal ca_hs_pulse : std_logic; + signal cb_hs_sr : std_logic; + signal cb_hs_pulse : std_logic; + + signal cb1_in_mux : std_logic; + signal ca1_ip_reg : std_logic; + signal cb1_ip_reg : std_logic; + signal ca1_int : boolean; + signal cb1_int : boolean; + signal ca1_irq : std_logic; + signal cb1_irq : std_logic; + + signal ca2_ip_reg : std_logic; + signal cb2_ip_reg : std_logic; + signal ca2_int : boolean; + signal cb2_int : boolean; + signal ca2_irq : std_logic; + signal cb2_irq : std_logic; + + signal final_irq : std_logic; +begin + p_phase : process + begin + -- internal clock phase + wait until rising_edge(CLK); + if (ENA_4 = '1') then + p2_h_t1 <= I_P2_H; + if (p2_h_t1 = '0') and (I_P2_H = '1') then + phase <= "11"; + else + phase <= phase + "1"; + end if; + end if; + end process; + + p_cs : process(I_CS1, I_CS2_L, I_P2_H) + begin + cs <= '0'; + if (I_CS1 = '1') and (I_CS2_L = '0') and (I_P2_H = '1') then + cs <= '1'; + end if; + end process; + + -- peripheral control reg (pcr) + -- 0 ca1 interrupt control (0 +ve edge, 1 -ve edge) + -- 3..1 ca2 operation + -- 000 input -ve edge + -- 001 independend interrupt input -ve edge + -- 010 input +ve edge + -- 011 independend interrupt input +ve edge + -- 100 handshake output + -- 101 pulse output + -- 110 low output + -- 111 high output + -- 7..4 as 3..0 for cb1,cb2 + + -- auxiliary control reg (acr) + -- 0 input latch PA (0 disable, 1 enable) + -- 1 input latch PB (0 disable, 1 enable) + -- 4..2 shift reg control + -- 000 disable + -- 001 shift in using t2 + -- 010 shift in using o2 + -- 011 shift in using ext clk + -- 100 shift out free running t2 rate + -- 101 shift out using t2 + -- 101 shift out using o2 + -- 101 shift out using ext clk + -- 5 t2 timer control (0 timed interrupt, 1 count down with pulses on pb6) + -- 7..6 t1 timer control + -- 00 timed interrupt each time t1 is loaded pb7 disable + -- 01 continuous interrupts pb7 disable + -- 00 timed interrupt each time t1 is loaded pb7 one shot output + -- 01 continuous interrupts pb7 square wave output + -- + + p_write_reg_reset : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + r_ora <= x"00"; r_orb <= x"00"; + r_ddra <= x"00"; r_ddrb <= x"00"; + r_acr <= x"00"; r_pcr <= x"00"; + + w_orb_hs <= '0'; + w_ora_hs <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + w_orb_hs <= '0'; + w_ora_hs <= '0'; + if (cs = '1') and (I_RW_L = '0') then + case I_RS is + when x"0" => r_orb <= I_DATA; w_orb_hs <= '1'; + when x"1" => r_ora <= I_DATA; w_ora_hs <= '1'; + when x"2" => r_ddrb <= I_DATA; + when x"3" => r_ddra <= I_DATA; + + when x"B" => r_acr <= I_DATA; + when x"C" => r_pcr <= I_DATA; + when x"F" => r_ora <= I_DATA; + + when others => null; + end case; + end if; + + if (r_acr(7) = '1') and (t1_toggle = '1') then + r_orb(7) <= not r_orb(7); -- toggle + end if; + end if; + end if; + end process; + + p_write_reg : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + t1_w_reset_int <= false; + t1_load_counter <= false; + + t2_w_reset_int <= false; + t2_load_counter <= false; + + load_data <= x"00"; + sr_write_ena <= false; + ifr_write_ena <= false; + ier_write_ena <= false; + + if (cs = '1') and (I_RW_L = '0') then + load_data <= I_DATA; + case I_RS is + when x"4" => r_t1l_l <= I_DATA; + when x"5" => r_t1l_h <= I_DATA; t1_w_reset_int <= true; + t1_load_counter <= true; + + when x"6" => r_t1l_l <= I_DATA; + when x"7" => r_t1l_h <= I_DATA; t1_w_reset_int <= true; + + when x"8" => r_t2l_l <= I_DATA; + when x"9" => r_t2l_h <= I_DATA; t2_w_reset_int <= true; + t2_load_counter <= true; + + when x"A" => sr_write_ena <= true; + when x"D" => ifr_write_ena <= true; + when x"E" => ier_write_ena <= true; + + when others => null; + end case; + end if; + end if; + end process; + + p_oe : process(cs, I_RW_L) + begin + O_DATA_OE_L <= '1'; + if (cs = '1') and (I_RW_L = '1') then + O_DATA_OE_L <= '0'; + end if; + end process; + + p_read : process + begin + wait until rising_edge(CLK); + + if ENA_4 = '1' then + t1_r_reset_int <= false; + t2_r_reset_int <= false; + sr_read_ena <= false; + r_irb_hs <= '0'; + r_ira_hs <= '0'; + + if (cs = '1') and (I_RW_L = '1') then + case I_RS is + --when x"0" => O_DATA <= r_irb; r_irb_hs <= '1'; + -- fix from Mark McDougall, untested + when x"0" => O_DATA <= (r_irb and not r_ddrb) or (r_orb and r_ddrb); r_irb_hs <= '1'; + when x"1" => O_DATA <= r_ira; r_ira_hs <= '1'; + when x"2" => O_DATA <= r_ddrb; + when x"3" => O_DATA <= r_ddra; + when x"4" => O_DATA <= t1c( 7 downto 0); t1_r_reset_int <= true; + when x"5" => O_DATA <= t1c(15 downto 8); + when x"6" => O_DATA <= r_t1l_l; + when x"7" => O_DATA <= r_t1l_h; + when x"8" => O_DATA <= t2c( 7 downto 0); t2_r_reset_int <= true; + when x"9" => O_DATA <= t2c(15 downto 8); + when x"A" => O_DATA <= r_sr; sr_read_ena <= true; + when x"B" => O_DATA <= r_acr; + when x"C" => O_DATA <= r_pcr; + when x"D" => O_DATA <= r_ifr; + when x"E" => O_DATA <= ('0' & r_ier); + when x"F" => O_DATA <= r_ira; + when others => null; + end case; + end if; + end if; + + end process; + -- + -- IO + -- + p_ca1_cb1_sel : process(sr_cb1_oe_l, sr_cb1_out, I_CB1) + begin + -- if the shift register is enabled, cb1 may be an output + -- in this case, we should listen to the CB1_OUT for the interrupt + if (sr_cb1_oe_l = '1') then + cb1_in_mux <= I_CB1; + else + cb1_in_mux <= sr_cb1_out; + end if; + end process; + + p_ca1_cb1_int : process(r_pcr, ca1_ip_reg, I_CA1, cb1_ip_reg, cb1_in_mux) + begin + if (r_pcr(0) = '0') then -- ca1 control + -- negative edge + ca1_int <= (ca1_ip_reg = '1') and (I_CA1 = '0'); + else + -- positive edge + ca1_int <= (ca1_ip_reg = '0') and (I_CA1 = '1'); + end if; + + if (r_pcr(4) = '0') then -- cb1 control + -- negative edge + cb1_int <= (cb1_ip_reg = '1') and (cb1_in_mux = '0'); + else + -- positive edge + cb1_int <= (cb1_ip_reg = '0') and (cb1_in_mux = '1'); + end if; + end process; + + p_ca2_cb2_int : process(r_pcr, ca2_ip_reg, I_CA2, cb2_ip_reg, I_CB2) + begin + ca2_int <= false; + if (r_pcr(3) = '0') then -- ca2 input + if (r_pcr(2) = '0') then -- ca2 edge + -- negative edge + ca2_int <= (ca2_ip_reg = '1') and (I_CA2 = '0'); + else + -- positive edge + ca2_int <= (ca2_ip_reg = '0') and (I_CA2 = '1'); + end if; + end if; + + cb2_int <= false; + if (r_pcr(7) = '0') then -- cb2 input + if (r_pcr(6) = '0') then -- cb2 edge + -- negative edge + cb2_int <= (cb2_ip_reg = '1') and (I_CB2 = '0'); + else + -- positive edge + cb2_int <= (cb2_ip_reg = '0') and (I_CB2 = '1'); + end if; + end if; + end process; + + p_ca2_cb2 : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + O_CA2 <= '0'; + O_CA2_OE_L <= '1'; + O_CB2 <= '0'; + O_CB2_OE_L <= '1'; + + ca_hs_sr <= '0'; + ca_hs_pulse <= '0'; + cb_hs_sr <= '0'; + cb_hs_pulse <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- ca + if (phase = "00") and ((w_ora_hs = '1') or (r_ira_hs = '1')) then + ca_hs_sr <= '1'; + elsif ca1_int then + ca_hs_sr <= '0'; + end if; + + if (phase = "00") then + ca_hs_pulse <= w_ora_hs or r_ira_hs; + end if; + + O_CA2_OE_L <= not r_pcr(3); -- ca2 output + case r_pcr(3 downto 1) is + when "000" => O_CA2 <= '0'; -- input + when "001" => O_CA2 <= '0'; -- input + when "010" => O_CA2 <= '0'; -- input + when "011" => O_CA2 <= '0'; -- input + when "100" => O_CA2 <= not (ca_hs_sr); -- handshake + when "101" => O_CA2 <= not (ca_hs_pulse); -- pulse + when "110" => O_CA2 <= '0'; -- low + when "111" => O_CA2 <= '1'; -- high + when others => null; + end case; + + -- cb + if (phase = "00") and (w_orb_hs = '1') then + cb_hs_sr <= '1'; + elsif cb1_int then + cb_hs_sr <= '0'; + end if; + + if (phase = "00") then + cb_hs_pulse <= w_orb_hs; + end if; + + O_CB2_OE_L <= not (r_pcr(7) or sr_drive_cb2); -- cb2 output or serial + if (sr_drive_cb2 = '1') then -- serial output + O_CB2 <= sr_out; + else + case r_pcr(7 downto 5) is + when "000" => O_CB2 <= '0'; -- input + when "001" => O_CB2 <= '0'; -- input + when "010" => O_CB2 <= '0'; -- input + when "011" => O_CB2 <= '0'; -- input + when "100" => O_CB2 <= not (cb_hs_sr); -- handshake + when "101" => O_CB2 <= not (cb_hs_pulse); -- pulse + when "110" => O_CB2 <= '0'; -- low + when "111" => O_CB2 <= '1'; -- high + when others => null; + end case; + end if; + end if; + end if; + end process; + O_CB1 <= sr_cb1_out; + O_CB1_OE_L <= sr_cb1_oe_l; + + p_ca_cb_irq : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + ca1_irq <= '0'; + ca2_irq <= '0'; + cb1_irq <= '0'; + cb2_irq <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- not pretty + if ca1_int then + ca1_irq <= '1'; + elsif (r_ira_hs = '1') or (w_ora_hs = '1') or (clear_irq(1) = '1') then + ca1_irq <= '0'; + end if; + + if ca2_int then + ca2_irq <= '1'; + else + if (((r_ira_hs = '1') or (w_ora_hs = '1')) and (r_pcr(1) = '0')) or + (clear_irq(0) = '1') then + ca2_irq <= '0'; + end if; + end if; + + if cb1_int then + cb1_irq <= '1'; + elsif (r_irb_hs = '1') or (w_orb_hs = '1') or (clear_irq(4) = '1') then + cb1_irq <= '0'; + end if; + + if cb2_int then + cb2_irq <= '1'; + else + if (((r_irb_hs = '1') or (w_orb_hs = '1')) and (r_pcr(5) = '0')) or + (clear_irq(3) = '1') then + cb2_irq <= '0'; + end if; + end if; + end if; + end if; + end process; + + p_input_reg : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + ca1_ip_reg <= '0'; + cb1_ip_reg <= '0'; + + ca2_ip_reg <= '0'; + cb2_ip_reg <= '0'; + + r_ira <= x"00"; + r_irb <= x"00"; + + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- we have a fast clock, so we can have input registers + ca1_ip_reg <= I_CA1; + cb1_ip_reg <= cb1_in_mux; + + ca2_ip_reg <= I_CA2; + cb2_ip_reg <= I_CB2; + + if (r_acr(0) = '0') then + r_ira <= I_PA; + else -- enable latching + if ca1_int then + r_ira <= I_PA; + end if; + end if; + + if (r_acr(1) = '0') then + r_irb <= I_PB; + else -- enable latching + if cb1_int then + r_irb <= I_PB; + end if; + end if; + end if; + end if; + end process; + + + p_buffers : process(r_ddra, r_ora, r_ddrb, r_acr, r_orb) + begin + -- data direction reg (ddr) 0 = input, 1 = output + O_PA <= r_ora; + O_PA_OE_L <= not r_ddra; + + if (r_acr(7) = '1') then -- not clear if r_ddrb(7) must be 1 as well + O_PB_OE_L(7) <= '0'; -- an output if under t1 control + else + O_PB_OE_L(7) <= not (r_ddrb(7)); + end if; + + O_PB_OE_L(6 downto 0) <= not r_ddrb(6 downto 0); + O_PB(7 downto 0) <= r_orb(7 downto 0); + + end process; + -- + -- Timer 1 + -- + p_timer1_done : process(t1c,phase,r_acr) + variable done : boolean; + begin + done := (t1c = x"0000"); + t1c_done <= done and (phase = "11"); + --if (phase = "11") then + t1_reload_counter <= done and (r_acr(6) = '1'); + --end if; + end process; + + p_timer1 : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + if t1_load_counter or (t1_reload_counter and phase = "11") then + t1c( 7 downto 0) <= r_t1l_l; + t1c(15 downto 8) <= r_t1l_h; + elsif (phase="11") then + t1c <= t1c - "1"; + end if; + + if t1_load_counter or t1_reload_counter then + t1c_active <= true; + elsif t1c_done then + t1c_active <= false; + end if; + if RESET_L = '0' then + t1c_active <= false; + end if; + + t1_toggle <= '0'; + if t1c_active and t1c_done then + t1_toggle <= '1'; + t1_irq <= '1'; + elsif RESET_L = '0' or t1_w_reset_int or t1_r_reset_int or (clear_irq(6) = '1') then + t1_irq <= '0'; + end if; + end if; + end process; + -- + -- Timer2 + -- + p_timer2_pb6_input : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + if (phase = "01") then -- leading edge p2_h + t2_pb6 <= I_PB(6); + t2_pb6_t1 <= t2_pb6; + end if; + end if; + end process; + + p_timer2_done : process(t2c,phase) + variable done : boolean; + begin + done := (t2c = x"0000"); + t2c_done <= done and (phase = "11"); + --if (phase = "11") then + t2_reload_counter <= done; + --end if; + end process; + + p_timer2 : process + variable ena : boolean; + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + if (r_acr(5) = '0') then + ena := true; + else + ena := (t2_pb6_t1 = '1') and (t2_pb6 = '0'); -- falling edge + end if; + + if t2_load_counter or (t2_reload_counter and phase = "11") then + -- not sure if t2c_reload should be here. Does timer2 just continue to + -- count down, or is it reloaded ? Reloaded makes more sense if using + -- it to generate a clock for the shift register. + t2c( 7 downto 0) <= r_t2l_l; + t2c(15 downto 8) <= r_t2l_h; + else + if (phase="11") and ena then -- or count mode + t2c <= t2c - "1"; + end if; + end if; + + t2_sr_ena <= (t2c(7 downto 0) = x"00") and (phase = "11"); + + if t2_load_counter then + t2c_active <= true; + elsif t2c_done then + t2c_active <= false; + end if; + if RESET_L = '0' then + t2c_active <= false; + end if; + + if t2c_active and t2c_done then + t2_irq <= '1'; + elsif RESET_L = '0' or t2_w_reset_int or t2_r_reset_int or (clear_irq(5) = '1') then + t2_irq <= '0'; + end if; + end if; + end process; + -- + -- Shift Register + -- + p_sr : process(RESET_L, CLK) + variable dir_out : std_logic; + variable ena : std_logic; + variable cb1_op : std_logic; + variable cb1_ip : std_logic; + variable use_t2 : std_logic; + variable free_run : std_logic; + variable sr_count_ena : boolean; + begin + if (RESET_L = '0') then + r_sr <= x"00"; + sr_drive_cb2 <= '0'; + sr_cb1_oe_l <= '1'; + sr_cb1_out <= '0'; + sr_strobe <= '1'; + sr_cnt <= "0000"; + sr_irq <= '0'; + sr_out <= '1'; + sr_off_delay <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- decode mode + dir_out := r_acr(4); -- output on cb2 + cb1_op := '0'; + cb1_ip := '0'; + use_t2 := '0'; + free_run := '0'; + + case r_acr(4 downto 2) is + when "000" => ena := '0'; cb1_ip := '1'; + when "001" => ena := '1'; cb1_op := '1'; use_t2 := '1'; + when "010" => ena := '1'; cb1_op := '1'; + when "011" => ena := '1'; cb1_ip := '1'; + when "100" => ena := '1'; use_t2 := '1'; free_run := '1'; + when "101" => ena := '1'; cb1_op := '1'; use_t2 := '1'; + when "110" => ena := '1'; + when "111" => ena := '1'; cb1_ip := '1'; + when others => null; + end case; + + -- clock select + -- SR still runs even in disabled mode (on rising edge of CB1). It + -- just doesn't generate any interrupts. + -- Ref BBC micro advanced user guide p409 + if (cb1_ip = '1') then + sr_strobe <= I_CB1; + else + if (sr_cnt(3) = '0') and (free_run = '0') then + sr_strobe <= '1'; + else + if ((use_t2 = '1') and t2_sr_ena) or + ((use_t2 = '0') and (phase = "00")) then + sr_strobe <= not sr_strobe; + end if; + end if; + end if; + + -- latch on rising edge, shift on falling edge + if sr_write_ena then + r_sr <= load_data; + else + if (dir_out = '0') then + -- input + if (sr_cnt(3) = '1') or (cb1_ip = '1') then + if sr_strobe_rising then + r_sr <= r_sr(6 downto 0) & I_CB2; + end if; + end if; + sr_out <= '1'; + else + -- output + if (sr_cnt(3) = '1') or (sr_off_delay = '1') or (cb1_ip = '1') or (free_run = '1') then + if sr_strobe_falling then + r_sr(7 downto 1) <= r_sr(6 downto 0); + r_sr(0) <= r_sr(7); + sr_out <= r_sr(7); + end if; + else + sr_out <= '1'; + end if; + end if; + end if; + + sr_count_ena := sr_strobe_rising; + + if sr_write_ena or sr_read_ena then + -- some documentation says sr bit in IFR must be set as well ? + sr_cnt <= "1000"; + elsif sr_count_ena and (sr_cnt(3) = '1') then + sr_cnt <= sr_cnt + "1"; + end if; + + if (phase = "00") then + sr_off_delay <= sr_cnt(3); -- give some hold time when shifting out + end if; + + if sr_count_ena and (sr_cnt = "1111") and (ena = '1') and (free_run = '0') then + sr_irq <= '1'; + elsif sr_write_ena or sr_read_ena or (clear_irq(2) = '1') then + sr_irq <= '0'; + end if; + + -- assign ops + sr_drive_cb2 <= dir_out; + sr_cb1_oe_l <= not cb1_op; + sr_cb1_out <= sr_strobe; + end if; + end if; + end process; + + p_sr_strobe_rise_fall : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + sr_strobe_t1 <= sr_strobe; + sr_strobe_rising <= (sr_strobe_t1 = '0') and (sr_strobe = '1'); + sr_strobe_falling <= (sr_strobe_t1 = '1') and (sr_strobe = '0'); + end if; + end process; + -- + -- Interrupts + -- + p_ier : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + r_ier <= "0000000"; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + if ier_write_ena then + if (load_data(7) = '1') then + -- set + r_ier <= r_ier or load_data(6 downto 0); + else + -- clear + r_ier <= r_ier and not load_data(6 downto 0); + end if; + end if; + end if; + end if; + end process; + + p_ifr : process(t1_irq, t2_irq, final_irq, ca1_irq, ca2_irq, sr_irq, + cb1_irq, cb2_irq) + begin + r_ifr(7) <= final_irq; + r_ifr(6) <= t1_irq; + r_ifr(5) <= t2_irq; + r_ifr(4) <= cb1_irq; + r_ifr(3) <= cb2_irq; + r_ifr(2) <= sr_irq; + r_ifr(1) <= ca1_irq; + r_ifr(0) <= ca2_irq; + + O_IRQ_L <= not final_irq; + end process; + + p_irq : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + final_irq <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + if ((r_ifr(6 downto 0) and r_ier(6 downto 0)) = "0000000") then + final_irq <= '0'; -- no interrupts + else + final_irq <= '1'; + end if; + end if; + end if; + end process; + + p_clear_irq : process(ifr_write_ena, load_data) + begin + clear_irq <= x"00"; + if ifr_write_ena then + clear_irq <= load_data; + end if; + end process; + +end architecture RTL; diff --git a/m6522_tb.vhd b/m6522_tb.vhd index 3e4262d..30307d2 100644 --- a/m6522_tb.vhd +++ b/m6522_tb.vhd @@ -1,378 +1,378 @@ --- BBC Micro for Altera DE1 --- --- Copyright (c) 2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - -entity m6522_tb is -end entity; - -architecture tb of m6522_tb is - -component M6522 is - port ( - - I_RS : in std_logic_vector(3 downto 0); - I_DATA : in std_logic_vector(7 downto 0); - O_DATA : out std_logic_vector(7 downto 0); - O_DATA_OE_L : out std_logic; - - I_RW_L : in std_logic; - I_CS1 : in std_logic; - I_CS2_L : in std_logic; - - O_IRQ_L : out std_logic; -- note, not open drain - -- port a - I_CA1 : in std_logic; - I_CA2 : in std_logic; - O_CA2 : out std_logic; - O_CA2_OE_L : out std_logic; - - I_PA : in std_logic_vector(7 downto 0); - O_PA : out std_logic_vector(7 downto 0); - O_PA_OE_L : out std_logic_vector(7 downto 0); - - -- port b - I_CB1 : in std_logic; - O_CB1 : out std_logic; - O_CB1_OE_L : out std_logic; - - I_CB2 : in std_logic; - O_CB2 : out std_logic; - O_CB2_OE_L : out std_logic; - - I_PB : in std_logic_vector(7 downto 0); - O_PB : out std_logic_vector(7 downto 0); - O_PB_OE_L : out std_logic_vector(7 downto 0); - - I_P2_H : in std_logic; -- high for phase 2 clock ____----__ - RESET_L : in std_logic; - ENA_4 : in std_logic; -- clk enable - CLK : in std_logic - ); -end component; - -signal rs : std_logic_vector(3 downto 0) := "0000"; -signal di : std_logic_vector(7 downto 0) := "00000000"; -signal do : std_logic_vector(7 downto 0); -signal n_d_oe : std_logic; -signal r_nw : std_logic := '1'; -signal cs1 : std_logic := '0'; -signal n_cs2 : std_logic := '0'; -signal n_irq : std_logic; -signal ca1_in : std_logic := '0'; -signal ca2_in : std_logic := '0'; -signal ca2_out : std_logic; -signal n_ca2_oe : std_logic; -signal pa_in : std_logic_vector(7 downto 0) := "00000000"; -signal pa_out : std_logic_vector(7 downto 0); -signal n_pa_oe : std_logic_vector(7 downto 0); -signal cb1_in : std_logic := '0'; -signal cb1_out : std_logic; -signal n_cb1_oe : std_logic; -signal cb2_in : std_logic := '0'; -signal cb2_out : std_logic; -signal n_cb2_oe : std_logic; -signal pb_in : std_logic_vector(7 downto 0) := "00000000"; -signal pb_out : std_logic_vector(7 downto 0); -signal n_pb_oe : std_logic_vector(7 downto 0); - -signal phase2 : std_logic := '0'; -signal n_reset : std_logic := '0'; -signal clken : std_logic := '0'; -signal clock : std_logic := '0'; - -begin - - uut: m6522 port map ( - rs, di, do, n_d_oe, - r_nw, cs1, n_cs2, n_irq, - ca1_in, ca2_in, ca2_out, n_ca2_oe, - pa_in, pa_out, n_pa_oe, - cb1_in, cb1_out, n_cb1_oe, - cb2_in, cb2_out, n_cb2_oe, - pb_in, pb_out, n_pb_oe, - phase2, n_reset, clken, clock - ); - - clock <= not clock after 125 ns; -- 4x 1 MHz - phase2 <= not phase2 after 500 ns; - clken <= '1'; -- all cycles enabled - - process - begin - wait for 1 us; - -- Release reset - n_reset <= '1'; - end process; - - process - - procedure reg_write( - a : in std_logic_vector(3 downto 0); - d : in std_logic_vector(7 downto 0)) is - begin - wait until falling_edge(phase2); - rs <= a; - di <= d; - cs1 <= '1'; - r_nw <= '0'; - wait until falling_edge(phase2); - cs1 <= '0'; - r_nw <= '1'; - end procedure; - - procedure reg_read( - a : in std_logic_vector(3 downto 0)) is - begin - wait until falling_edge(phase2); - rs <= a; - cs1 <= '1'; - r_nw <= '1'; - wait until falling_edge(phase2); - cs1 <= '0'; - end procedure; - - begin - wait for 2 us; - - -- Set port A and B to output - reg_write("0010","11111111"); - reg_write("0011","11111111"); - - -- Write to port B - reg_write("0000","10101010"); - -- Write to port B - reg_write("0000","01010101"); - -- Write to port A (no handshake) - reg_write("1111","10101010"); - -- Write to port A (with handshake) - reg_write("0001","01010101"); - - -- Set port A and B to input - reg_write("0010","00000000"); - reg_write("0011","00000000"); - - -- Apply input stimuli and read from ports - pa_in <= "10101010"; - pb_in <= "01010101"; - reg_read("0000"); - reg_read("0001"); - - -- Test CA1 interrupt - ca1_in <= '0'; - reg_write("1100","00000001"); -- PCR - interrupt on rising edge - reg_write("1101","01111111"); -- Clear interrupts - reg_write("1110","01111111"); -- Disable all interrupts - reg_write("1110","10000010"); -- Enable CA1 interrupt - ca1_in <= '1'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("0001"); -- Should clear interrupt - wait for 2 us; - reg_write("1100","00000000"); -- PCR - interrupt on falling edge - ca1_in <= '0'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_write("1101","00000010"); -- Should clear interrupt - wait for 2 us; - reg_write("1110","00000010"); -- Disable CA1 interrupt - - -- Test CB1 interrupt - cb1_in <= '0'; - reg_write("1100","00010000"); -- PCR - interrupt on rising edge - reg_write("1101","01111111"); -- Clear interrupts - reg_write("1110","01111111"); -- Disable all interrupts - reg_write("1110","10010000"); -- Enable CB1 interrupt - cb1_in <= '1'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("0000"); -- Should clear interrupt - wait for 2 us; - reg_write("1100","00000000"); -- PCR - interrupt on falling edge - cb1_in <= '0'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_write("1101","00010000"); -- Should clear interrupt - wait for 2 us; - reg_write("1110","00010000"); -- Disable CA1 interrupt - - -- Test CA2 interrupt modes - reg_write("1101","01111111"); -- Clear interrupts - reg_write("1110","01111111"); -- Disable all interrupts - reg_write("1110","10000001"); -- Enable CA2 interrupt - -- mode 2 (+ve edge, clear on read/write) - reg_write("1100","00000100"); -- PCR - ca2_in <= '1'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("1111"); -- Should not clear interrupt - reg_read("0001"); -- Should clear interrupt - wait for 2 us; - -- mode 0 (-ve edge, clear on read/write) - reg_write("1100","00000000"); -- PCR - ca2_in <= '0'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("1111"); -- Should not clear interrupt - reg_read("0001"); -- Should clear interrupt - wait for 2 us; - -- mode 3 (+ve edge, don't clear on read/write) - reg_write("1100","00000110"); - ca2_in <= '1'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("1111"); -- Should not clear interrupt - reg_read("0001"); -- Should not clear interrupt - reg_write("1101","00000001"); -- Should clear interrupt - wait for 2 us; - -- mode 1 (-ve edge, don't clear on read/write) - reg_write("1100","00000010"); - ca2_in <= '0'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("1111"); -- Should not clear interrupt - reg_read("0001"); -- Should not clear interrupt - reg_write("1101","00000001"); -- Should clear interrupt - wait for 2 us; - - -- Test CA2 output modes - -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge) - reg_write("1100","00001000"); - -- mode 5 (set low for 1 cycle on read/write ORA) - reg_write("1100","00001010"); - -- mode 6 (held low) - reg_write("1100","00001100"); - -- mode 7 (held high) - reg_write("1100","00001110"); - - -- Test CB2 interrupt modes - reg_write("1101","01111111"); -- Clear interrupts - reg_write("1110","01111111"); -- Disable all interrupts - reg_write("1110","10001000"); -- Enable CB2 interrupt - -- mode 2 (+ve edge, clear on read/write) - reg_write("1100","01000000"); -- PCR - cb2_in <= '1'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("0000"); -- Should clear interrupt - wait for 2 us; - -- mode 0 (-ve edge, clear on read/write) - reg_write("1100","00000000"); -- PCR - cb2_in <= '0'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("0000"); -- Should clear interrupt - wait for 2 us; - -- mode 3 (+ve edge, don't clear on read/write) - reg_write("1100","01100000"); - cb2_in <= '1'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("0000"); -- Should not clear interrupt - reg_write("1101","00001000"); -- Should clear interrupt - wait for 2 us; - -- mode 1 (-ve edge, don't clear on read/write) - reg_write("1100","00100000"); - cb2_in <= '0'; -- Trigger event - wait for 2 us; - reg_read("1101"); - reg_read("0000"); -- Should not clear interrupt - reg_write("1101","00001000"); -- Should clear interrupt - wait for 2 us; - - -- Test CB2 output modes - -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge) - reg_write("1100","10000000"); - -- mode 5 (set low for 1 cycle on read/write ORA) - reg_write("1100","10100000"); - -- mode 6 (held low) - reg_write("1100","11000000"); - -- mode 7 (held high) - reg_write("1100","11100000"); - - -- Timer 1 timeout - reg_write("1101","01111111"); -- Clear interrupts - reg_write("1110","01111111"); -- Disable all interrupts - reg_write("1110","11000000"); -- Enable timer 1 interrupt - -- Count to 16 - reg_write("0100","00010000"); - reg_write("0101","00000000"); - wait for 50 us; - -- Count to 16 - reg_write("0100","00010000"); - reg_write("0101","00000000"); -- Should clear interrupt - wait for 50 us; - reg_read("0100"); -- Should clear interrupt - - -- Timer 2 timeout - reg_write("1101","01111111"); -- Clear interrupts - reg_write("1110","01111111"); -- Disable all interrupts - reg_write("1110","10100000"); -- Enable timer 2 interrupt - -- Count to 16 - reg_write("1000","00010000"); - reg_write("1001","00000000"); - wait for 50 us; - -- Count to 16 - reg_write("1000","00010000"); - reg_write("1001","00000000"); -- Should clear interrupt - wait for 50 us; - reg_read("1000"); -- Should clear interrupt - - -- Timer 2 test similar to BBC usage (speech interrupt) - -- PB6 high - pb_in(6) <= '1'; - reg_write("1101","01111111"); -- Clear interrupts - reg_write("1110","01111111"); -- Disable all interrupts - reg_write("1011","00100000"); -- Timer 2 PB6 counter mode - reg_write("1000","00000001"); -- Start at 1 - reg_write("1001","00000000"); - reg_write("1110","10100000"); -- Enable timer 2 interrupt - wait for 5 us; - -- Generate falling edge - pb_in(6) <= '0'; - wait for 5 us; - -- Clear interrupt - reg_write("1101","00100000"); - -- Zero timer high byte - reg_write("1001","00000000"); - - wait; - end process; - -end architecture; +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity m6522_tb is +end entity; + +architecture tb of m6522_tb is + +component M6522 is + port ( + + I_RS : in std_logic_vector(3 downto 0); + I_DATA : in std_logic_vector(7 downto 0); + O_DATA : out std_logic_vector(7 downto 0); + O_DATA_OE_L : out std_logic; + + I_RW_L : in std_logic; + I_CS1 : in std_logic; + I_CS2_L : in std_logic; + + O_IRQ_L : out std_logic; -- note, not open drain + -- port a + I_CA1 : in std_logic; + I_CA2 : in std_logic; + O_CA2 : out std_logic; + O_CA2_OE_L : out std_logic; + + I_PA : in std_logic_vector(7 downto 0); + O_PA : out std_logic_vector(7 downto 0); + O_PA_OE_L : out std_logic_vector(7 downto 0); + + -- port b + I_CB1 : in std_logic; + O_CB1 : out std_logic; + O_CB1_OE_L : out std_logic; + + I_CB2 : in std_logic; + O_CB2 : out std_logic; + O_CB2_OE_L : out std_logic; + + I_PB : in std_logic_vector(7 downto 0); + O_PB : out std_logic_vector(7 downto 0); + O_PB_OE_L : out std_logic_vector(7 downto 0); + + I_P2_H : in std_logic; -- high for phase 2 clock ____----__ + RESET_L : in std_logic; + ENA_4 : in std_logic; -- clk enable + CLK : in std_logic + ); +end component; + +signal rs : std_logic_vector(3 downto 0) := "0000"; +signal di : std_logic_vector(7 downto 0) := "00000000"; +signal do : std_logic_vector(7 downto 0); +signal n_d_oe : std_logic; +signal r_nw : std_logic := '1'; +signal cs1 : std_logic := '0'; +signal n_cs2 : std_logic := '0'; +signal n_irq : std_logic; +signal ca1_in : std_logic := '0'; +signal ca2_in : std_logic := '0'; +signal ca2_out : std_logic; +signal n_ca2_oe : std_logic; +signal pa_in : std_logic_vector(7 downto 0) := "00000000"; +signal pa_out : std_logic_vector(7 downto 0); +signal n_pa_oe : std_logic_vector(7 downto 0); +signal cb1_in : std_logic := '0'; +signal cb1_out : std_logic; +signal n_cb1_oe : std_logic; +signal cb2_in : std_logic := '0'; +signal cb2_out : std_logic; +signal n_cb2_oe : std_logic; +signal pb_in : std_logic_vector(7 downto 0) := "00000000"; +signal pb_out : std_logic_vector(7 downto 0); +signal n_pb_oe : std_logic_vector(7 downto 0); + +signal phase2 : std_logic := '0'; +signal n_reset : std_logic := '0'; +signal clken : std_logic := '0'; +signal clock : std_logic := '0'; + +begin + + uut: m6522 port map ( + rs, di, do, n_d_oe, + r_nw, cs1, n_cs2, n_irq, + ca1_in, ca2_in, ca2_out, n_ca2_oe, + pa_in, pa_out, n_pa_oe, + cb1_in, cb1_out, n_cb1_oe, + cb2_in, cb2_out, n_cb2_oe, + pb_in, pb_out, n_pb_oe, + phase2, n_reset, clken, clock + ); + + clock <= not clock after 125 ns; -- 4x 1 MHz + phase2 <= not phase2 after 500 ns; + clken <= '1'; -- all cycles enabled + + process + begin + wait for 1 us; + -- Release reset + n_reset <= '1'; + end process; + + process + + procedure reg_write( + a : in std_logic_vector(3 downto 0); + d : in std_logic_vector(7 downto 0)) is + begin + wait until falling_edge(phase2); + rs <= a; + di <= d; + cs1 <= '1'; + r_nw <= '0'; + wait until falling_edge(phase2); + cs1 <= '0'; + r_nw <= '1'; + end procedure; + + procedure reg_read( + a : in std_logic_vector(3 downto 0)) is + begin + wait until falling_edge(phase2); + rs <= a; + cs1 <= '1'; + r_nw <= '1'; + wait until falling_edge(phase2); + cs1 <= '0'; + end procedure; + + begin + wait for 2 us; + + -- Set port A and B to output + reg_write("0010","11111111"); + reg_write("0011","11111111"); + + -- Write to port B + reg_write("0000","10101010"); + -- Write to port B + reg_write("0000","01010101"); + -- Write to port A (no handshake) + reg_write("1111","10101010"); + -- Write to port A (with handshake) + reg_write("0001","01010101"); + + -- Set port A and B to input + reg_write("0010","00000000"); + reg_write("0011","00000000"); + + -- Apply input stimuli and read from ports + pa_in <= "10101010"; + pb_in <= "01010101"; + reg_read("0000"); + reg_read("0001"); + + -- Test CA1 interrupt + ca1_in <= '0'; + reg_write("1100","00000001"); -- PCR - interrupt on rising edge + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10000010"); -- Enable CA1 interrupt + ca1_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0001"); -- Should clear interrupt + wait for 2 us; + reg_write("1100","00000000"); -- PCR - interrupt on falling edge + ca1_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_write("1101","00000010"); -- Should clear interrupt + wait for 2 us; + reg_write("1110","00000010"); -- Disable CA1 interrupt + + -- Test CB1 interrupt + cb1_in <= '0'; + reg_write("1100","00010000"); -- PCR - interrupt on rising edge + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10010000"); -- Enable CB1 interrupt + cb1_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should clear interrupt + wait for 2 us; + reg_write("1100","00000000"); -- PCR - interrupt on falling edge + cb1_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_write("1101","00010000"); -- Should clear interrupt + wait for 2 us; + reg_write("1110","00010000"); -- Disable CA1 interrupt + + -- Test CA2 interrupt modes + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10000001"); -- Enable CA2 interrupt + -- mode 2 (+ve edge, clear on read/write) + reg_write("1100","00000100"); -- PCR + ca2_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("1111"); -- Should not clear interrupt + reg_read("0001"); -- Should clear interrupt + wait for 2 us; + -- mode 0 (-ve edge, clear on read/write) + reg_write("1100","00000000"); -- PCR + ca2_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("1111"); -- Should not clear interrupt + reg_read("0001"); -- Should clear interrupt + wait for 2 us; + -- mode 3 (+ve edge, don't clear on read/write) + reg_write("1100","00000110"); + ca2_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("1111"); -- Should not clear interrupt + reg_read("0001"); -- Should not clear interrupt + reg_write("1101","00000001"); -- Should clear interrupt + wait for 2 us; + -- mode 1 (-ve edge, don't clear on read/write) + reg_write("1100","00000010"); + ca2_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("1111"); -- Should not clear interrupt + reg_read("0001"); -- Should not clear interrupt + reg_write("1101","00000001"); -- Should clear interrupt + wait for 2 us; + + -- Test CA2 output modes + -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge) + reg_write("1100","00001000"); + -- mode 5 (set low for 1 cycle on read/write ORA) + reg_write("1100","00001010"); + -- mode 6 (held low) + reg_write("1100","00001100"); + -- mode 7 (held high) + reg_write("1100","00001110"); + + -- Test CB2 interrupt modes + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10001000"); -- Enable CB2 interrupt + -- mode 2 (+ve edge, clear on read/write) + reg_write("1100","01000000"); -- PCR + cb2_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should clear interrupt + wait for 2 us; + -- mode 0 (-ve edge, clear on read/write) + reg_write("1100","00000000"); -- PCR + cb2_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should clear interrupt + wait for 2 us; + -- mode 3 (+ve edge, don't clear on read/write) + reg_write("1100","01100000"); + cb2_in <= '1'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should not clear interrupt + reg_write("1101","00001000"); -- Should clear interrupt + wait for 2 us; + -- mode 1 (-ve edge, don't clear on read/write) + reg_write("1100","00100000"); + cb2_in <= '0'; -- Trigger event + wait for 2 us; + reg_read("1101"); + reg_read("0000"); -- Should not clear interrupt + reg_write("1101","00001000"); -- Should clear interrupt + wait for 2 us; + + -- Test CB2 output modes + -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge) + reg_write("1100","10000000"); + -- mode 5 (set low for 1 cycle on read/write ORA) + reg_write("1100","10100000"); + -- mode 6 (held low) + reg_write("1100","11000000"); + -- mode 7 (held high) + reg_write("1100","11100000"); + + -- Timer 1 timeout + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","11000000"); -- Enable timer 1 interrupt + -- Count to 16 + reg_write("0100","00010000"); + reg_write("0101","00000000"); + wait for 50 us; + -- Count to 16 + reg_write("0100","00010000"); + reg_write("0101","00000000"); -- Should clear interrupt + wait for 50 us; + reg_read("0100"); -- Should clear interrupt + + -- Timer 2 timeout + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1110","10100000"); -- Enable timer 2 interrupt + -- Count to 16 + reg_write("1000","00010000"); + reg_write("1001","00000000"); + wait for 50 us; + -- Count to 16 + reg_write("1000","00010000"); + reg_write("1001","00000000"); -- Should clear interrupt + wait for 50 us; + reg_read("1000"); -- Should clear interrupt + + -- Timer 2 test similar to BBC usage (speech interrupt) + -- PB6 high + pb_in(6) <= '1'; + reg_write("1101","01111111"); -- Clear interrupts + reg_write("1110","01111111"); -- Disable all interrupts + reg_write("1011","00100000"); -- Timer 2 PB6 counter mode + reg_write("1000","00000001"); -- Start at 1 + reg_write("1001","00000000"); + reg_write("1110","10100000"); -- Enable timer 2 interrupt + wait for 5 us; + -- Generate falling edge + pb_in(6) <= '0'; + wait for 5 us; + -- Clear interrupt + reg_write("1101","00100000"); + -- Zero timer high byte + reg_write("1001","00000000"); + + wait; + end process; + +end architecture; diff --git a/mc6845.vhd b/mc6845.vhd index 31208ea..c102501 100644 --- a/mc6845.vhd +++ b/mc6845.vhd @@ -1,481 +1,481 @@ --- BBC Micro for Altera DE1 --- --- Copyright (c) 2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- MC6845 CRTC --- --- Synchronous implementation for FPGA --- --- (C) 2011 Mike Stirling --- -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - -entity mc6845 is -port ( - CLOCK : in std_logic; - CLKEN : in std_logic; - nRESET : in std_logic; - - -- Bus interface - ENABLE : in std_logic; - R_nW : in std_logic; - RS : in std_logic; - DI : in std_logic_vector(7 downto 0); - DO : out std_logic_vector(7 downto 0); - - -- Display interface - VSYNC : out std_logic; - HSYNC : out std_logic; - DE : out std_logic; - CURSOR : out std_logic; - LPSTB : in std_logic; - - -- Memory interface - MA : out std_logic_vector(13 downto 0); - RA : out std_logic_vector(4 downto 0) - ); -end entity; - -architecture rtl of mc6845 is - --- Host-accessible registers -signal addr_reg : std_logic_vector(4 downto 0); -- Currently addressed register --- These are write-only -signal r00_h_total : unsigned(7 downto 0); -- Horizontal total, chars -signal r01_h_displayed : unsigned(7 downto 0); -- Horizontal active, chars -signal r02_h_sync_pos : unsigned(7 downto 0); -- Horizontal sync position, chars -signal r03_v_sync_width : unsigned(3 downto 0); -- Vertical sync width, scan lines (0=16 lines) -signal r03_h_sync_width : unsigned(3 downto 0); -- Horizontal sync width, chars (0=no sync) -signal r04_v_total : unsigned(6 downto 0); -- Vertical total, character rows -signal r05_v_total_adj : unsigned(4 downto 0); -- Vertical offset, scan lines -signal r06_v_displayed : unsigned(6 downto 0); -- Vertical active, character rows -signal r07_v_sync_pos : unsigned(6 downto 0); -- Vertical sync position, character rows -signal r08_interlace : std_logic_vector(1 downto 0); -signal r09_max_scan_line_addr : unsigned(4 downto 0); -signal r10_cursor_mode : std_logic_vector(1 downto 0); -signal r10_cursor_start : unsigned(4 downto 0); -- Cursor start, scan lines -signal r11_cursor_end : unsigned(4 downto 0); -- Cursor end, scan lines -signal r12_start_addr_h : unsigned(5 downto 0); -signal r13_start_addr_l : unsigned(7 downto 0); --- These are read/write -signal r14_cursor_h : unsigned(5 downto 0); -signal r15_cursor_l : unsigned(7 downto 0); --- These are read-only -signal r16_light_pen_h : unsigned(5 downto 0); -signal r17_light_pen_l : unsigned(7 downto 0); - - --- Timing generation --- Horizontal counter counts position on line -signal h_counter : unsigned(7 downto 0); --- HSYNC counter counts duration of sync pulse -signal h_sync_counter : unsigned(3 downto 0); --- Row counter counts current character row -signal row_counter : unsigned(6 downto 0); --- Line counter counts current line within each character row -signal line_counter : unsigned(4 downto 0); --- VSYNC counter counts duration of sync pulse -signal v_sync_counter : unsigned(3 downto 0); --- Field counter counts number of complete fields for cursor flash -signal field_counter : unsigned(5 downto 0); - --- Internal signals -signal h_sync_start : std_logic; -signal h_half_way : std_logic; -signal h_display : std_logic; -signal hs : std_logic; -signal v_display : std_logic; -signal vs : std_logic; -signal odd_field : std_logic; -signal ma_i : unsigned(13 downto 0); -signal ma_row_start : unsigned(13 downto 0); -- Start address of current character row -signal cursor_i : std_logic; -signal lpstb_i : std_logic; - - -begin - HSYNC <= hs; -- External HSYNC driven directly from internal signal +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- MC6845 CRTC +-- +-- Synchronous implementation for FPGA +-- +-- (C) 2011 Mike Stirling +-- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity mc6845 is +port ( + CLOCK : in std_logic; + CLKEN : in std_logic; + nRESET : in std_logic; + + -- Bus interface + ENABLE : in std_logic; + R_nW : in std_logic; + RS : in std_logic; + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0); + + -- Display interface + VSYNC : out std_logic; + HSYNC : out std_logic; + DE : out std_logic; + CURSOR : out std_logic; + LPSTB : in std_logic; + + -- Memory interface + MA : out std_logic_vector(13 downto 0); + RA : out std_logic_vector(4 downto 0) + ); +end entity; + +architecture rtl of mc6845 is + +-- Host-accessible registers +signal addr_reg : std_logic_vector(4 downto 0); -- Currently addressed register +-- These are write-only +signal r00_h_total : unsigned(7 downto 0); -- Horizontal total, chars +signal r01_h_displayed : unsigned(7 downto 0); -- Horizontal active, chars +signal r02_h_sync_pos : unsigned(7 downto 0); -- Horizontal sync position, chars +signal r03_v_sync_width : unsigned(3 downto 0); -- Vertical sync width, scan lines (0=16 lines) +signal r03_h_sync_width : unsigned(3 downto 0); -- Horizontal sync width, chars (0=no sync) +signal r04_v_total : unsigned(6 downto 0); -- Vertical total, character rows +signal r05_v_total_adj : unsigned(4 downto 0); -- Vertical offset, scan lines +signal r06_v_displayed : unsigned(6 downto 0); -- Vertical active, character rows +signal r07_v_sync_pos : unsigned(6 downto 0); -- Vertical sync position, character rows +signal r08_interlace : std_logic_vector(1 downto 0); +signal r09_max_scan_line_addr : unsigned(4 downto 0); +signal r10_cursor_mode : std_logic_vector(1 downto 0); +signal r10_cursor_start : unsigned(4 downto 0); -- Cursor start, scan lines +signal r11_cursor_end : unsigned(4 downto 0); -- Cursor end, scan lines +signal r12_start_addr_h : unsigned(5 downto 0); +signal r13_start_addr_l : unsigned(7 downto 0); +-- These are read/write +signal r14_cursor_h : unsigned(5 downto 0); +signal r15_cursor_l : unsigned(7 downto 0); +-- These are read-only +signal r16_light_pen_h : unsigned(5 downto 0); +signal r17_light_pen_l : unsigned(7 downto 0); + + +-- Timing generation +-- Horizontal counter counts position on line +signal h_counter : unsigned(7 downto 0); +-- HSYNC counter counts duration of sync pulse +signal h_sync_counter : unsigned(3 downto 0); +-- Row counter counts current character row +signal row_counter : unsigned(6 downto 0); +-- Line counter counts current line within each character row +signal line_counter : unsigned(4 downto 0); +-- VSYNC counter counts duration of sync pulse +signal v_sync_counter : unsigned(3 downto 0); +-- Field counter counts number of complete fields for cursor flash +signal field_counter : unsigned(5 downto 0); + +-- Internal signals +signal h_sync_start : std_logic; +signal h_half_way : std_logic; +signal h_display : std_logic; +signal hs : std_logic; +signal v_display : std_logic; +signal vs : std_logic; +signal odd_field : std_logic; +signal ma_i : unsigned(13 downto 0); +signal ma_row_start : unsigned(13 downto 0); -- Start address of current character row +signal cursor_i : std_logic; +signal lpstb_i : std_logic; + + +begin + HSYNC <= hs; -- External HSYNC driven directly from internal signal VSYNC <= vs; -- External VSYNC driven directly from internal signal - DE <= h_display and v_display; - - -- Cursor output generated combinatorially from the internal signal in - -- accordance with the currently selected cursor mode - CURSOR <= cursor_i when r10_cursor_mode = "00" else - '0' when r10_cursor_mode = "01" else - (cursor_i and field_counter(4)) when r10_cursor_mode = "10" else - (cursor_i and field_counter(5)); - - -- Synchronous register access. Enabled on every clock. - process(CLOCK,nRESET) - begin - if nRESET = '0' then - -- Reset registers to defaults - addr_reg <= (others => '0'); - r00_h_total <= (others => '0'); - r01_h_displayed <= (others => '0'); - r02_h_sync_pos <= (others => '0'); - r03_v_sync_width <= (others => '0'); - r03_h_sync_width <= (others => '0'); - r04_v_total <= (others => '0'); - r05_v_total_adj <= (others => '0'); - r06_v_displayed <= (others => '0'); - r07_v_sync_pos <= (others => '0'); - r08_interlace <= (others => '0'); - r09_max_scan_line_addr <= (others => '0'); - r10_cursor_mode <= (others => '0'); - r10_cursor_start <= (others => '0'); - r11_cursor_end <= (others => '0'); - r12_start_addr_h <= (others => '0'); - r13_start_addr_l <= (others => '0'); - r14_cursor_h <= (others => '0'); - r15_cursor_l <= (others => '0'); - - DO <= (others => '0'); - elsif rising_edge(CLOCK) then - if ENABLE = '1' then - if R_nW = '1' then - -- Read - case addr_reg is - when "01110" => - DO <= "00" & std_logic_vector(r14_cursor_h); - when "01111" => - DO <= std_logic_vector(r15_cursor_l); - when "10000" => - DO <= "00" & std_logic_vector(r16_light_pen_h); - when "10001" => - DO <= std_logic_vector(r17_light_pen_l); - when others => - DO <= (others => '0'); - end case; - else - -- Write - if RS = '0' then - addr_reg <= DI(4 downto 0); - else - case addr_reg is - when "00000" => - r00_h_total <= unsigned(DI); - when "00001" => - r01_h_displayed <= unsigned(DI); - when "00010" => - r02_h_sync_pos <= unsigned(DI); - when "00011" => - r03_v_sync_width <= unsigned(DI(7 downto 4)); - r03_h_sync_width <= unsigned(DI(3 downto 0)); - when "00100" => - r04_v_total <= unsigned(DI(6 downto 0)); - when "00101" => - r05_v_total_adj <= unsigned(DI(4 downto 0)); - when "00110" => - r06_v_displayed <= unsigned(DI(6 downto 0)); - when "00111" => - r07_v_sync_pos <= unsigned(DI(6 downto 0)); - when "01000" => - r08_interlace <= DI(1 downto 0); - when "01001" => - r09_max_scan_line_addr <= unsigned(DI(4 downto 0)); - when "01010" => - r10_cursor_mode <= DI(6 downto 5); - r10_cursor_start <= unsigned(DI(4 downto 0)); - when "01011" => - r11_cursor_end <= unsigned(DI(4 downto 0)); - when "01100" => - r12_start_addr_h <= unsigned(DI(5 downto 0)); - when "01101" => - r13_start_addr_l <= unsigned(DI(7 downto 0)); - when "01110" => - r14_cursor_h <= unsigned(DI(5 downto 0)); - when "01111" => - r15_cursor_l <= unsigned(DI(7 downto 0)); - when others => - null; - end case; - end if; - end if; - end if; - end if; - end process; -- registers - - -- Horizontal, vertical and address counters - process(CLOCK,nRESET) - variable ma_row_start : unsigned(13 downto 0); - variable max_scan_line : unsigned(4 downto 0); - begin - if nRESET = '0' then - -- H - h_counter <= (others => '0'); - - -- V - line_counter <= (others => '0'); - row_counter <= (others => '0'); - odd_field <= '0'; - - -- Fields (cursor flash) - field_counter <= (others => '0'); - - -- Addressing - ma_row_start := (others => '0'); - ma_i <= (others => '0'); - elsif rising_edge(CLOCK) and CLKEN='1' then - -- Horizontal counter increments on each clock, wrapping at - -- h_total - if h_counter = r00_h_total then - -- h_total reached - h_counter <= (others => '0'); - - -- In interlace sync + video mode mask off the LSb of the - -- max scan line address - if r08_interlace = "11" then - max_scan_line := r09_max_scan_line_addr(4 downto 1) & "0"; - else - max_scan_line := r09_max_scan_line_addr; - end if; - - -- Scan line counter increments, wrapping at max_scan_line_addr - if line_counter = max_scan_line then - -- Next character row - -- FIXME: No support for v_total_adj yet - line_counter <= (others => '0'); - if row_counter = r04_v_total then - -- If in interlace mode we toggle to the opposite field. - -- Save on some logic by doing this here rather than at the - -- end of v_total_adj - it shouldn't make any difference to the - -- output - if r08_interlace(0) = '1' then - odd_field <= not odd_field; - else - odd_field <= '0'; - end if; - - -- Address is loaded from start address register at the top of - -- each field and the row counter is reset - ma_row_start := r12_start_addr_h & r13_start_addr_l; - row_counter <= (others => '0'); - - -- Increment field counter - field_counter <= field_counter + 1; - else - -- On all other character rows within the field the row start address is - -- increased by h_displayed and the row counter is incremented - ma_row_start := ma_row_start + r01_h_displayed; - row_counter <= row_counter + 1; - end if; - else - -- Next scan line. Count in twos in interlaced sync+video mode - if r08_interlace = "11" then - line_counter <= line_counter + 2; - line_counter(0) <= '0'; -- Force to even - else - line_counter <= line_counter + 1; - end if; - end if; - - -- Memory address preset to row start at the beginning of each - -- scan line - ma_i <= ma_row_start; - else - -- Increment horizontal counter - h_counter <= h_counter + 1; - -- Increment memory address - ma_i <= ma_i + 1; - end if; - end if; - end process; - - -- Signals to mark hsync and half way points for generating - -- vsync in even and odd fields - process(h_counter) - begin - h_sync_start <= '0'; - h_half_way <= '0'; - - if h_counter = r02_h_sync_pos then - h_sync_start <= '1'; - end if; - if h_counter = "0" & r02_h_sync_pos(7 downto 1) then - h_half_way <= '1'; - end if; - end process; - - -- Video timing and sync counters - process(CLOCK,nRESET) - begin - if nRESET = '0' then - -- H - h_display <= '0'; - hs <= '0'; - h_sync_counter <= (others => '0'); - - -- V - v_display <= '0'; - vs <= '0'; - v_sync_counter <= (others => '0'); - elsif rising_edge(CLOCK) and CLKEN = '1' then - -- Horizontal active video - if h_counter = 0 then - -- Start of active video - h_display <= '1'; - end if; - if h_counter = r01_h_displayed then - -- End of active video - h_display <= '0'; - end if; - - -- Horizontal sync - if h_sync_start = '1' or hs = '1' then - -- In horizontal sync - hs <= '1'; - h_sync_counter <= h_sync_counter + 1; - else - h_sync_counter <= (others => '0'); - end if; - if h_sync_counter = r03_h_sync_width then - -- Terminate hsync after h_sync_width (0 means no hsync so this - -- can immediately override the setting above) - hs <= '0'; - end if; - - -- Vertical active video - if row_counter = 0 then - -- Start of active video - v_display <= '1'; - end if; - if row_counter = r06_v_displayed then - -- End of active video - v_display <= '0'; - end if; - - -- Vertical sync occurs either at the same time as the horizontal sync (even fields) - -- or half a line later (odd fields) - if (odd_field = '0' and h_sync_start = '1') or (odd_field = '1' and h_half_way = '1') then - if (row_counter = r07_v_sync_pos and line_counter = 0) or vs = '1' then - -- In vertical sync - vs <= '1'; - v_sync_counter <= v_sync_counter + 1; - else - v_sync_counter <= (others => '0'); - end if; - if v_sync_counter = r03_v_sync_width and vs = '1' then - -- Terminate vsync after v_sync_width (0 means 16 lines so this is - -- masked by 'vs' to ensure a full turn of the counter in this case) - vs <= '0'; - end if; - end if; - end if; - end process; - - -- Address generation - process(CLOCK,nRESET) - variable slv_line : std_logic_vector(4 downto 0); - begin - if nRESET = '0' then - RA <= (others => '0'); - MA <= (others => '0'); - elsif rising_edge(CLOCK) and CLKEN = '1' then - slv_line := std_logic_vector(line_counter); - - -- Character row address is just the scan line counter delayed by - -- one clock to line up with the syncs. - if r08_interlace = "11" then - -- In interlace sync and video mode the LSb is determined by the - -- field number. The line counter counts up in 2s in this case. - RA <= slv_line(4 downto 1) & (slv_line(0) or odd_field); - else - RA <= slv_line; - end if; - -- Internal memory address delayed by one cycle as well - MA <= std_logic_vector(ma_i); - end if; - end process; - - -- Cursor control - process(CLOCK,nRESET) - variable cursor_line : std_logic; - begin - -- Internal cursor enable signal delayed by 1 clock to line up - -- with address outputs - if nRESET = '0' then - cursor_i <= '0'; - cursor_line := '0'; - elsif rising_edge(CLOCK) and CLKEN = '1' then - if h_display = '1' and v_display = '1' and ma_i = r14_cursor_h & r15_cursor_l then - if line_counter = 0 then - -- Suppress wrap around if last line is > max scan line - cursor_line := '0'; - end if; - if line_counter = r10_cursor_start then - -- First cursor scanline - cursor_line := '1'; - end if; - - -- Cursor output is asserted within the current cursor character - -- on the selected lines only - cursor_i <= cursor_line; - - if line_counter = r11_cursor_end then - -- Last cursor scanline - cursor_line := '0'; - end if; - else - -- Cursor is off in all character positions apart from the - -- selected one - cursor_i <= '0'; - end if; - end if; - end process; - - -- Light pen capture - process(CLOCK,nRESET) - begin - if nRESET = '0' then - lpstb_i <= '0'; - r16_light_pen_h <= (others => '0'); - r17_light_pen_l <= (others => '0'); - elsif rising_edge(CLOCK) and CLKEN = '1' then - -- Register light-pen strobe input - lpstb_i <= LPSTB; - - if LPSTB = '1' and lpstb_i = '0' then - -- Capture address on rising edge - r16_light_pen_h <= ma_i(13 downto 8); - r17_light_pen_l <= ma_i(7 downto 0); - end if; - end if; - end process; -end architecture; - - + DE <= h_display and v_display; + + -- Cursor output generated combinatorially from the internal signal in + -- accordance with the currently selected cursor mode + CURSOR <= cursor_i when r10_cursor_mode = "00" else + '0' when r10_cursor_mode = "01" else + (cursor_i and field_counter(4)) when r10_cursor_mode = "10" else + (cursor_i and field_counter(5)); + + -- Synchronous register access. Enabled on every clock. + process(CLOCK,nRESET) + begin + if nRESET = '0' then + -- Reset registers to defaults + addr_reg <= (others => '0'); + r00_h_total <= (others => '0'); + r01_h_displayed <= (others => '0'); + r02_h_sync_pos <= (others => '0'); + r03_v_sync_width <= (others => '0'); + r03_h_sync_width <= (others => '0'); + r04_v_total <= (others => '0'); + r05_v_total_adj <= (others => '0'); + r06_v_displayed <= (others => '0'); + r07_v_sync_pos <= (others => '0'); + r08_interlace <= (others => '0'); + r09_max_scan_line_addr <= (others => '0'); + r10_cursor_mode <= (others => '0'); + r10_cursor_start <= (others => '0'); + r11_cursor_end <= (others => '0'); + r12_start_addr_h <= (others => '0'); + r13_start_addr_l <= (others => '0'); + r14_cursor_h <= (others => '0'); + r15_cursor_l <= (others => '0'); + + DO <= (others => '0'); + elsif rising_edge(CLOCK) then + if ENABLE = '1' then + if R_nW = '1' then + -- Read + case addr_reg is + when "01110" => + DO <= "00" & std_logic_vector(r14_cursor_h); + when "01111" => + DO <= std_logic_vector(r15_cursor_l); + when "10000" => + DO <= "00" & std_logic_vector(r16_light_pen_h); + when "10001" => + DO <= std_logic_vector(r17_light_pen_l); + when others => + DO <= (others => '0'); + end case; + else + -- Write + if RS = '0' then + addr_reg <= DI(4 downto 0); + else + case addr_reg is + when "00000" => + r00_h_total <= unsigned(DI); + when "00001" => + r01_h_displayed <= unsigned(DI); + when "00010" => + r02_h_sync_pos <= unsigned(DI); + when "00011" => + r03_v_sync_width <= unsigned(DI(7 downto 4)); + r03_h_sync_width <= unsigned(DI(3 downto 0)); + when "00100" => + r04_v_total <= unsigned(DI(6 downto 0)); + when "00101" => + r05_v_total_adj <= unsigned(DI(4 downto 0)); + when "00110" => + r06_v_displayed <= unsigned(DI(6 downto 0)); + when "00111" => + r07_v_sync_pos <= unsigned(DI(6 downto 0)); + when "01000" => + r08_interlace <= DI(1 downto 0); + when "01001" => + r09_max_scan_line_addr <= unsigned(DI(4 downto 0)); + when "01010" => + r10_cursor_mode <= DI(6 downto 5); + r10_cursor_start <= unsigned(DI(4 downto 0)); + when "01011" => + r11_cursor_end <= unsigned(DI(4 downto 0)); + when "01100" => + r12_start_addr_h <= unsigned(DI(5 downto 0)); + when "01101" => + r13_start_addr_l <= unsigned(DI(7 downto 0)); + when "01110" => + r14_cursor_h <= unsigned(DI(5 downto 0)); + when "01111" => + r15_cursor_l <= unsigned(DI(7 downto 0)); + when others => + null; + end case; + end if; + end if; + end if; + end if; + end process; -- registers + + -- Horizontal, vertical and address counters + process(CLOCK,nRESET) + variable ma_row_start : unsigned(13 downto 0); + variable max_scan_line : unsigned(4 downto 0); + begin + if nRESET = '0' then + -- H + h_counter <= (others => '0'); + + -- V + line_counter <= (others => '0'); + row_counter <= (others => '0'); + odd_field <= '0'; + + -- Fields (cursor flash) + field_counter <= (others => '0'); + + -- Addressing + ma_row_start := (others => '0'); + ma_i <= (others => '0'); + elsif rising_edge(CLOCK) and CLKEN='1' then + -- Horizontal counter increments on each clock, wrapping at + -- h_total + if h_counter = r00_h_total then + -- h_total reached + h_counter <= (others => '0'); + + -- In interlace sync + video mode mask off the LSb of the + -- max scan line address + if r08_interlace = "11" then + max_scan_line := r09_max_scan_line_addr(4 downto 1) & "0"; + else + max_scan_line := r09_max_scan_line_addr; + end if; + + -- Scan line counter increments, wrapping at max_scan_line_addr + if line_counter = max_scan_line then + -- Next character row + -- FIXME: No support for v_total_adj yet + line_counter <= (others => '0'); + if row_counter = r04_v_total then + -- If in interlace mode we toggle to the opposite field. + -- Save on some logic by doing this here rather than at the + -- end of v_total_adj - it shouldn't make any difference to the + -- output + if r08_interlace(0) = '1' then + odd_field <= not odd_field; + else + odd_field <= '0'; + end if; + + -- Address is loaded from start address register at the top of + -- each field and the row counter is reset + ma_row_start := r12_start_addr_h & r13_start_addr_l; + row_counter <= (others => '0'); + + -- Increment field counter + field_counter <= field_counter + 1; + else + -- On all other character rows within the field the row start address is + -- increased by h_displayed and the row counter is incremented + ma_row_start := ma_row_start + r01_h_displayed; + row_counter <= row_counter + 1; + end if; + else + -- Next scan line. Count in twos in interlaced sync+video mode + if r08_interlace = "11" then + line_counter <= line_counter + 2; + line_counter(0) <= '0'; -- Force to even + else + line_counter <= line_counter + 1; + end if; + end if; + + -- Memory address preset to row start at the beginning of each + -- scan line + ma_i <= ma_row_start; + else + -- Increment horizontal counter + h_counter <= h_counter + 1; + -- Increment memory address + ma_i <= ma_i + 1; + end if; + end if; + end process; + + -- Signals to mark hsync and half way points for generating + -- vsync in even and odd fields + process(h_counter) + begin + h_sync_start <= '0'; + h_half_way <= '0'; + + if h_counter = r02_h_sync_pos then + h_sync_start <= '1'; + end if; + if h_counter = "0" & r02_h_sync_pos(7 downto 1) then + h_half_way <= '1'; + end if; + end process; + + -- Video timing and sync counters + process(CLOCK,nRESET) + begin + if nRESET = '0' then + -- H + h_display <= '0'; + hs <= '0'; + h_sync_counter <= (others => '0'); + + -- V + v_display <= '0'; + vs <= '0'; + v_sync_counter <= (others => '0'); + elsif rising_edge(CLOCK) and CLKEN = '1' then + -- Horizontal active video + if h_counter = 0 then + -- Start of active video + h_display <= '1'; + end if; + if h_counter = r01_h_displayed then + -- End of active video + h_display <= '0'; + end if; + + -- Horizontal sync + if h_sync_start = '1' or hs = '1' then + -- In horizontal sync + hs <= '1'; + h_sync_counter <= h_sync_counter + 1; + else + h_sync_counter <= (others => '0'); + end if; + if h_sync_counter = r03_h_sync_width then + -- Terminate hsync after h_sync_width (0 means no hsync so this + -- can immediately override the setting above) + hs <= '0'; + end if; + + -- Vertical active video + if row_counter = 0 then + -- Start of active video + v_display <= '1'; + end if; + if row_counter = r06_v_displayed then + -- End of active video + v_display <= '0'; + end if; + + -- Vertical sync occurs either at the same time as the horizontal sync (even fields) + -- or half a line later (odd fields) + if (odd_field = '0' and h_sync_start = '1') or (odd_field = '1' and h_half_way = '1') then + if (row_counter = r07_v_sync_pos and line_counter = 0) or vs = '1' then + -- In vertical sync + vs <= '1'; + v_sync_counter <= v_sync_counter + 1; + else + v_sync_counter <= (others => '0'); + end if; + if v_sync_counter = r03_v_sync_width and vs = '1' then + -- Terminate vsync after v_sync_width (0 means 16 lines so this is + -- masked by 'vs' to ensure a full turn of the counter in this case) + vs <= '0'; + end if; + end if; + end if; + end process; + + -- Address generation + process(CLOCK,nRESET) + variable slv_line : std_logic_vector(4 downto 0); + begin + if nRESET = '0' then + RA <= (others => '0'); + MA <= (others => '0'); + elsif rising_edge(CLOCK) and CLKEN = '1' then + slv_line := std_logic_vector(line_counter); + + -- Character row address is just the scan line counter delayed by + -- one clock to line up with the syncs. + if r08_interlace = "11" then + -- In interlace sync and video mode the LSb is determined by the + -- field number. The line counter counts up in 2s in this case. + RA <= slv_line(4 downto 1) & (slv_line(0) or odd_field); + else + RA <= slv_line; + end if; + -- Internal memory address delayed by one cycle as well + MA <= std_logic_vector(ma_i); + end if; + end process; + + -- Cursor control + process(CLOCK,nRESET) + variable cursor_line : std_logic; + begin + -- Internal cursor enable signal delayed by 1 clock to line up + -- with address outputs + if nRESET = '0' then + cursor_i <= '0'; + cursor_line := '0'; + elsif rising_edge(CLOCK) and CLKEN = '1' then + if h_display = '1' and v_display = '1' and ma_i = r14_cursor_h & r15_cursor_l then + if line_counter = 0 then + -- Suppress wrap around if last line is > max scan line + cursor_line := '0'; + end if; + if line_counter = r10_cursor_start then + -- First cursor scanline + cursor_line := '1'; + end if; + + -- Cursor output is asserted within the current cursor character + -- on the selected lines only + cursor_i <= cursor_line; + + if line_counter = r11_cursor_end then + -- Last cursor scanline + cursor_line := '0'; + end if; + else + -- Cursor is off in all character positions apart from the + -- selected one + cursor_i <= '0'; + end if; + end if; + end process; + + -- Light pen capture + process(CLOCK,nRESET) + begin + if nRESET = '0' then + lpstb_i <= '0'; + r16_light_pen_h <= (others => '0'); + r17_light_pen_l <= (others => '0'); + elsif rising_edge(CLOCK) and CLKEN = '1' then + -- Register light-pen strobe input + lpstb_i <= LPSTB; + + if LPSTB = '1' and lpstb_i = '0' then + -- Capture address on rising edge + r16_light_pen_h <= ma_i(13 downto 8); + r17_light_pen_l <= ma_i(7 downto 0); + end if; + end if; + end process; +end architecture; + + diff --git a/pll32.ppf b/pll32.ppf index 1ba6b2c..71486cf 100644 --- a/pll32.ppf +++ b/pll32.ppf @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/pll32.qip b/pll32.qip index f78bd93..e82abed 100644 --- a/pll32.qip +++ b/pll32.qip @@ -1,4 +1,4 @@ -set_global_assignment -name IP_TOOL_NAME "ALTPLL" -set_global_assignment -name IP_TOOL_VERSION "9.1" -set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pll32.vhd"] -set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll32.ppf"] +set_global_assignment -name IP_TOOL_NAME "ALTPLL" +set_global_assignment -name IP_TOOL_VERSION "9.1" +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pll32.vhd"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll32.ppf"] diff --git a/pll32.vhd b/pll32.vhd index 43df1aa..ab53700 100644 --- a/pll32.vhd +++ b/pll32.vhd @@ -1,365 +1,365 @@ --- megafunction wizard: %ALTPLL% --- GENERATION: STANDARD --- VERSION: WM1.0 --- MODULE: altpll - --- ============================================================ --- File Name: pll32.vhd --- Megafunction Name(s): --- altpll --- --- Simulation Library Files(s): --- altera_mf --- ============================================================ --- ************************************************************ --- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! --- --- 9.1 Build 222 10/21/2009 SJ Web Edition --- ************************************************************ - - ---Copyright (C) 1991-2009 Altera Corporation ---Your use of Altera Corporation's design tools, logic functions ---and other software and tools, and its AMPP partner logic ---functions, and any output files from any of the foregoing ---(including device programming or simulation files), and any ---associated documentation or information are expressly subject ---to the terms and conditions of the Altera Program License ---Subscription Agreement, Altera MegaCore Function License ---Agreement, or other applicable license agreement, including, ---without limitation, that your use is for the sole purpose of ---programming logic devices manufactured by Altera and sold by ---Altera or its authorized distributors. Please refer to the ---applicable agreement for further details. - - -LIBRARY ieee; -USE ieee.std_logic_1164.all; - -LIBRARY altera_mf; -USE altera_mf.all; - -ENTITY pll32 IS - PORT - ( - areset : IN STD_LOGIC := '0'; - inclk0 : IN STD_LOGIC := '0'; - c0 : OUT STD_LOGIC ; - locked : OUT STD_LOGIC - ); -END pll32; - - -ARCHITECTURE SYN OF pll32 IS - - SIGNAL sub_wire0 : STD_LOGIC_VECTOR (5 DOWNTO 0); - SIGNAL sub_wire1 : STD_LOGIC ; - SIGNAL sub_wire2 : STD_LOGIC ; - SIGNAL sub_wire3 : STD_LOGIC ; - SIGNAL sub_wire4 : STD_LOGIC_VECTOR (1 DOWNTO 0); - SIGNAL sub_wire5_bv : BIT_VECTOR (0 DOWNTO 0); - SIGNAL sub_wire5 : STD_LOGIC_VECTOR (0 DOWNTO 0); - - - - COMPONENT altpll - GENERIC ( - clk0_divide_by : NATURAL; - clk0_duty_cycle : NATURAL; - clk0_multiply_by : NATURAL; - clk0_phase_shift : STRING; - compensate_clock : STRING; - gate_lock_signal : STRING; - inclk0_input_frequency : NATURAL; - intended_device_family : STRING; - invalid_lock_multiplier : NATURAL; - lpm_hint : STRING; - lpm_type : STRING; - operation_mode : STRING; - port_activeclock : STRING; - port_areset : STRING; - port_clkbad0 : STRING; - port_clkbad1 : STRING; - port_clkloss : STRING; - port_clkswitch : STRING; - port_configupdate : STRING; - port_fbin : STRING; - port_inclk0 : STRING; - port_inclk1 : STRING; - port_locked : STRING; - port_pfdena : STRING; - port_phasecounterselect : STRING; - port_phasedone : STRING; - port_phasestep : STRING; - port_phaseupdown : STRING; - port_pllena : STRING; - port_scanaclr : STRING; - port_scanclk : STRING; - port_scanclkena : STRING; - port_scandata : STRING; - port_scandataout : STRING; - port_scandone : STRING; - port_scanread : STRING; - port_scanwrite : STRING; - port_clk0 : STRING; - port_clk1 : STRING; - port_clk2 : STRING; - port_clk3 : STRING; - port_clk4 : STRING; - port_clk5 : STRING; - port_clkena0 : STRING; - port_clkena1 : STRING; - port_clkena2 : STRING; - port_clkena3 : STRING; - port_clkena4 : STRING; - port_clkena5 : STRING; - port_extclk0 : STRING; - port_extclk1 : STRING; - port_extclk2 : STRING; - port_extclk3 : STRING; - valid_lock_multiplier : NATURAL - ); - PORT ( - inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0); - locked : OUT STD_LOGIC ; - areset : IN STD_LOGIC ; - clk : OUT STD_LOGIC_VECTOR (5 DOWNTO 0) - ); - END COMPONENT; - -BEGIN - sub_wire5_bv(0 DOWNTO 0) <= "0"; - sub_wire5 <= To_stdlogicvector(sub_wire5_bv); - sub_wire1 <= sub_wire0(0); - c0 <= sub_wire1; - locked <= sub_wire2; - sub_wire3 <= inclk0; - sub_wire4 <= sub_wire5(0 DOWNTO 0) & sub_wire3; - - altpll_component : altpll - GENERIC MAP ( - clk0_divide_by => 3, - clk0_duty_cycle => 50, - clk0_multiply_by => 4, - clk0_phase_shift => "0", - compensate_clock => "CLK0", - gate_lock_signal => "NO", - inclk0_input_frequency => 41666, - intended_device_family => "Cyclone II", - invalid_lock_multiplier => 5, - lpm_hint => "CBX_MODULE_PREFIX=pll32", - lpm_type => "altpll", - operation_mode => "NORMAL", - port_activeclock => "PORT_UNUSED", - port_areset => "PORT_USED", - port_clkbad0 => "PORT_UNUSED", - port_clkbad1 => "PORT_UNUSED", - port_clkloss => "PORT_UNUSED", - port_clkswitch => "PORT_UNUSED", - port_configupdate => "PORT_UNUSED", - port_fbin => "PORT_UNUSED", - port_inclk0 => "PORT_USED", - port_inclk1 => "PORT_UNUSED", - port_locked => "PORT_USED", - port_pfdena => "PORT_UNUSED", - port_phasecounterselect => "PORT_UNUSED", - port_phasedone => "PORT_UNUSED", - port_phasestep => "PORT_UNUSED", - port_phaseupdown => "PORT_UNUSED", - port_pllena => "PORT_UNUSED", - port_scanaclr => "PORT_UNUSED", - port_scanclk => "PORT_UNUSED", - port_scanclkena => "PORT_UNUSED", - port_scandata => "PORT_UNUSED", - port_scandataout => "PORT_UNUSED", - port_scandone => "PORT_UNUSED", - port_scanread => "PORT_UNUSED", - port_scanwrite => "PORT_UNUSED", - port_clk0 => "PORT_USED", - port_clk1 => "PORT_UNUSED", - port_clk2 => "PORT_UNUSED", - port_clk3 => "PORT_UNUSED", - port_clk4 => "PORT_UNUSED", - port_clk5 => "PORT_UNUSED", - port_clkena0 => "PORT_UNUSED", - port_clkena1 => "PORT_UNUSED", - port_clkena2 => "PORT_UNUSED", - port_clkena3 => "PORT_UNUSED", - port_clkena4 => "PORT_UNUSED", - port_clkena5 => "PORT_UNUSED", - port_extclk0 => "PORT_UNUSED", - port_extclk1 => "PORT_UNUSED", - port_extclk2 => "PORT_UNUSED", - port_extclk3 => "PORT_UNUSED", - valid_lock_multiplier => 1 - ) - PORT MAP ( - inclk => sub_wire4, - areset => areset, - clk => sub_wire0, - locked => sub_wire2 - ); - - - -END SYN; - --- ============================================================ --- CNX file retrieval info --- ============================================================ --- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" --- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" --- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "0" --- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" --- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" --- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" --- Retrieval info: PRIVATE: BANDWIDTH_USE_CUSTOM STRING "0" --- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" --- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" --- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" --- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "1" --- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" --- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" --- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" --- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" --- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "e0" --- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "7" --- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1" --- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" --- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "32.000000" --- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" --- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" --- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" --- Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "1" --- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" --- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" --- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" --- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "24.000" --- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" --- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" --- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" --- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" --- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" --- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" --- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" --- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" --- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" --- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "312.000" --- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" --- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" --- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" --- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" --- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1" --- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" --- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "32.00000000" --- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1" --- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" --- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "0" --- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" --- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" --- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" --- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" --- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" --- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" --- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" --- Retrieval info: PRIVATE: PLL_ENA_CHECK STRING "0" --- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" --- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" --- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" --- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" --- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" --- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" --- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" --- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll32.mif" --- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" --- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "0" --- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" --- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" --- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" --- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" --- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" --- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" --- Retrieval info: PRIVATE: SPREAD_USE STRING "0" --- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" --- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" --- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" --- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" --- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" --- Retrieval info: PRIVATE: USE_CLK0 STRING "1" --- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" --- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" --- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" --- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all --- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "3" --- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" --- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "4" --- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" --- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" --- Retrieval info: CONSTANT: GATE_LOCK_SIGNAL STRING "NO" --- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "41666" --- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" --- Retrieval info: CONSTANT: INVALID_LOCK_MULTIPLIER NUMERIC "5" --- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" --- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" --- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" --- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" --- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" --- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" --- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" --- Retrieval info: CONSTANT: VALID_LOCK_MULTIPLIER NUMERIC "1" --- Retrieval info: USED_PORT: @clk 0 0 6 0 OUTPUT_CLK_EXT VCC "@clk[5..0]" --- Retrieval info: USED_PORT: @extclk 0 0 4 0 OUTPUT_CLK_EXT VCC "@extclk[3..0]" --- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]" --- Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" --- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" --- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" --- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" --- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 --- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 --- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 --- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 --- Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 --- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.vhd TRUE --- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.ppf TRUE --- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.inc FALSE --- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.cmp FALSE --- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.bsf FALSE --- Retrieval info: GEN_FILE: TYPE_NORMAL pll32_inst.vhd FALSE --- Retrieval info: LIB_FILE: altera_mf --- Retrieval info: CBX_MODULE_PREFIX: ON +-- megafunction wizard: %ALTPLL% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altpll + +-- ============================================================ +-- File Name: pll32.vhd +-- Megafunction Name(s): +-- altpll +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 9.1 Build 222 10/21/2009 SJ Web Edition +-- ************************************************************ + + +--Copyright (C) 1991-2009 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY pll32 IS + PORT + ( + areset : IN STD_LOGIC := '0'; + inclk0 : IN STD_LOGIC := '0'; + c0 : OUT STD_LOGIC ; + locked : OUT STD_LOGIC + ); +END pll32; + + +ARCHITECTURE SYN OF pll32 IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (5 DOWNTO 0); + SIGNAL sub_wire1 : STD_LOGIC ; + SIGNAL sub_wire2 : STD_LOGIC ; + SIGNAL sub_wire3 : STD_LOGIC ; + SIGNAL sub_wire4 : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL sub_wire5_bv : BIT_VECTOR (0 DOWNTO 0); + SIGNAL sub_wire5 : STD_LOGIC_VECTOR (0 DOWNTO 0); + + + + COMPONENT altpll + GENERIC ( + clk0_divide_by : NATURAL; + clk0_duty_cycle : NATURAL; + clk0_multiply_by : NATURAL; + clk0_phase_shift : STRING; + compensate_clock : STRING; + gate_lock_signal : STRING; + inclk0_input_frequency : NATURAL; + intended_device_family : STRING; + invalid_lock_multiplier : NATURAL; + lpm_hint : STRING; + lpm_type : STRING; + operation_mode : STRING; + port_activeclock : STRING; + port_areset : STRING; + port_clkbad0 : STRING; + port_clkbad1 : STRING; + port_clkloss : STRING; + port_clkswitch : STRING; + port_configupdate : STRING; + port_fbin : STRING; + port_inclk0 : STRING; + port_inclk1 : STRING; + port_locked : STRING; + port_pfdena : STRING; + port_phasecounterselect : STRING; + port_phasedone : STRING; + port_phasestep : STRING; + port_phaseupdown : STRING; + port_pllena : STRING; + port_scanaclr : STRING; + port_scanclk : STRING; + port_scanclkena : STRING; + port_scandata : STRING; + port_scandataout : STRING; + port_scandone : STRING; + port_scanread : STRING; + port_scanwrite : STRING; + port_clk0 : STRING; + port_clk1 : STRING; + port_clk2 : STRING; + port_clk3 : STRING; + port_clk4 : STRING; + port_clk5 : STRING; + port_clkena0 : STRING; + port_clkena1 : STRING; + port_clkena2 : STRING; + port_clkena3 : STRING; + port_clkena4 : STRING; + port_clkena5 : STRING; + port_extclk0 : STRING; + port_extclk1 : STRING; + port_extclk2 : STRING; + port_extclk3 : STRING; + valid_lock_multiplier : NATURAL + ); + PORT ( + inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0); + locked : OUT STD_LOGIC ; + areset : IN STD_LOGIC ; + clk : OUT STD_LOGIC_VECTOR (5 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + sub_wire5_bv(0 DOWNTO 0) <= "0"; + sub_wire5 <= To_stdlogicvector(sub_wire5_bv); + sub_wire1 <= sub_wire0(0); + c0 <= sub_wire1; + locked <= sub_wire2; + sub_wire3 <= inclk0; + sub_wire4 <= sub_wire5(0 DOWNTO 0) & sub_wire3; + + altpll_component : altpll + GENERIC MAP ( + clk0_divide_by => 3, + clk0_duty_cycle => 50, + clk0_multiply_by => 4, + clk0_phase_shift => "0", + compensate_clock => "CLK0", + gate_lock_signal => "NO", + inclk0_input_frequency => 41666, + intended_device_family => "Cyclone II", + invalid_lock_multiplier => 5, + lpm_hint => "CBX_MODULE_PREFIX=pll32", + lpm_type => "altpll", + operation_mode => "NORMAL", + port_activeclock => "PORT_UNUSED", + port_areset => "PORT_USED", + port_clkbad0 => "PORT_UNUSED", + port_clkbad1 => "PORT_UNUSED", + port_clkloss => "PORT_UNUSED", + port_clkswitch => "PORT_UNUSED", + port_configupdate => "PORT_UNUSED", + port_fbin => "PORT_UNUSED", + port_inclk0 => "PORT_USED", + port_inclk1 => "PORT_UNUSED", + port_locked => "PORT_USED", + port_pfdena => "PORT_UNUSED", + port_phasecounterselect => "PORT_UNUSED", + port_phasedone => "PORT_UNUSED", + port_phasestep => "PORT_UNUSED", + port_phaseupdown => "PORT_UNUSED", + port_pllena => "PORT_UNUSED", + port_scanaclr => "PORT_UNUSED", + port_scanclk => "PORT_UNUSED", + port_scanclkena => "PORT_UNUSED", + port_scandata => "PORT_UNUSED", + port_scandataout => "PORT_UNUSED", + port_scandone => "PORT_UNUSED", + port_scanread => "PORT_UNUSED", + port_scanwrite => "PORT_UNUSED", + port_clk0 => "PORT_USED", + port_clk1 => "PORT_UNUSED", + port_clk2 => "PORT_UNUSED", + port_clk3 => "PORT_UNUSED", + port_clk4 => "PORT_UNUSED", + port_clk5 => "PORT_UNUSED", + port_clkena0 => "PORT_UNUSED", + port_clkena1 => "PORT_UNUSED", + port_clkena2 => "PORT_UNUSED", + port_clkena3 => "PORT_UNUSED", + port_clkena4 => "PORT_UNUSED", + port_clkena5 => "PORT_UNUSED", + port_extclk0 => "PORT_UNUSED", + port_extclk1 => "PORT_UNUSED", + port_extclk2 => "PORT_UNUSED", + port_extclk3 => "PORT_UNUSED", + valid_lock_multiplier => 1 + ) + PORT MAP ( + inclk => sub_wire4, + areset => areset, + clk => sub_wire0, + locked => sub_wire2 + ); + + + +END SYN; + +-- ============================================================ +-- CNX file retrieval info +-- ============================================================ +-- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +-- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +-- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +-- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_CUSTOM STRING "0" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +-- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "1" +-- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +-- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +-- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +-- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +-- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "e0" +-- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "7" +-- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1" +-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "32.000000" +-- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +-- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +-- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +-- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +-- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +-- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "24.000" +-- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +-- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +-- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "312.000" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +-- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +-- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1" +-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "32.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +-- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +-- Retrieval info: PRIVATE: PLL_ENA_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +-- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll32.mif" +-- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +-- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +-- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +-- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +-- Retrieval info: PRIVATE: SPREAD_USE STRING "0" +-- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +-- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +-- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +-- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +-- Retrieval info: PRIVATE: USE_CLK0 STRING "1" +-- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +-- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +-- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +-- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "3" +-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "4" +-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +-- Retrieval info: CONSTANT: GATE_LOCK_SIGNAL STRING "NO" +-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "41666" +-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +-- Retrieval info: CONSTANT: INVALID_LOCK_MULTIPLIER NUMERIC "5" +-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: VALID_LOCK_MULTIPLIER NUMERIC "1" +-- Retrieval info: USED_PORT: @clk 0 0 6 0 OUTPUT_CLK_EXT VCC "@clk[5..0]" +-- Retrieval info: USED_PORT: @extclk 0 0 4 0 OUTPUT_CLK_EXT VCC "@extclk[3..0]" +-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]" +-- Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +-- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +-- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +-- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +-- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +-- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +-- Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.ppf TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.cmp FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32_inst.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf +-- Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/ps2_intf.vhd b/ps2_intf.vhd index dc8440f..015a7d0 100644 --- a/ps2_intf.vhd +++ b/ps2_intf.vhd @@ -1,157 +1,157 @@ --- ZX Spectrum for Altera DE1 --- --- Copyright (c) 2009-2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- - --- PS/2 interface (input only) --- Based loosely on ps2_ctrl.vhd (c) ALSE. http://www.alse-fr.com -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - --- This is input-only for the time being -entity ps2_intf is -generic (filter_length : positive := 8); -port( - CLK : in std_logic; - nRESET : in std_logic; - - -- PS/2 interface (could be bi-dir) - PS2_CLK : in std_logic; - PS2_DATA : in std_logic; - - -- Byte-wide data interface - only valid for one clock - -- so must be latched externally if required - DATA : out std_logic_vector(7 downto 0); - VALID : out std_logic; - ERROR : out std_logic - ); -end ps2_intf; - -architecture ps2_intf_arch of ps2_intf is -subtype filter_t is std_logic_vector(filter_length-1 downto 0); -signal clk_filter : filter_t; - -signal ps2_clk_in : std_logic; -signal ps2_dat_in : std_logic; --- Goes high when a clock falling edge is detected -signal clk_edge : std_logic; -signal bit_count : unsigned (3 downto 0); -signal shiftreg : std_logic_vector(8 downto 0); -signal parity : std_logic; -begin - -- Register input signals - process(nRESET,CLK) - begin - if nRESET = '0' then - ps2_clk_in <= '1'; - ps2_dat_in <= '1'; - clk_filter <= (others => '1'); - clk_edge <= '0'; - elsif rising_edge(CLK) then - -- Register inputs (and filter clock) - ps2_dat_in <= PS2_DATA; - clk_filter <= PS2_CLK & clk_filter(clk_filter'high downto 1); - clk_edge <= '0'; - - if clk_filter = filter_t'(others => '1') then - -- Filtered clock is high - ps2_clk_in <= '1'; - elsif clk_filter = filter_t'(others => '0') then - -- Filter clock is low, check for edge - if ps2_clk_in = '1' then - clk_edge <= '1'; - end if; - ps2_clk_in <= '0'; - end if; - end if; - end process; - - -- Shift in keyboard data - process(nRESET,CLK) - begin - if nRESET = '0' then - bit_count <= (others => '0'); - shiftreg <= (others => '0'); - parity <= '0'; - DATA <= (others => '0'); - VALID <= '0'; - ERROR <= '0'; - elsif rising_edge(CLK) then - -- Clear flags - VALID <= '0'; - ERROR <= '0'; - - if clk_edge = '1' then - -- We have a new bit from the keyboard for processing - if bit_count = 0 then - -- Idle state, check for start bit (0) only and don't - -- start counting bits until we get it - - parity <= '0'; - - if ps2_dat_in = '0' then - -- This is a start bit - bit_count <= bit_count + 1; - end if; - else - -- Running. 8-bit data comes in LSb first followed by - -- a single stop bit (1) - if bit_count < 10 then - -- Shift in data and parity (9 bits) - bit_count <= bit_count + 1; - shiftreg <= ps2_dat_in & shiftreg(shiftreg'high downto 1); - parity <= parity xor ps2_dat_in; -- Calculate parity - elsif ps2_dat_in = '1' then - -- Valid stop bit received - bit_count <= (others => '0'); -- back to idle - if parity = '1' then - -- Parity correct, submit data to host - DATA <= shiftreg(7 downto 0); - VALID <= '1'; - else - -- Error - ERROR <= '1'; - end if; - else - -- Invalid stop bit - bit_count <= (others => '0'); -- back to idle - ERROR <= '1'; - end if; - end if; - end if; - end if; - end process; -end ps2_intf_arch; +-- ZX Spectrum for Altera DE1 +-- +-- Copyright (c) 2009-2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +-- PS/2 interface (input only) +-- Based loosely on ps2_ctrl.vhd (c) ALSE. http://www.alse-fr.com +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +-- This is input-only for the time being +entity ps2_intf is +generic (filter_length : positive := 8); +port( + CLK : in std_logic; + nRESET : in std_logic; + + -- PS/2 interface (could be bi-dir) + PS2_CLK : in std_logic; + PS2_DATA : in std_logic; + + -- Byte-wide data interface - only valid for one clock + -- so must be latched externally if required + DATA : out std_logic_vector(7 downto 0); + VALID : out std_logic; + ERROR : out std_logic + ); +end ps2_intf; + +architecture ps2_intf_arch of ps2_intf is +subtype filter_t is std_logic_vector(filter_length-1 downto 0); +signal clk_filter : filter_t; + +signal ps2_clk_in : std_logic; +signal ps2_dat_in : std_logic; +-- Goes high when a clock falling edge is detected +signal clk_edge : std_logic; +signal bit_count : unsigned (3 downto 0); +signal shiftreg : std_logic_vector(8 downto 0); +signal parity : std_logic; +begin + -- Register input signals + process(nRESET,CLK) + begin + if nRESET = '0' then + ps2_clk_in <= '1'; + ps2_dat_in <= '1'; + clk_filter <= (others => '1'); + clk_edge <= '0'; + elsif rising_edge(CLK) then + -- Register inputs (and filter clock) + ps2_dat_in <= PS2_DATA; + clk_filter <= PS2_CLK & clk_filter(clk_filter'high downto 1); + clk_edge <= '0'; + + if clk_filter = filter_t'(others => '1') then + -- Filtered clock is high + ps2_clk_in <= '1'; + elsif clk_filter = filter_t'(others => '0') then + -- Filter clock is low, check for edge + if ps2_clk_in = '1' then + clk_edge <= '1'; + end if; + ps2_clk_in <= '0'; + end if; + end if; + end process; + + -- Shift in keyboard data + process(nRESET,CLK) + begin + if nRESET = '0' then + bit_count <= (others => '0'); + shiftreg <= (others => '0'); + parity <= '0'; + DATA <= (others => '0'); + VALID <= '0'; + ERROR <= '0'; + elsif rising_edge(CLK) then + -- Clear flags + VALID <= '0'; + ERROR <= '0'; + + if clk_edge = '1' then + -- We have a new bit from the keyboard for processing + if bit_count = 0 then + -- Idle state, check for start bit (0) only and don't + -- start counting bits until we get it + + parity <= '0'; + + if ps2_dat_in = '0' then + -- This is a start bit + bit_count <= bit_count + 1; + end if; + else + -- Running. 8-bit data comes in LSb first followed by + -- a single stop bit (1) + if bit_count < 10 then + -- Shift in data and parity (9 bits) + bit_count <= bit_count + 1; + shiftreg <= ps2_dat_in & shiftreg(shiftreg'high downto 1); + parity <= parity xor ps2_dat_in; -- Calculate parity + elsif ps2_dat_in = '1' then + -- Valid stop bit received + bit_count <= (others => '0'); -- back to idle + if parity = '1' then + -- Parity correct, submit data to host + DATA <= shiftreg(7 downto 0); + VALID <= '1'; + else + -- Error + ERROR <= '1'; + end if; + else + -- Invalid stop bit + bit_count <= (others => '0'); -- back to idle + ERROR <= '1'; + end if; + end if; + end if; + end if; + end process; +end ps2_intf_arch; diff --git a/saa5050.vhd b/saa5050.vhd index 57dd999..f198aa8 100644 --- a/saa5050.vhd +++ b/saa5050.vhd @@ -1,391 +1,391 @@ --- BBC Micro for Altera DE1 --- --- Copyright (c) 2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- SAA5050 teletext generator --- --- Synchronous implementation for FPGA. Certain TV-specific functions are --- not implemented. e.g. --- --- No /SI pin - 'TEXT' mode is permanently enabled --- No remote control features (/DATA, DLIM) --- No large character support --- No support for box overlay (BLAN, PO, DE) --- No character rounding, although this may be added --- --- FIXME: Hold graphics not supported - this needs to be added --- --- (C) 2011 Mike Stirling --- -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - -entity saa5050 is -port ( - CLOCK : in std_logic; - -- 6 MHz dot clock enable - CLKEN : in std_logic; - -- Async reset - nRESET : in std_logic; - - -- Character data input (in the bus clock domain) - DI_CLOCK : in std_logic; - DI_CLKEN : in std_logic; - DI : in std_logic_vector(6 downto 0); - - -- Timing inputs - -- General line reset (not used) - GLR : in std_logic; -- /HSYNC - -- Data entry window - high during VSYNC. - -- Resets ROM row counter and drives 'flash' signal - DEW : in std_logic; -- VSYNC - -- Character rounding select - high during even field - CRS : in std_logic; -- FIELD - -- Load output shift register enable - high during active video - LOSE : in std_logic; -- DE - - -- Video out - R : out std_logic; - G : out std_logic; - B : out std_logic; - Y : out std_logic - ); -end entity; - -architecture rtl of saa5050 is - -component saa5050_rom IS - PORT - ( - address : IN STD_LOGIC_VECTOR (11 DOWNTO 0); - clock : IN STD_LOGIC ; - q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) - ); -end component; - --- Register inputs in the bus clock domain -signal di_r : std_logic_vector(6 downto 0); -signal dew_r : std_logic; -signal lose_r : std_logic; --- Data input registered in the pixel clock domain -signal code : std_logic_vector(6 downto 0); -signal line_addr : unsigned(3 downto 0); -signal rom_address : std_logic_vector(11 downto 0); -signal rom_data : std_logic_vector(7 downto 0); - --- Delayed display enable derived from LOSE by delaying for one character -signal disp_enable : std_logic; --- Latched timing signals for detection of falling edges -signal dew_latch : std_logic; -signal lose_latch : std_logic; -signal disp_enable_latch : std_logic; - --- Row and column addressing is handled externally. We just need to --- keep track of which of the 10 lines we are on within the character... -signal line_counter : unsigned(3 downto 0); --- ... and which of the 6 pixels we are on within each line -signal pixel_counter : unsigned(2 downto 0); --- We also need to count frames to implement the flash feature. --- The datasheet says this is 0.75 Hz with a 3:1 on/off ratio, so it --- is probably a /64 counter, which gives us 0.78 Hz -signal flash_counter : unsigned(5 downto 0); --- Output shift register -signal shift_reg : std_logic_vector(5 downto 0); - --- Flash mask -signal flash : std_logic; - --- Current display state --- Foreground colour (B2, G1, R0) -signal fg : std_logic_vector(2 downto 0); --- Background colour (B2, G1, R0) -signal bg : std_logic_vector(2 downto 0); -signal conceal : std_logic; -signal gfx : std_logic; -signal gfx_sep : std_logic; -signal gfx_hold : std_logic; -signal is_flash : std_logic; -signal double_high : std_logic; --- Set in first row of double height -signal double_high1 : std_logic; --- Set in second row of double height -signal double_high2 : std_logic; - -begin - char_rom: saa5050_rom port map ( - rom_address, - CLOCK, - rom_data - ); - - -- Generate flash signal for 3:1 ratio - flash <= flash_counter(5) and flash_counter(4); - - -- Sync inputs - process(DI_CLOCK,nRESET) - begin - if nRESET = '0' then - di_r <= (others => '0'); - dew_r <= '0'; - lose_r <= '0'; - elsif rising_edge(DI_CLOCK) and DI_CLKEN = '1' then - di_r <= DI; - dew_r <= DEW; - lose_r <= LOSE; - end if; - end process; - - -- Register data into pixel clock domain - process(CLOCK,nRESET) - begin - if nRESET = '0' then - code <= (others => '0'); - elsif rising_edge(CLOCK) and CLKEN = '1' then - code <= di_r; - end if; - end process; - - -- Generate character rom address in pixel clock domain - -- This is done combinatorially since all the inputs are already - -- registered and the address is re-registered by the ROM - line_addr <= line_counter when double_high = '0' else - ("0" & line_counter(3 downto 1)) when double_high2 = '0' else - ("0" & line_counter(3 downto 1)) + 5; - rom_address <= (others => '0') when (double_high = '0' and double_high2 = '1') else - gfx & code & std_logic_vector(line_addr); - - -- Character row and pixel counters - process(CLOCK,nRESET) - begin - if nRESET = '0' then - dew_latch <= '0'; - lose_latch <= '0'; - disp_enable <= '0'; - disp_enable_latch <= '0'; - double_high1 <= '0'; - double_high2 <= '0'; - line_counter <= (others => '0'); - pixel_counter <= (others => '0'); - flash_counter <= (others => '0'); - elsif rising_edge(CLOCK) and CLKEN = '1' then - -- Register syncs for edge detection - dew_latch <= dew_r; - lose_latch <= lose_r; - disp_enable_latch <= disp_enable; - - -- When first entering double-height mode start on top row - if double_high = '1' and double_high1 = '0' and double_high2 = '0' then - double_high1 <= '1'; - end if; - - -- Count pixels between 0 and 5 - if pixel_counter = 5 then - -- Start of next character and delayed display enable - pixel_counter <= (others => '0'); - disp_enable <= lose_latch; - else - pixel_counter <= pixel_counter + 1; - end if; - - -- Rising edge of LOSE is the start of the active line - if lose_r = '1' and lose_latch = '0' then - -- Reset pixel counter - small offset to make the output - -- line up with the cursor from the video ULA - pixel_counter <= "011"; - end if; - - -- Count frames on end of VSYNC (falling edge of DEW) - if dew_r = '0' and dew_latch = '1' then - flash_counter <= flash_counter + 1; - end if; - - if dew_r = '1' then - -- Reset line counter and double height state during VSYNC - line_counter <= (others => '0'); - double_high1 <= '0'; - double_high2 <= '0'; - else - -- Count lines on end of active video (falling edge of disp_enable) - if disp_enable = '0' and disp_enable_latch = '1' then - if line_counter = 9 then - line_counter <= (others => '0'); - - -- Keep track of which row we are on for double-height - -- The double_high flag can be cleared before the end of a row, but if - -- double height characters are used anywhere on a row then the double_high1 - -- flag will be set and remain set until the next row. This is used - -- to determine that the bottom half of the characters should be shown if - -- double_high is set once again on the row below. - double_high1 <= '0'; - double_high2 <= double_high1; - else - line_counter <= line_counter + 1; - end if; - end if; - end if; - end if; - end process; - - -- Shift register - process(CLOCK,nRESET) - begin - if nRESET = '0' then - shift_reg <= (others => '0'); - elsif rising_edge(CLOCK) and CLKEN = '1' then - if disp_enable = '1' and pixel_counter = 0 then - -- Load the shift register with the ROM bit pattern - -- at the start of each character while disp_enable is asserted. - shift_reg <= rom_data(5 downto 0); - - -- If bit 7 of the ROM data is set then this is a graphics - -- character and separated/hold graphics modes apply. - -- We don't just assume this to be the case if gfx=1 because - -- these modes don't apply to caps even in graphics mode - if rom_data(7) = '1' then - -- Apply a mask for separated graphics mode - if gfx_sep = '1' then - shift_reg(5) <= '0'; - shift_reg(2) <= '0'; - if line_counter = 2 or line_counter = 6 or line_counter = 9 then - shift_reg <= (others => '0'); - end if; - end if; - end if; - else - -- Pump the shift register - shift_reg <= shift_reg(4 downto 0) & "0"; - end if; - end if; - end process; - - -- Control character handling - process(CLOCK,nRESET) - begin - if nRESET = '0' then - fg <= (others => '1'); - bg <= (others => '0'); - conceal <= '0'; - gfx <= '0'; - gfx_sep <= '0'; - gfx_hold <= '0'; - is_flash <= '0'; - double_high <= '0'; - elsif rising_edge(CLOCK) and CLKEN = '1' then - if disp_enable = '0' then - -- Reset to start of line defaults - fg <= (others => '1'); - bg <= (others => '0'); - conceal <= '0'; - gfx <= '0'; - gfx_sep <= '0'; - gfx_hold <= '0'; - is_flash <= '0'; - double_high <= '0'; - elsif pixel_counter = 0 then - -- Latch new control codes at the start of each character - if code(6 downto 5) = "00" then - if code(3) = '0' then - -- Colour and graphics setting clears conceal mode - conceal <= '0'; - - -- Select graphics or alpha mode - gfx <= code(4); - - -- 0 would be black but is not allowed so has no effect, - -- otherwise set the colour - if code(2 downto 0) /= "000" then - fg <= code(2 downto 0); - end if; - else - case code(4 downto 0) is - -- FLASH - when "01000" => is_flash <= '1'; - -- STEADY - when "01001" => is_flash <= '0'; - -- NORMAL HEIGHT - when "01100" => double_high <= '0'; - -- DOUBLE HEIGHT - when "01101" => double_high <= '1'; - -- CONCEAL - when "11000" => conceal <= '1'; - -- CONTIGUOUS GFX - when "11001" => gfx_sep <= '0'; - -- SEPARATED GFX - when "11010" => gfx_sep <= '1'; - -- BLACK BACKGROUND - when "11100" => bg <= (others => '0'); - -- NEW BACKGROUND - when "11101" => bg <= fg; - -- HOLD GFX - when "11110" => gfx_hold <= '1'; - -- RELEASE GFX - when "11111" => gfx_hold <= '0'; - - when others => null; - end case; - end if; - end if; - end if; - end if; - end process; - - -- Output - process(CLOCK,nRESET) - variable pixel : std_logic; - begin - pixel := shift_reg(5) and not ((flash and is_flash) or conceal); - - if nRESET = '0' then - R <= '0'; - G <= '0'; - B <= '0'; - elsif rising_edge(CLOCK) and CLKEN = '1' then - -- Generate mono output - Y <= pixel; - - -- Generate colour output - if pixel = '1' then - R <= fg(0); - G <= fg(1); - B <= fg(2); - else - R <= bg(0); - G <= bg(1); - B <= bg(2); - end if; - end if; - end process; -end architecture; +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- SAA5050 teletext generator +-- +-- Synchronous implementation for FPGA. Certain TV-specific functions are +-- not implemented. e.g. +-- +-- No /SI pin - 'TEXT' mode is permanently enabled +-- No remote control features (/DATA, DLIM) +-- No large character support +-- No support for box overlay (BLAN, PO, DE) +-- No character rounding, although this may be added +-- +-- FIXME: Hold graphics not supported - this needs to be added +-- +-- (C) 2011 Mike Stirling +-- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity saa5050 is +port ( + CLOCK : in std_logic; + -- 6 MHz dot clock enable + CLKEN : in std_logic; + -- Async reset + nRESET : in std_logic; + + -- Character data input (in the bus clock domain) + DI_CLOCK : in std_logic; + DI_CLKEN : in std_logic; + DI : in std_logic_vector(6 downto 0); + + -- Timing inputs + -- General line reset (not used) + GLR : in std_logic; -- /HSYNC + -- Data entry window - high during VSYNC. + -- Resets ROM row counter and drives 'flash' signal + DEW : in std_logic; -- VSYNC + -- Character rounding select - high during even field + CRS : in std_logic; -- FIELD + -- Load output shift register enable - high during active video + LOSE : in std_logic; -- DE + + -- Video out + R : out std_logic; + G : out std_logic; + B : out std_logic; + Y : out std_logic + ); +end entity; + +architecture rtl of saa5050 is + +component saa5050_rom IS + PORT + ( + address : IN STD_LOGIC_VECTOR (11 DOWNTO 0); + clock : IN STD_LOGIC ; + q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) + ); +end component; + +-- Register inputs in the bus clock domain +signal di_r : std_logic_vector(6 downto 0); +signal dew_r : std_logic; +signal lose_r : std_logic; +-- Data input registered in the pixel clock domain +signal code : std_logic_vector(6 downto 0); +signal line_addr : unsigned(3 downto 0); +signal rom_address : std_logic_vector(11 downto 0); +signal rom_data : std_logic_vector(7 downto 0); + +-- Delayed display enable derived from LOSE by delaying for one character +signal disp_enable : std_logic; +-- Latched timing signals for detection of falling edges +signal dew_latch : std_logic; +signal lose_latch : std_logic; +signal disp_enable_latch : std_logic; + +-- Row and column addressing is handled externally. We just need to +-- keep track of which of the 10 lines we are on within the character... +signal line_counter : unsigned(3 downto 0); +-- ... and which of the 6 pixels we are on within each line +signal pixel_counter : unsigned(2 downto 0); +-- We also need to count frames to implement the flash feature. +-- The datasheet says this is 0.75 Hz with a 3:1 on/off ratio, so it +-- is probably a /64 counter, which gives us 0.78 Hz +signal flash_counter : unsigned(5 downto 0); +-- Output shift register +signal shift_reg : std_logic_vector(5 downto 0); + +-- Flash mask +signal flash : std_logic; + +-- Current display state +-- Foreground colour (B2, G1, R0) +signal fg : std_logic_vector(2 downto 0); +-- Background colour (B2, G1, R0) +signal bg : std_logic_vector(2 downto 0); +signal conceal : std_logic; +signal gfx : std_logic; +signal gfx_sep : std_logic; +signal gfx_hold : std_logic; +signal is_flash : std_logic; +signal double_high : std_logic; +-- Set in first row of double height +signal double_high1 : std_logic; +-- Set in second row of double height +signal double_high2 : std_logic; + +begin + char_rom: saa5050_rom port map ( + rom_address, + CLOCK, + rom_data + ); + + -- Generate flash signal for 3:1 ratio + flash <= flash_counter(5) and flash_counter(4); + + -- Sync inputs + process(DI_CLOCK,nRESET) + begin + if nRESET = '0' then + di_r <= (others => '0'); + dew_r <= '0'; + lose_r <= '0'; + elsif rising_edge(DI_CLOCK) and DI_CLKEN = '1' then + di_r <= DI; + dew_r <= DEW; + lose_r <= LOSE; + end if; + end process; + + -- Register data into pixel clock domain + process(CLOCK,nRESET) + begin + if nRESET = '0' then + code <= (others => '0'); + elsif rising_edge(CLOCK) and CLKEN = '1' then + code <= di_r; + end if; + end process; + + -- Generate character rom address in pixel clock domain + -- This is done combinatorially since all the inputs are already + -- registered and the address is re-registered by the ROM + line_addr <= line_counter when double_high = '0' else + ("0" & line_counter(3 downto 1)) when double_high2 = '0' else + ("0" & line_counter(3 downto 1)) + 5; + rom_address <= (others => '0') when (double_high = '0' and double_high2 = '1') else + gfx & code & std_logic_vector(line_addr); + + -- Character row and pixel counters + process(CLOCK,nRESET) + begin + if nRESET = '0' then + dew_latch <= '0'; + lose_latch <= '0'; + disp_enable <= '0'; + disp_enable_latch <= '0'; + double_high1 <= '0'; + double_high2 <= '0'; + line_counter <= (others => '0'); + pixel_counter <= (others => '0'); + flash_counter <= (others => '0'); + elsif rising_edge(CLOCK) and CLKEN = '1' then + -- Register syncs for edge detection + dew_latch <= dew_r; + lose_latch <= lose_r; + disp_enable_latch <= disp_enable; + + -- When first entering double-height mode start on top row + if double_high = '1' and double_high1 = '0' and double_high2 = '0' then + double_high1 <= '1'; + end if; + + -- Count pixels between 0 and 5 + if pixel_counter = 5 then + -- Start of next character and delayed display enable + pixel_counter <= (others => '0'); + disp_enable <= lose_latch; + else + pixel_counter <= pixel_counter + 1; + end if; + + -- Rising edge of LOSE is the start of the active line + if lose_r = '1' and lose_latch = '0' then + -- Reset pixel counter - small offset to make the output + -- line up with the cursor from the video ULA + pixel_counter <= "011"; + end if; + + -- Count frames on end of VSYNC (falling edge of DEW) + if dew_r = '0' and dew_latch = '1' then + flash_counter <= flash_counter + 1; + end if; + + if dew_r = '1' then + -- Reset line counter and double height state during VSYNC + line_counter <= (others => '0'); + double_high1 <= '0'; + double_high2 <= '0'; + else + -- Count lines on end of active video (falling edge of disp_enable) + if disp_enable = '0' and disp_enable_latch = '1' then + if line_counter = 9 then + line_counter <= (others => '0'); + + -- Keep track of which row we are on for double-height + -- The double_high flag can be cleared before the end of a row, but if + -- double height characters are used anywhere on a row then the double_high1 + -- flag will be set and remain set until the next row. This is used + -- to determine that the bottom half of the characters should be shown if + -- double_high is set once again on the row below. + double_high1 <= '0'; + double_high2 <= double_high1; + else + line_counter <= line_counter + 1; + end if; + end if; + end if; + end if; + end process; + + -- Shift register + process(CLOCK,nRESET) + begin + if nRESET = '0' then + shift_reg <= (others => '0'); + elsif rising_edge(CLOCK) and CLKEN = '1' then + if disp_enable = '1' and pixel_counter = 0 then + -- Load the shift register with the ROM bit pattern + -- at the start of each character while disp_enable is asserted. + shift_reg <= rom_data(5 downto 0); + + -- If bit 7 of the ROM data is set then this is a graphics + -- character and separated/hold graphics modes apply. + -- We don't just assume this to be the case if gfx=1 because + -- these modes don't apply to caps even in graphics mode + if rom_data(7) = '1' then + -- Apply a mask for separated graphics mode + if gfx_sep = '1' then + shift_reg(5) <= '0'; + shift_reg(2) <= '0'; + if line_counter = 2 or line_counter = 6 or line_counter = 9 then + shift_reg <= (others => '0'); + end if; + end if; + end if; + else + -- Pump the shift register + shift_reg <= shift_reg(4 downto 0) & "0"; + end if; + end if; + end process; + + -- Control character handling + process(CLOCK,nRESET) + begin + if nRESET = '0' then + fg <= (others => '1'); + bg <= (others => '0'); + conceal <= '0'; + gfx <= '0'; + gfx_sep <= '0'; + gfx_hold <= '0'; + is_flash <= '0'; + double_high <= '0'; + elsif rising_edge(CLOCK) and CLKEN = '1' then + if disp_enable = '0' then + -- Reset to start of line defaults + fg <= (others => '1'); + bg <= (others => '0'); + conceal <= '0'; + gfx <= '0'; + gfx_sep <= '0'; + gfx_hold <= '0'; + is_flash <= '0'; + double_high <= '0'; + elsif pixel_counter = 0 then + -- Latch new control codes at the start of each character + if code(6 downto 5) = "00" then + if code(3) = '0' then + -- Colour and graphics setting clears conceal mode + conceal <= '0'; + + -- Select graphics or alpha mode + gfx <= code(4); + + -- 0 would be black but is not allowed so has no effect, + -- otherwise set the colour + if code(2 downto 0) /= "000" then + fg <= code(2 downto 0); + end if; + else + case code(4 downto 0) is + -- FLASH + when "01000" => is_flash <= '1'; + -- STEADY + when "01001" => is_flash <= '0'; + -- NORMAL HEIGHT + when "01100" => double_high <= '0'; + -- DOUBLE HEIGHT + when "01101" => double_high <= '1'; + -- CONCEAL + when "11000" => conceal <= '1'; + -- CONTIGUOUS GFX + when "11001" => gfx_sep <= '0'; + -- SEPARATED GFX + when "11010" => gfx_sep <= '1'; + -- BLACK BACKGROUND + when "11100" => bg <= (others => '0'); + -- NEW BACKGROUND + when "11101" => bg <= fg; + -- HOLD GFX + when "11110" => gfx_hold <= '1'; + -- RELEASE GFX + when "11111" => gfx_hold <= '0'; + + when others => null; + end case; + end if; + end if; + end if; + end if; + end process; + + -- Output + process(CLOCK,nRESET) + variable pixel : std_logic; + begin + pixel := shift_reg(5) and not ((flash and is_flash) or conceal); + + if nRESET = '0' then + R <= '0'; + G <= '0'; + B <= '0'; + elsif rising_edge(CLOCK) and CLKEN = '1' then + -- Generate mono output + Y <= pixel; + + -- Generate colour output + if pixel = '1' then + R <= fg(0); + G <= fg(1); + B <= fg(2); + else + R <= bg(0); + G <= bg(1); + B <= bg(2); + end if; + end if; + end process; +end architecture; diff --git a/saa5050_rom.qip b/saa5050_rom.qip index e9513f7..be776f1 100644 --- a/saa5050_rom.qip +++ b/saa5050_rom.qip @@ -1,3 +1,3 @@ -set_global_assignment -name IP_TOOL_NAME "ROM: 1-PORT" -set_global_assignment -name IP_TOOL_VERSION "9.1" -set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "saa5050_rom.vhd"] +set_global_assignment -name IP_TOOL_NAME "ROM: 1-PORT" +set_global_assignment -name IP_TOOL_VERSION "9.1" +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "saa5050_rom.vhd"] diff --git a/saa5050_rom.vhd b/saa5050_rom.vhd index 7541c0b..e1c702d 100644 --- a/saa5050_rom.vhd +++ b/saa5050_rom.vhd @@ -1,168 +1,168 @@ --- megafunction wizard: %ROM: 1-PORT% --- GENERATION: STANDARD --- VERSION: WM1.0 --- MODULE: altsyncram - --- ============================================================ --- File Name: saa5050_rom.vhd --- Megafunction Name(s): --- altsyncram --- --- Simulation Library Files(s): --- altera_mf --- ============================================================ --- ************************************************************ --- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! --- --- 9.1 Build 222 10/21/2009 SJ Web Edition --- ************************************************************ - - ---Copyright (C) 1991-2009 Altera Corporation ---Your use of Altera Corporation's design tools, logic functions ---and other software and tools, and its AMPP partner logic ---functions, and any output files from any of the foregoing ---(including device programming or simulation files), and any ---associated documentation or information are expressly subject ---to the terms and conditions of the Altera Program License ---Subscription Agreement, Altera MegaCore Function License ---Agreement, or other applicable license agreement, including, ---without limitation, that your use is for the sole purpose of ---programming logic devices manufactured by Altera and sold by ---Altera or its authorized distributors. Please refer to the ---applicable agreement for further details. - - -LIBRARY ieee; -USE ieee.std_logic_1164.all; - -LIBRARY altera_mf; -USE altera_mf.all; - -ENTITY saa5050_rom IS - PORT - ( - address : IN STD_LOGIC_VECTOR (11 DOWNTO 0); - clock : IN STD_LOGIC ; - q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) - ); -END saa5050_rom; - - -ARCHITECTURE SYN OF saa5050_rom IS - - SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0); - - - - COMPONENT altsyncram - GENERIC ( - clock_enable_input_a : STRING; - clock_enable_output_a : STRING; - init_file : STRING; - intended_device_family : STRING; - lpm_hint : STRING; - lpm_type : STRING; - numwords_a : NATURAL; - operation_mode : STRING; - outdata_aclr_a : STRING; - outdata_reg_a : STRING; - widthad_a : NATURAL; - width_a : NATURAL; - width_byteena_a : NATURAL - ); - PORT ( - clock0 : IN STD_LOGIC ; - address_a : IN STD_LOGIC_VECTOR (11 DOWNTO 0); - q_a : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) - ); - END COMPONENT; - -BEGIN - q <= sub_wire0(7 DOWNTO 0); - - altsyncram_component : altsyncram - GENERIC MAP ( - clock_enable_input_a => "BYPASS", - clock_enable_output_a => "BYPASS", - init_file => "./roms/saa5050/saa5050.hex", - intended_device_family => "Cyclone II", - lpm_hint => "ENABLE_RUNTIME_MOD=NO", - lpm_type => "altsyncram", - numwords_a => 4096, - operation_mode => "ROM", - outdata_aclr_a => "NONE", - outdata_reg_a => "UNREGISTERED", - widthad_a => 12, - width_a => 8, - width_byteena_a => 1 - ) - PORT MAP ( - clock0 => clock, - address_a => address, - q_a => sub_wire0 - ); - - - -END SYN; - --- ============================================================ --- CNX file retrieval info --- ============================================================ --- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" --- Retrieval info: PRIVATE: AclrAddr NUMERIC "0" --- Retrieval info: PRIVATE: AclrByte NUMERIC "0" --- Retrieval info: PRIVATE: AclrOutput NUMERIC "0" --- Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" --- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" --- Retrieval info: PRIVATE: BlankMemory NUMERIC "0" --- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" --- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" --- Retrieval info: PRIVATE: Clken NUMERIC "0" --- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" --- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" --- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" --- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" --- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" --- Retrieval info: PRIVATE: JTAG_ID STRING "NONE" --- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" --- Retrieval info: PRIVATE: MIFfilename STRING "./roms/saa5050/saa5050.hex" --- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "4096" --- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" --- Retrieval info: PRIVATE: RegAddr NUMERIC "1" --- Retrieval info: PRIVATE: RegOutput NUMERIC "0" --- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" --- Retrieval info: PRIVATE: SingleClock NUMERIC "1" --- Retrieval info: PRIVATE: UseDQRAM NUMERIC "0" --- Retrieval info: PRIVATE: WidthAddr NUMERIC "12" --- Retrieval info: PRIVATE: WidthData NUMERIC "8" --- Retrieval info: PRIVATE: rden NUMERIC "0" --- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" --- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" --- Retrieval info: CONSTANT: INIT_FILE STRING "./roms/saa5050/saa5050.hex" --- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" --- Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO" --- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" --- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "4096" --- Retrieval info: CONSTANT: OPERATION_MODE STRING "ROM" --- Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" --- Retrieval info: CONSTANT: OUTDATA_REG_A STRING "UNREGISTERED" --- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "12" --- Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" --- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" --- Retrieval info: USED_PORT: address 0 0 12 0 INPUT NODEFVAL address[11..0] --- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock --- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL q[7..0] --- Retrieval info: CONNECT: @address_a 0 0 12 0 address 0 0 12 0 --- Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 --- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 --- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all --- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.vhd TRUE --- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.inc FALSE --- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.cmp FALSE --- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.bsf FALSE --- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_inst.vhd FALSE --- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_waveforms.html FALSE --- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_wave*.jpg FALSE --- Retrieval info: LIB_FILE: altera_mf +-- megafunction wizard: %ROM: 1-PORT% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altsyncram + +-- ============================================================ +-- File Name: saa5050_rom.vhd +-- Megafunction Name(s): +-- altsyncram +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 9.1 Build 222 10/21/2009 SJ Web Edition +-- ************************************************************ + + +--Copyright (C) 1991-2009 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY saa5050_rom IS + PORT + ( + address : IN STD_LOGIC_VECTOR (11 DOWNTO 0); + clock : IN STD_LOGIC ; + q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) + ); +END saa5050_rom; + + +ARCHITECTURE SYN OF saa5050_rom IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0); + + + + COMPONENT altsyncram + GENERIC ( + clock_enable_input_a : STRING; + clock_enable_output_a : STRING; + init_file : STRING; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + numwords_a : NATURAL; + operation_mode : STRING; + outdata_aclr_a : STRING; + outdata_reg_a : STRING; + widthad_a : NATURAL; + width_a : NATURAL; + width_byteena_a : NATURAL + ); + PORT ( + clock0 : IN STD_LOGIC ; + address_a : IN STD_LOGIC_VECTOR (11 DOWNTO 0); + q_a : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + q <= sub_wire0(7 DOWNTO 0); + + altsyncram_component : altsyncram + GENERIC MAP ( + clock_enable_input_a => "BYPASS", + clock_enable_output_a => "BYPASS", + init_file => "./roms/saa5050/saa5050.hex", + intended_device_family => "Cyclone II", + lpm_hint => "ENABLE_RUNTIME_MOD=NO", + lpm_type => "altsyncram", + numwords_a => 4096, + operation_mode => "ROM", + outdata_aclr_a => "NONE", + outdata_reg_a => "UNREGISTERED", + widthad_a => 12, + width_a => 8, + width_byteena_a => 1 + ) + PORT MAP ( + clock0 => clock, + address_a => address, + q_a => sub_wire0 + ); + + + +END SYN; + +-- ============================================================ +-- CNX file retrieval info +-- ============================================================ +-- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" +-- Retrieval info: PRIVATE: AclrAddr NUMERIC "0" +-- Retrieval info: PRIVATE: AclrByte NUMERIC "0" +-- Retrieval info: PRIVATE: AclrOutput NUMERIC "0" +-- Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" +-- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" +-- Retrieval info: PRIVATE: BlankMemory NUMERIC "0" +-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" +-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" +-- Retrieval info: PRIVATE: Clken NUMERIC "0" +-- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" +-- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" +-- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" +-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +-- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" +-- Retrieval info: PRIVATE: JTAG_ID STRING "NONE" +-- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" +-- Retrieval info: PRIVATE: MIFfilename STRING "./roms/saa5050/saa5050.hex" +-- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "4096" +-- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +-- Retrieval info: PRIVATE: RegAddr NUMERIC "1" +-- Retrieval info: PRIVATE: RegOutput NUMERIC "0" +-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +-- Retrieval info: PRIVATE: SingleClock NUMERIC "1" +-- Retrieval info: PRIVATE: UseDQRAM NUMERIC "0" +-- Retrieval info: PRIVATE: WidthAddr NUMERIC "12" +-- Retrieval info: PRIVATE: WidthData NUMERIC "8" +-- Retrieval info: PRIVATE: rden NUMERIC "0" +-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" +-- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" +-- Retrieval info: CONSTANT: INIT_FILE STRING "./roms/saa5050/saa5050.hex" +-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +-- Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO" +-- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" +-- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "4096" +-- Retrieval info: CONSTANT: OPERATION_MODE STRING "ROM" +-- Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" +-- Retrieval info: CONSTANT: OUTDATA_REG_A STRING "UNREGISTERED" +-- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "12" +-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +-- Retrieval info: USED_PORT: address 0 0 12 0 INPUT NODEFVAL address[11..0] +-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock +-- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL q[7..0] +-- Retrieval info: CONNECT: @address_a 0 0 12 0 address 0 0 12 0 +-- Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 +-- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.cmp FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_inst.vhd FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_waveforms.html FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_wave*.jpg FALSE +-- Retrieval info: LIB_FILE: altera_mf diff --git a/seg7.vhd b/seg7.vhd index a61e679..566b1f6 100644 --- a/seg7.vhd +++ b/seg7.vhd @@ -1,68 +1,68 @@ --- BBC Micro for Altera DE1 --- --- Copyright (c) 2009-2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- - -library ieee; -use ieee.std_logic_1164.all; - --- Convert BCD to 7-segment display characters -entity seg7 is -port ( - D : in std_logic_vector(3 downto 0); - Q : out std_logic_vector(6 downto 0) -); -end seg7; - -architecture seg7_arch of seg7 is -begin - Q <= "1000000" when D = "0000" else - "1111001" when D = "0001" else - "0100100" when D = "0010" else - "0110000" when D = "0011" else - "0011001" when D = "0100" else - "0010010" when D = "0101" else - "0000010" when D = "0110" else - "1111000" when D = "0111" else - "0000000" when D = "1000" else - "0010000" when D = "1001" else - "0001000" when D = "1010" else - "0000011" when D = "1011" else - "1000110" when D = "1100" else - "0100001" when D = "1101" else - "0000110" when D = "1110" else - "0001110"; -end seg7_arch; - +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2009-2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- + +library ieee; +use ieee.std_logic_1164.all; + +-- Convert BCD to 7-segment display characters +entity seg7 is +port ( + D : in std_logic_vector(3 downto 0); + Q : out std_logic_vector(6 downto 0) +); +end seg7; + +architecture seg7_arch of seg7 is +begin + Q <= "1000000" when D = "0000" else + "1111001" when D = "0001" else + "0100100" when D = "0010" else + "0110000" when D = "0011" else + "0011001" when D = "0100" else + "0010010" when D = "0101" else + "0000010" when D = "0110" else + "1111000" when D = "0111" else + "0000000" when D = "1000" else + "0010000" when D = "1001" else + "0001000" when D = "1010" else + "0000011" when D = "1011" else + "1000110" when D = "1100" else + "0100001" when D = "1101" else + "0000110" when D = "1110" else + "0001110"; +end seg7_arch; + diff --git a/sn76489-1.0/sn76489_top.vhd b/sn76489-1.0/sn76489_top.vhd index 277f601..deb8170 100644 --- a/sn76489-1.0/sn76489_top.vhd +++ b/sn76489-1.0/sn76489_top.vhd @@ -196,15 +196,15 @@ begin noise_o => noise_s ); - + -- Register output - process(clock_i) - begin - if res_n_i = '0' then - aout_o <= (others => '0'); - elsif rising_edge(clock_i) then - aout_o <= tone1_s + tone2_s + tone3_s + noise_s; - end if; - end process; + process(clock_i) + begin + if res_n_i = '0' then + aout_o <= (others => '0'); + elsif rising_edge(clock_i) then + aout_o <= tone1_s + tone2_s + tone3_s + noise_s; + end if; + end process; end struct; diff --git a/vidproc.vhd b/vidproc.vhd index 6d5f91f..25f3d75 100644 --- a/vidproc.vhd +++ b/vidproc.vhd @@ -1,279 +1,279 @@ --- BBC Micro for Altera DE1 --- --- Copyright (c) 2011 Mike Stirling --- --- All rights reserved --- --- Redistribution and use in source and synthezised forms, with or without --- modification, are permitted provided that the following conditions are met: --- --- * Redistributions of source code must retain the above copyright notice, --- this list of conditions and the following disclaimer. --- --- * Redistributions in synthesized form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- --- * Neither the name of the author nor the names of other contributors may --- be used to endorse or promote products derived from this software without --- specific prior written agreement from the author. --- --- * License is granted for non-commercial use only. A fee may not be charged --- for redistributions as source code or in synthesized/hardware form without --- specific prior written agreement from the author. --- --- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" --- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, --- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR --- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE --- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR --- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF --- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS --- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN --- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) --- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE --- POSSIBILITY OF SUCH DAMAGE. --- --- BBC Micro "VIDPROC" Video ULA --- --- Synchronous implementation for FPGA --- --- (C) 2011 Mike Stirling --- -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - -entity vidproc is -port ( - CLOCK : in std_logic; - -- Clock enable qualifies display cycles (interleaved with CPU cycles) - CLKEN : in std_logic; - nRESET : in std_logic; - - -- Clock enable output to CRTC - CLKEN_CRTC : out std_logic; - - -- Bus interface - ENABLE : in std_logic; - A0 : in std_logic; - -- CPU data bus (for register writes) - DI_CPU : in std_logic_vector(7 downto 0); - -- Display RAM data bus (for display data fetch) - DI_RAM : in std_logic_vector(7 downto 0); - - -- Control interface - nINVERT : in std_logic; - DISEN : in std_logic; - CURSOR : in std_logic; - - -- Video in (teletext mode) - R_IN : in std_logic; - G_IN : in std_logic; - B_IN : in std_logic; - - -- Video out - R : out std_logic; - G : out std_logic; - B : out std_logic - ); -end entity; - -architecture rtl of vidproc is --- Write-only registers -signal r0_cursor0 : std_logic; -signal r0_cursor1 : std_logic; -signal r0_cursor2 : std_logic; -signal r0_crtc_2mhz : std_logic; -signal r0_pixel_rate : std_logic_vector(1 downto 0); -signal r0_teletext : std_logic; -signal r0_flash : std_logic; - -type palette_t is array(0 to 15) of std_logic_vector(3 downto 0); -signal palette : palette_t; - --- Pixel shift register -signal shiftreg : std_logic_vector(7 downto 0); --- Delayed display enable -signal delayed_disen : std_logic; - --- Internal clock enable generation -signal clken_pixel : std_logic; -signal clken_fetch : std_logic; -signal clken_counter : unsigned(3 downto 0); - --- Cursor generation - can span up to 32 pixels --- Segments 0 and 1 are 8 pixels wide --- Segment 2 is 16 pixels wide -signal cursor_invert : std_logic; -signal cursor_active : std_logic; -signal cursor_counter : unsigned(1 downto 0); - -begin - -- Synchronous register access, enabled on every clock - process(CLOCK,nRESET) - begin - if nRESET = '0' then - r0_cursor0 <= '0'; - r0_cursor1 <= '0'; - r0_cursor2 <= '0'; - r0_crtc_2mhz <= '0'; - r0_pixel_rate <= "00"; - r0_teletext <= '0'; - r0_flash <= '0'; - - for colour in 0 to 15 loop - palette(colour) <= (others => '0'); - end loop; - elsif rising_edge(CLOCK) then - if ENABLE = '1' then - if A0 = '0' then - -- Access control register - r0_cursor0 <= DI_CPU(7); - r0_cursor1 <= DI_CPU(6); - r0_cursor2 <= DI_CPU(5); - r0_crtc_2mhz <= DI_CPU(4); - r0_pixel_rate <= DI_CPU(3 downto 2); - r0_teletext <= DI_CPU(1); - r0_flash <= DI_CPU(0); - else - -- Access palette register - palette(to_integer(unsigned(DI_CPU(7 downto 4)))) <= DI_CPU(3 downto 0); - end if; - end if; - end if; - end process; - - -- Clock enable generation. - -- Pixel clock can be divided by 1,2,4 or 8 depending on the value - -- programmed at r0_pixel_rate - -- 00 = /8, 01 = /4, 10 = /2, 11 = /1 - clken_pixel <= - CLKEN when r0_pixel_rate = "11" else - (CLKEN and not clken_counter(0)) when r0_pixel_rate = "10" else - (CLKEN and not (clken_counter(0) or clken_counter(1))) when r0_pixel_rate = "01" else - (CLKEN and not (clken_counter(0) or clken_counter(1) or clken_counter(2))); - -- The CRT controller is always enabled in the 15th cycle, so that the result - -- is ready for latching into the shift register in cycle 0. If 2 MHz mode is - -- selected then the CRTC is also enabled in the 7th cycle - CLKEN_CRTC <= CLKEN and - clken_counter(0) and clken_counter(1) and clken_counter(2) and - (clken_counter(3) or r0_crtc_2mhz); - -- The result is fetched from the CRTC in cycle 0 and also cycle 8 if 2 MHz - -- mode is selected. This is used for reloading the shift register as well as - -- counting cursor pixels - clken_fetch <= CLKEN and not (clken_counter(0) or clken_counter(1) or clken_counter(2) or - (clken_counter(3) and not r0_crtc_2mhz)); - - process(CLOCK,nRESET) - begin - if nRESET = '0' then - clken_counter <= (others => '0'); - elsif rising_edge(CLOCK) and CLKEN = '1' then - -- Increment internal cycle counter during each video clock - clken_counter <= clken_counter + 1; - end if; - end process; - - -- Fetch control - process(CLOCK,nRESET) - begin - if nRESET = '0' then - shiftreg <= (others => '0'); - elsif rising_edge(CLOCK) and clken_pixel = '1' then - if clken_fetch = '1' then - -- Fetch next byte from RAM into shift register. This always occurs in - -- cycle 0, and also in cycle 8 if the CRTC is clocked at double rate. - shiftreg <= DI_RAM; - else - -- Clock shift register and input '1' at LSB - shiftreg <= shiftreg(6 downto 0) & "1"; - end if; - end if; - end process; - - -- Cursor generation - cursor_invert <= cursor_active and - ((r0_cursor0 and not (cursor_counter(0) or cursor_counter(1))) or - (r0_cursor1 and cursor_counter(0) and not cursor_counter(1)) or - (r0_cursor2 and cursor_counter(1))); - process(CLOCK,nRESET) - begin - if nRESET = '0' then - cursor_active <= '0'; - cursor_counter <= (others => '0'); - elsif rising_edge(CLOCK) and clken_fetch = '1' then - if CURSOR = '1' or cursor_active = '1' then - -- Latch cursor - cursor_active <= '1'; - - -- Reset on counter wrap - if cursor_counter = "11" then - cursor_active <= '0'; - end if; - - -- Increment counter - if cursor_active = '0' then - -- Reset - cursor_counter <= (others => '0'); - else - -- Increment - cursor_counter <= cursor_counter + 1; - end if; - end if; - end if; - end process; - - -- Pixel generation - -- The new shift register contents are loaded during - -- cycle 0 (and 8) but will not be read here until the next cycle. - -- By running this process on every single video tick instead of at - -- the pixel rate we ensure that the resulting delay is minimal and - -- constant (running this at the pixel rate would cause - -- the display to move slightly depending on which mode was selected). - process(CLOCK,nRESET) - variable palette_a : std_logic_vector(3 downto 0); - variable dot_val : std_logic_vector(3 downto 0); - variable red_val : std_logic; - variable green_val : std_logic; - variable blue_val : std_logic; - begin - if nRESET = '0' then - R <= '0'; - G <= '0'; - B <= '0'; - delayed_disen <= '0'; - elsif rising_edge(CLOCK) and CLKEN = '1' then - -- Look up dot value in the palette. Bits are as follows: - -- bit 3 - FLASH - -- bit 2 - Not BLUE - -- bit 1 - Not GREEN - -- bit 0 - Not RED - palette_a := shiftreg(7) & shiftreg(5) & shiftreg(3) & shiftreg(1); - dot_val := palette(to_integer(unsigned(palette_a))); - - -- Apply flash inversion if required - red_val := (dot_val(3) and r0_flash) xor not dot_val(0); - green_val := (dot_val(3) and r0_flash) xor not dot_val(1); - blue_val := (dot_val(3) and r0_flash) xor not dot_val(2); - - -- To output - -- FIXME: INVERT option - if r0_teletext = '0' then - -- Cursor can extend outside the bounds of the screen, so - -- it is not affected by DISEN - R <= (red_val and delayed_disen) xor cursor_invert; - G <= (green_val and delayed_disen) xor cursor_invert; - B <= (blue_val and delayed_disen) xor cursor_invert; - else - R <= R_IN xor cursor_invert; - G <= G_IN xor cursor_invert; - B <= B_IN xor cursor_invert; - end if; - - -- Display enable signal delayed by one clock - delayed_disen <= DISEN; - end if; - end process; -end architecture; - +-- BBC Micro for Altera DE1 +-- +-- Copyright (c) 2011 Mike Stirling +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- * Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- * Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- * Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written agreement from the author. +-- +-- * License is granted for non-commercial use only. A fee may not be charged +-- for redistributions as source code or in synthesized/hardware form without +-- specific prior written agreement from the author. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- BBC Micro "VIDPROC" Video ULA +-- +-- Synchronous implementation for FPGA +-- +-- (C) 2011 Mike Stirling +-- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity vidproc is +port ( + CLOCK : in std_logic; + -- Clock enable qualifies display cycles (interleaved with CPU cycles) + CLKEN : in std_logic; + nRESET : in std_logic; + + -- Clock enable output to CRTC + CLKEN_CRTC : out std_logic; + + -- Bus interface + ENABLE : in std_logic; + A0 : in std_logic; + -- CPU data bus (for register writes) + DI_CPU : in std_logic_vector(7 downto 0); + -- Display RAM data bus (for display data fetch) + DI_RAM : in std_logic_vector(7 downto 0); + + -- Control interface + nINVERT : in std_logic; + DISEN : in std_logic; + CURSOR : in std_logic; + + -- Video in (teletext mode) + R_IN : in std_logic; + G_IN : in std_logic; + B_IN : in std_logic; + + -- Video out + R : out std_logic; + G : out std_logic; + B : out std_logic + ); +end entity; + +architecture rtl of vidproc is +-- Write-only registers +signal r0_cursor0 : std_logic; +signal r0_cursor1 : std_logic; +signal r0_cursor2 : std_logic; +signal r0_crtc_2mhz : std_logic; +signal r0_pixel_rate : std_logic_vector(1 downto 0); +signal r0_teletext : std_logic; +signal r0_flash : std_logic; + +type palette_t is array(0 to 15) of std_logic_vector(3 downto 0); +signal palette : palette_t; + +-- Pixel shift register +signal shiftreg : std_logic_vector(7 downto 0); +-- Delayed display enable +signal delayed_disen : std_logic; + +-- Internal clock enable generation +signal clken_pixel : std_logic; +signal clken_fetch : std_logic; +signal clken_counter : unsigned(3 downto 0); + +-- Cursor generation - can span up to 32 pixels +-- Segments 0 and 1 are 8 pixels wide +-- Segment 2 is 16 pixels wide +signal cursor_invert : std_logic; +signal cursor_active : std_logic; +signal cursor_counter : unsigned(1 downto 0); + +begin + -- Synchronous register access, enabled on every clock + process(CLOCK,nRESET) + begin + if nRESET = '0' then + r0_cursor0 <= '0'; + r0_cursor1 <= '0'; + r0_cursor2 <= '0'; + r0_crtc_2mhz <= '0'; + r0_pixel_rate <= "00"; + r0_teletext <= '0'; + r0_flash <= '0'; + + for colour in 0 to 15 loop + palette(colour) <= (others => '0'); + end loop; + elsif rising_edge(CLOCK) then + if ENABLE = '1' then + if A0 = '0' then + -- Access control register + r0_cursor0 <= DI_CPU(7); + r0_cursor1 <= DI_CPU(6); + r0_cursor2 <= DI_CPU(5); + r0_crtc_2mhz <= DI_CPU(4); + r0_pixel_rate <= DI_CPU(3 downto 2); + r0_teletext <= DI_CPU(1); + r0_flash <= DI_CPU(0); + else + -- Access palette register + palette(to_integer(unsigned(DI_CPU(7 downto 4)))) <= DI_CPU(3 downto 0); + end if; + end if; + end if; + end process; + + -- Clock enable generation. + -- Pixel clock can be divided by 1,2,4 or 8 depending on the value + -- programmed at r0_pixel_rate + -- 00 = /8, 01 = /4, 10 = /2, 11 = /1 + clken_pixel <= + CLKEN when r0_pixel_rate = "11" else + (CLKEN and not clken_counter(0)) when r0_pixel_rate = "10" else + (CLKEN and not (clken_counter(0) or clken_counter(1))) when r0_pixel_rate = "01" else + (CLKEN and not (clken_counter(0) or clken_counter(1) or clken_counter(2))); + -- The CRT controller is always enabled in the 15th cycle, so that the result + -- is ready for latching into the shift register in cycle 0. If 2 MHz mode is + -- selected then the CRTC is also enabled in the 7th cycle + CLKEN_CRTC <= CLKEN and + clken_counter(0) and clken_counter(1) and clken_counter(2) and + (clken_counter(3) or r0_crtc_2mhz); + -- The result is fetched from the CRTC in cycle 0 and also cycle 8 if 2 MHz + -- mode is selected. This is used for reloading the shift register as well as + -- counting cursor pixels + clken_fetch <= CLKEN and not (clken_counter(0) or clken_counter(1) or clken_counter(2) or + (clken_counter(3) and not r0_crtc_2mhz)); + + process(CLOCK,nRESET) + begin + if nRESET = '0' then + clken_counter <= (others => '0'); + elsif rising_edge(CLOCK) and CLKEN = '1' then + -- Increment internal cycle counter during each video clock + clken_counter <= clken_counter + 1; + end if; + end process; + + -- Fetch control + process(CLOCK,nRESET) + begin + if nRESET = '0' then + shiftreg <= (others => '0'); + elsif rising_edge(CLOCK) and clken_pixel = '1' then + if clken_fetch = '1' then + -- Fetch next byte from RAM into shift register. This always occurs in + -- cycle 0, and also in cycle 8 if the CRTC is clocked at double rate. + shiftreg <= DI_RAM; + else + -- Clock shift register and input '1' at LSB + shiftreg <= shiftreg(6 downto 0) & "1"; + end if; + end if; + end process; + + -- Cursor generation + cursor_invert <= cursor_active and + ((r0_cursor0 and not (cursor_counter(0) or cursor_counter(1))) or + (r0_cursor1 and cursor_counter(0) and not cursor_counter(1)) or + (r0_cursor2 and cursor_counter(1))); + process(CLOCK,nRESET) + begin + if nRESET = '0' then + cursor_active <= '0'; + cursor_counter <= (others => '0'); + elsif rising_edge(CLOCK) and clken_fetch = '1' then + if CURSOR = '1' or cursor_active = '1' then + -- Latch cursor + cursor_active <= '1'; + + -- Reset on counter wrap + if cursor_counter = "11" then + cursor_active <= '0'; + end if; + + -- Increment counter + if cursor_active = '0' then + -- Reset + cursor_counter <= (others => '0'); + else + -- Increment + cursor_counter <= cursor_counter + 1; + end if; + end if; + end if; + end process; + + -- Pixel generation + -- The new shift register contents are loaded during + -- cycle 0 (and 8) but will not be read here until the next cycle. + -- By running this process on every single video tick instead of at + -- the pixel rate we ensure that the resulting delay is minimal and + -- constant (running this at the pixel rate would cause + -- the display to move slightly depending on which mode was selected). + process(CLOCK,nRESET) + variable palette_a : std_logic_vector(3 downto 0); + variable dot_val : std_logic_vector(3 downto 0); + variable red_val : std_logic; + variable green_val : std_logic; + variable blue_val : std_logic; + begin + if nRESET = '0' then + R <= '0'; + G <= '0'; + B <= '0'; + delayed_disen <= '0'; + elsif rising_edge(CLOCK) and CLKEN = '1' then + -- Look up dot value in the palette. Bits are as follows: + -- bit 3 - FLASH + -- bit 2 - Not BLUE + -- bit 1 - Not GREEN + -- bit 0 - Not RED + palette_a := shiftreg(7) & shiftreg(5) & shiftreg(3) & shiftreg(1); + dot_val := palette(to_integer(unsigned(palette_a))); + + -- Apply flash inversion if required + red_val := (dot_val(3) and r0_flash) xor not dot_val(0); + green_val := (dot_val(3) and r0_flash) xor not dot_val(1); + blue_val := (dot_val(3) and r0_flash) xor not dot_val(2); + + -- To output + -- FIXME: INVERT option + if r0_teletext = '0' then + -- Cursor can extend outside the bounds of the screen, so + -- it is not affected by DISEN + R <= (red_val and delayed_disen) xor cursor_invert; + G <= (green_val and delayed_disen) xor cursor_invert; + B <= (blue_val and delayed_disen) xor cursor_invert; + else + R <= R_IN xor cursor_invert; + G <= G_IN xor cursor_invert; + B <= B_IN xor cursor_invert; + end if; + + -- Display enable signal delayed by one clock + delayed_disen <= DISEN; + end if; + end process; +end architecture; +