summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@lab.panaceas.james.local>2013-10-18 11:03:26 +0100
committerroot <root@lab.panaceas.james.local>2013-10-18 11:03:26 +0100
commit6f6a0c3344ea905979901065cf723bdf168c1bf1 (patch)
tree2ac8dd82c35368525721c00f53ceb0142a7c5f46
downloadbbc_de1-6f6a0c3344ea905979901065cf723bdf168c1bf1.tar.gz
bbc_de1-6f6a0c3344ea905979901065cf723bdf168c1bf1.tar.bz2
bbc_de1-6f6a0c3344ea905979901065cf723bdf168c1bf1.zip
start
-rw-r--r--quartus/CII_Starter_pin_assignments.csv455
-rw-r--r--quartus/README6
-rw-r--r--quartus/T65/T65.vhd564
-rw-r--r--quartus/T65/T65_ALU.vhd260
-rw-r--r--quartus/T65/T65_MCode.vhd1052
-rw-r--r--quartus/T65/T65_Pack.vhd117
-rw-r--r--quartus/bbc_micro.qpf30
-rw-r--r--quartus/bbc_micro_de1.qsf537
-rw-r--r--quartus/bbc_micro_de1.vhd1265
-rw-r--r--quartus/bbc_micro_de1_tb.vhd299
-rw-r--r--quartus/debugger.vhd300
-rw-r--r--quartus/i2c_loader.vhd304
-rw-r--r--quartus/i2s_intf.vhd195
-rw-r--r--quartus/keyboard.odgbin0 -> 16836 bytes
-rw-r--r--quartus/keyboard.pngbin0 -> 60246 bytes
-rw-r--r--quartus/keyboard.txt81
-rw-r--r--quartus/keyboard.vhd294
-rw-r--r--quartus/m6522.vhd886
-rw-r--r--quartus/m6522_tb.vhd378
-rw-r--r--quartus/mc6845.vhd481
-rw-r--r--quartus/pll32.ppf11
-rw-r--r--quartus/pll32.qip4
-rw-r--r--quartus/pll32.vhd365
-rw-r--r--quartus/ps2_intf.vhd157
-rw-r--r--quartus/roms/saa5050/genrom.c180
-rw-r--r--quartus/roms/saa5050/saa5050.hex257
-rw-r--r--quartus/roms/saa5050/saa5050.rombin0 -> 4096 bytes
-rw-r--r--quartus/saa5050.vhd391
-rw-r--r--quartus/saa5050_rom.qip3
-rw-r--r--quartus/saa5050_rom.vhd168
-rw-r--r--quartus/seg7.vhd68
-rw-r--r--quartus/sn76489-1.0/COPYING340
-rw-r--r--quartus/sn76489-1.0/README143
-rw-r--r--quartus/sn76489-1.0/sn76489_attenuator-c.vhd14
-rw-r--r--quartus/sn76489-1.0/sn76489_attenuator.vhd114
-rw-r--r--quartus/sn76489-1.0/sn76489_clock_div-c.vhd14
-rw-r--r--quartus/sn76489-1.0/sn76489_clock_div.vhd134
-rw-r--r--quartus/sn76489-1.0/sn76489_comp_pack-p.vhd96
-rw-r--r--quartus/sn76489-1.0/sn76489_latch_ctrl-c.vhd14
-rw-r--r--quartus/sn76489-1.0/sn76489_latch_ctrl.vhd138
-rw-r--r--quartus/sn76489-1.0/sn76489_noise-c.vhd19
-rw-r--r--quartus/sn76489-1.0/sn76489_noise.vhd281
-rw-r--r--quartus/sn76489-1.0/sn76489_tone-c.vhd19
-rw-r--r--quartus/sn76489-1.0/sn76489_tone.vhd191
-rw-r--r--quartus/sn76489-1.0/sn76489_top-c.vhd31
-rw-r--r--quartus/sn76489-1.0/sn76489_top.vhd210
-rw-r--r--quartus/vidproc.vhd279
47 files changed, 11145 insertions, 0 deletions
diff --git a/quartus/CII_Starter_pin_assignments.csv b/quartus/CII_Starter_pin_assignments.csv
new file mode 100644
index 0000000..f46adb0
--- /dev/null
+++ b/quartus/CII_Starter_pin_assignments.csv
@@ -0,0 +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
+
diff --git a/quartus/README b/quartus/README
new file mode 100644
index 0000000..47daf92
--- /dev/null
+++ b/quartus/README
@@ -0,0 +1,6 @@
+T65 implementation from http://www.fpgaarcade.com/resources/T65_v302.zip (bug fixes from PACE dev)
+M6522 implementation from FPGA arcade VIC20 design. Various bug fixes added locally.
+SN76489 implementation by Arnim Laeuger and obtained from FPGA arcade
+
+
+
diff --git a/quartus/T65/T65.vhd b/quartus/T65/T65.vhd
new file mode 100644
index 0000000..4a21d79
--- /dev/null
+++ b/quartus/T65/T65.vhd
@@ -0,0 +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;
diff --git a/quartus/T65/T65_ALU.vhd b/quartus/T65/T65_ALU.vhd
new file mode 100644
index 0000000..d9d25e1
--- /dev/null
+++ b/quartus/T65/T65_ALU.vhd
@@ -0,0 +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;
diff --git a/quartus/T65/T65_MCode.vhd b/quartus/T65/T65_MCode.vhd
new file mode 100644
index 0000000..3fd40d8
--- /dev/null
+++ b/quartus/T65/T65_MCode.vhd
@@ -0,0 +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;
diff --git a/quartus/T65/T65_Pack.vhd b/quartus/T65/T65_Pack.vhd
new file mode 100644
index 0000000..f8d603c
--- /dev/null
+++ b/quartus/T65/T65_Pack.vhd
@@ -0,0 +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;
diff --git a/quartus/bbc_micro.qpf b/quartus/bbc_micro.qpf
new file mode 100644
index 0000000..52e0fd0
--- /dev/null
+++ b/quartus/bbc_micro.qpf
@@ -0,0 +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"
diff --git a/quartus/bbc_micro_de1.qsf b/quartus/bbc_micro_de1.qsf
new file mode 100644
index 0000000..be8b1f2
--- /dev/null
+++ b/quartus/bbc_micro_de1.qsf
@@ -0,0 +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
+set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file
diff --git a/quartus/bbc_micro_de1.vhd b/quartus/bbc_micro_de1.vhd
new file mode 100644
index 0000000..e109c36
--- /dev/null
+++ b/quartus/bbc_micro_de1.vhd
@@ -0,0 +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;
diff --git a/quartus/bbc_micro_de1_tb.vhd b/quartus/bbc_micro_de1_tb.vhd
new file mode 100644
index 0000000..82012ec
--- /dev/null
+++ b/quartus/bbc_micro_de1_tb.vhd
@@ -0,0 +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;
diff --git a/quartus/debugger.vhd b/quartus/debugger.vhd
new file mode 100644
index 0000000..1d78bd5
--- /dev/null
+++ b/quartus/debugger.vhd
@@ -0,0 +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;
diff --git a/quartus/i2c_loader.vhd b/quartus/i2c_loader.vhd
new file mode 100644
index 0000000..35da643
--- /dev/null
+++ b/quartus/i2c_loader.vhd
@@ -0,0 +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;
+
diff --git a/quartus/i2s_intf.vhd b/quartus/i2s_intf.vhd
new file mode 100644
index 0000000..e15ce2c
--- /dev/null
+++ b/quartus/i2s_intf.vhd
@@ -0,0 +1,195 @@
+-- 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;
+
+entity 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 i2s_intf;
+
+architecture i2s_intf_arch of i2s_intf is
+constant ratio_mclk_fs : positive := (mclk_rate / sample_rate);
+constant lrdivider_top : positive := (ratio_mclk_fs / 2) - 1;
+constant bdivider_top : positive := (ratio_mclk_fs / 8 / (preamble + word_length) * 2) - 1;
+constant nbits : positive := preamble + word_length;
+
+subtype lrdivider_t is integer range 0 to lrdivider_top;
+subtype bdivider_t is integer range 0 to bdivider_top;
+subtype bitcount_t is integer range 0 to nbits;
+
+signal lrdivider : lrdivider_t;
+signal bdivider : bdivider_t;
+signal bitcount : bitcount_t;
+
+signal mclk_r : std_logic;
+signal lrclk_r : std_logic;
+signal bclk_r : std_logic;
+
+-- Shift register is long enough for the number of data bits
+-- plus the preamble, plus an extra bit on the right to register
+-- the incoming data
+signal shiftreg : std_logic_vector(nbits downto 0);
+begin
+ I2S_MCLK <= mclk_r;
+ I2S_LRCLK <= lrclk_r;
+ I2S_BCLK <= bclk_r;
+ I2S_DOUT <= shiftreg(nbits); -- data goes out MSb first
+
+ process(nRESET,CLK)
+ begin
+ if nRESET = '0' then
+ PCM_INL <= (others => '0');
+ PCM_INR <= (others => '0');
+
+ -- Preload down-counters for clock generation
+ lrdivider <= lrdivider_top;
+ bdivider <= bdivider_top;
+ bitcount <= nbits;
+
+ mclk_r <= '0';
+ lrclk_r <= '0';
+ bclk_r <= '0';
+ shiftreg <= (others => '0');
+ elsif rising_edge(CLK) then
+ -- Generate MCLK at half input clock rate
+ mclk_r <= not mclk_r;
+
+ -- Generate LRCLK at rate specified by codec configuration
+ if lrdivider = 0 then
+ -- LRCLK divider has reached 0 - start again from the top
+ lrdivider <= lrdivider_top;
+
+ -- Generate LRCLK edge and sync the BCLK counter
+ lrclk_r <= not lrclk_r;
+ bclk_r <= '0';
+ bitcount <= nbits; -- 1 extra required for setup
+ bdivider <= bdivider_top;
+
+ -- Load shift register with output data padding preamble
+ -- with 0s. Load output buses with input word from the
+ -- previous timeslot.
+ shiftreg(nbits downto nbits - preamble + 1) <= (others => '0');
+ if lrclk_r = '0' then
+ -- Previous channel input is LEFT. This is available in the
+ -- shift register at the end of a cycle, right justified
+ PCM_INL <= shiftreg(word_length - 1 downto 0);
+ -- Next channel to output is RIGHT. Load this into the
+ -- shift register at the start of a cycle, left justified
+ shiftreg(word_length downto 1) <= PCM_OUTR;
+ else
+ -- Previous channel input is RIGHT
+ PCM_INR <= shiftreg(word_length - 1 downto 0);
+ -- Next channel is LEFT
+ shiftreg(word_length downto 1) <= PCM_OUTL;
+ end if;
+ else
+ -- Decrement the LRCLK counter
+ lrdivider <= lrdivider - 1;
+
+ -- Generate BCLK at a suitable rate to fit the required number
+ -- of bits into each timeslot. Data is changed on the falling edge,
+ -- sampled on the rising edge
+ if bdivider = 0 then
+ -- If all bits have been output for this phase then
+ -- stop and wait to sync back up with LRCLK
+ if bitcount > 0 then
+ -- Reset
+ bdivider <= bdivider_top;
+
+ -- Toggle BCLK
+ bclk_r <= not bclk_r;
+ if bclk_r = '0' then
+ -- Rising edge - shift in current bit and decrement bit counter
+ bitcount <= bitcount - 1;
+ shiftreg(0) <= I2S_DIN;
+ else
+ -- Falling edge - shift out next bit
+ shiftreg(nbits downto 1) <= shiftreg(nbits - 1 downto 0);
+ end if;
+ end if;
+ else
+ -- Decrement the BCLK counter
+ bdivider <= bdivider - 1;
+ end if;
+ end if;
+
+ end if;
+ end process;
+end i2s_intf_arch;
+
diff --git a/quartus/keyboard.odg b/quartus/keyboard.odg
new file mode 100644
index 0000000..403b1e7
--- /dev/null
+++ b/quartus/keyboard.odg
Binary files differ
diff --git a/quartus/keyboard.png b/quartus/keyboard.png
new file mode 100644
index 0000000..12735bd
--- /dev/null
+++ b/quartus/keyboard.png
Binary files differ
diff --git a/quartus/keyboard.txt b/quartus/keyboard.txt
new file mode 100644
index 0000000..d63fa03
--- /dev/null
+++ b/quartus/keyboard.txt
@@ -0,0 +1,81 @@
+Column Row Key PC key Scancode
+0 0 SHIFT LEFT SHIFT, RIGHT SHIFT 12 + 59
+0 1 Q Q 15
+0 2 F0 F10 09
+0 3 1 (!) 1 16
+0 4 CAPS LOCK CAPS LOCK 58
+0 5 SHIFT LOCK LEFT ALT 11
+0 6 TAB TAB 0D
+0 7 ESCAPE ESCAPE 76
+1 0 CTRL LEFT CTRL, RIGHT CTRL 14 + E0,14
+1 1 3 (#) 3 26
+1 2 W W 1D
+1 3 2 (") 2 1E
+1 4 A A 1C
+1 5 S S 1B
+1 6 Z Z 1A
+1 7 F1 F1 05
+2 0 DIP 7
+2 1 4 ($) 4 25
+2 2 E E 24
+2 3 D D 23
+2 4 X X 22
+2 5 C C 21
+2 6 SPACE SPACE 29
+2 7 F2 F2 06
+3 0 DIP 6
+3 1 5 (%) 5 2E
+3 2 T T 2C
+3 3 R R 2D
+3 4 F F 2B
+3 5 G G 34
+3 6 V V 2A
+3 7 F3 F3 04
+4 0 DIP 5
+4 1 F4 F4 0C
+4 2 7 (') 7 3D
+4 3 6 (&) 6 36
+4 4 Y Y 35
+4 5 H H 33
+4 6 B B 32
+4 7 F5 F5 03
+5 0 DIP 4
+5 1 8 (() 8 3E
+5 2 I I 43
+5 3 U U 3C
+5 4 J J 3B
+5 5 N N 31
+5 6 M M 3A
+5 7 F6 F6 0B
+6 0 DIP 3
+6 1 F7 F7 83
+6 2 9 ()) 9 46
+6 3 O O 44
+6 4 K K 42
+6 5 L L 4B
+6 6 , (<) , 41
+6 7 F8 F8 0A
+7 0 DIP 2
+7 1 - (=) - 4E
+7 2 0 0 45
+7 3 P P 4D
+7 4 @ ` 0E
+7 5 ; (+) ; 4C
+7 6 . (>) . 49
+7 7 F9 F9 01
+8 0 DIP 1
+8 1 ^ (~) = 55
+8 2 _ (£) # 5D
+8 3 [ ({) [ 54
+8 4 : (*) ' 52
+8 5 ] (}) ] 5B
+8 6 / (?) / 4A
+8 7 \ (|) \ 61
+9 0 DIP 0
+9 1 LEFT LEFT E0,6B
+9 2 DOWN DOWN E0,72
+9 3 UP UP E0,75
+9 4 RETURN RETURN 5A
+9 5 DELETE BACKSPACE 66
+9 6 COPY END E0,69
+9 7 RIGHT RIGHT E0,74
diff --git a/quartus/keyboard.vhd b/quartus/keyboard.vhd
new file mode 100644
index 0000000..c0b8603
--- /dev/null
+++ b/quartus/keyboard.vhd
@@ -0,0 +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;
+
+
diff --git a/quartus/m6522.vhd b/quartus/m6522.vhd
new file mode 100644
index 0000000..e01ed10
--- /dev/null
+++ b/quartus/m6522.vhd
@@ -0,0 +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;
diff --git a/quartus/m6522_tb.vhd b/quartus/m6522_tb.vhd
new file mode 100644
index 0000000..3e4262d
--- /dev/null
+++ b/quartus/m6522_tb.vhd
@@ -0,0 +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;
diff --git a/quartus/mc6845.vhd b/quartus/mc6845.vhd
new file mode 100644
index 0000000..31208ea
--- /dev/null
+++ b/quartus/mc6845.vhd
@@ -0,0 +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
+ 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;
+
+
diff --git a/quartus/pll32.ppf b/quartus/pll32.ppf
new file mode 100644
index 0000000..1ba6b2c
--- /dev/null
+++ b/quartus/pll32.ppf
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE pinplan>
+<pinplan intended_family="Cyclone II" variation_name="pll32" megafunction_name="ALTPLL" specifies="all_ports">
+<global>
+<pin name="areset" direction="input" scope="external" />
+<pin name="inclk0" direction="input" scope="external" source="clock" />
+<pin name="c0" direction="output" scope="external" source="clock" />
+<pin name="locked" direction="output" scope="external" />
+
+</global>
+</pinplan>
diff --git a/quartus/pll32.qip b/quartus/pll32.qip
new file mode 100644
index 0000000..f78bd93
--- /dev/null
+++ b/quartus/pll32.qip
@@ -0,0 +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"]
diff --git a/quartus/pll32.vhd b/quartus/pll32.vhd
new file mode 100644
index 0000000..43df1aa
--- /dev/null
+++ b/quartus/pll32.vhd
@@ -0,0 +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
diff --git a/quartus/ps2_intf.vhd b/quartus/ps2_intf.vhd
new file mode 100644
index 0000000..dc8440f
--- /dev/null
+++ b/quartus/ps2_intf.vhd
@@ -0,0 +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;
diff --git a/quartus/roms/saa5050/genrom.c b/quartus/roms/saa5050/genrom.c
new file mode 100644
index 0000000..9d93bb3
--- /dev/null
+++ b/quartus/roms/saa5050/genrom.c
@@ -0,0 +1,180 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+// Characters on a 5x9 matrix. This is padded up to 16 rows when the
+// ROM is generated
+static uint8_t saa5050_charset[] = {
+ 0,0,0,0,0,0,0,0,0,
+ 4,4,4,4,4,0,4,0,0,
+ 10,10,10,0,0,0,0,0,0,
+ 6,9,8,28,8,8,31,0,0,
+ 14,21,20,14,5,21,14,0,0,
+ 24,25,2,4,8,19,3,0,0,
+ 8,20,20,8,21,18,13,0,0,
+ 4,4,4,0,0,0,0,0,0,
+
+ 2,4,8,8,8,4,2,0,0,
+ 8,4,2,2,2,4,8,0,0,
+ 4,21,14,4,14,21,4,0,0,
+ 0,4,4,31,4,4,0,0,0,
+ 0,0,0,0,0,4,4,8,0,
+ 0,0,0,14,0,0,0,0,0,
+ 0,0,0,0,0,0,4,0,0,
+ 0,1,2,4,8,16,0,0,0,
+
+ 4,10,17,17,17,10,4,0,0,
+ 4,12,4,4,4,4,14,0,0,
+ 14,17,1,6,8,16,31,0,0,
+ 31,1,2,6,1,17,14,0,0,
+ 2,6,10,18,31,2,2,0,0,
+ 31,16,30,1,1,17,14,0,0,
+ 6,8,16,30,17,17,14,0,0,
+ 31,1,2,4,8,8,8,0,0,
+
+ 14,17,17,14,17,17,14,0,0,
+ 14,17,17,15,1,2,12,0,0,
+ 0,0,4,0,0,0,4,0,0,
+ 0,0,4,0,0,4,4,8,0,
+ 2,4,8,16,8,4,2,0,0,
+ 0,0,31,0,31,0,0,0,0,
+ 8,4,2,1,2,4,8,0,0,
+ 14,17,2,4,4,0,4,0,0,
+
+ 14,17,23,21,23,16,14,0,0,
+ 4,10,17,17,31,17,17,0,0,
+ 30,17,17,30,17,17,30,0,0,
+ 14,17,16,16,16,17,14,0,0,
+ 30,17,17,17,17,17,30,0,0,
+ 31,16,16,30,16,16,31,0,0,
+ 31,16,16,30,16,16,16,0,0,
+ 14,17,16,16,19,17,15,0,0,
+
+ 17,17,17,31,17,17,17,0,0,
+ 14,4,4,4,4,4,14,0,0,
+ 1,1,1,1,1,17,14,0,0,
+ 17,18,20,24,20,18,17,0,0,
+ 16,16,16,16,16,16,31,0,0,
+ 17,27,21,21,17,17,17,0,0,
+ 17,17,25,21,19,17,17,0,0,
+ 14,17,17,17,17,17,14,0,0,
+
+ 30,17,17,30,16,16,16,0,0,
+ 14,17,17,17,21,18,13,0,0,
+ 30,17,17,30,20,18,17,0,0,
+ 14,17,16,14,1,17,14,0,0,
+ 31,4,4,4,4,4,4,0,0,
+ 17,17,17,17,17,17,14,0,0,
+ 17,17,17,10,10,4,4,0,0,
+ 17,17,17,21,21,21,10,0,0,
+
+ 17,17,10,4,10,17,17,0,0,
+ 17,17,10,4,4,4,4,0,0,
+ 31,1,2,4,8,16,31,0,0,
+ 0,4,8,31,8,4,0,0,0,
+ 16,16,16,16,22,1,2,4,7,
+ 0,4,2,31,2,4,0,0,0,
+ 0,4,14,21,4,4,0,0,0,
+ 10,10,31,10,31,10,10,0,0,
+
+ 0,0,0,31,0,0,0,0,0,
+ 0,0,14,1,15,17,15,0,0,
+ 16,16,30,17,17,17,30,0,0,
+ 0,0,15,16,16,16,15,0,0,
+ 1,1,15,17,17,17,15,0,0,
+ 0,0,14,17,31,16,14,0,0,
+ 2,4,4,14,4,4,4,0,0,
+ 0,0,15,17,17,17,15,1,14,
+
+ 16,16,30,17,17,17,17,0,0,
+ 4,0,12,4,4,4,14,0,0,
+ 4,0,4,4,4,4,4,4,8,
+ 8,8,9,10,12,10,9,0,0,
+ 12,4,4,4,4,4,14,0,0,
+ 0,0,26,21,21,21,21,0,0,
+ 0,0,30,17,17,17,17,0,0,
+ 0,0,14,17,17,17,14,0,0,
+
+ 0,0,30,17,17,17,30,16,16,
+ 0,0,15,17,17,17,15,1,1,
+ 0,0,11,12,8,8,8,0,0,
+ 0,0,15,16,14,1,30,0,0,
+ 4,4,14,4,4,4,2,0,0,
+ 0,0,17,17,17,17,15,0,0,
+ 0,0,17,17,10,10,4,0,0,
+ 0,0,17,17,21,21,10,0,0,
+
+ 0,0,17,10,4,10,17,0,0,
+ 0,0,17,17,17,17,15,1,14,
+ 0,0,31,2,4,8,31,0,0,
+ 8,8,8,8,9,3,5,7,1,
+ 10,10,10,10,10,10,10,0,0,
+ 24,4,24,4,25,3,5,7,1,
+ 0,4,0,31,0,4,0,0,0,
+ 31,31,31,31,31,31,31,0,0,
+};
+
+/* Generates 6x10 teletext graphics symbol according to specified code */
+void gen_gfx(char code,char *base)
+{
+ char *c;
+ int r;
+
+ for (r = 0, c = base; r < 10; r++, c++) {
+ /* Set unused bit 7 to 1 to flag these characters as graphics (the
+ * implementation uses this to determine whether hold and separated
+ * modes should be applied */
+ *c = 128;
+ if (r < 3) {
+ // 1 2
+ if (code & 1) *c += 56;
+ if (code & 2) *c += 7;
+ } else if (r < 7) {
+ // 4 8
+ if (code & 4) *c += 56;
+ if (code & 8) *c += 7;
+ } else {
+ // 16 64
+ if (code & 16) *c += 56;
+ if (code & 64) *c += 7;
+ }
+ }
+}
+
+int main(void) {
+ char *outbuf;
+ int ch,row;
+
+ outbuf = malloc(256 * 16);
+ if (outbuf == NULL) {
+ fprintf(stderr,"Out of memory\n");
+ return 1;
+ }
+
+ /* Unused locations are blank (all zero) */
+ memset(outbuf,0,256 * 16);
+
+ /* Copy character bitmaps to locations 32-127 and 160-255 */
+ for (ch = 0; ch < 96; ch++) {
+ for (row = 0; row < 9; row++) {
+ outbuf[16 * (32 + ch) + row + 1] = saa5050_charset[9 * ch + row];
+ outbuf[16 * (160 + ch) + row + 1] = saa5050_charset[9 * ch + row];
+ }
+ }
+
+ /* Generate graphics in locations 160-191 and 224-255 */
+ for (ch = 160; ch < 192; ch++) {
+ gen_gfx(ch,&outbuf[16 * ch]);
+ }
+ for (ch = 224; ch < 256; ch++) {
+ gen_gfx(ch,&outbuf[16 * ch]);
+ }
+
+ /* Write to stdout */
+ fwrite(outbuf,256 * 16,1,stdout);
+
+ free(outbuf);
+ return 0;
+}
+
diff --git a/quartus/roms/saa5050/saa5050.hex b/quartus/roms/saa5050/saa5050.hex
new file mode 100644
index 0000000..f696b00
--- /dev/null
+++ b/quartus/roms/saa5050/saa5050.hex
@@ -0,0 +1,257 @@
+:1000000000000000000000000000000000000000F0
+:1000100000000000000000000000000000000000E0
+:1000200000000000000000000000000000000000D0
+:1000300000000000000000000000000000000000C0
+:1000400000000000000000000000000000000000B0
+:1000500000000000000000000000000000000000A0
+:100060000000000000000000000000000000000090
+:100070000000000000000000000000000000000080
+:100080000000000000000000000000000000000070
+:100090000000000000000000000000000000000060
+:1000A0000000000000000000000000000000000050
+:1000B0000000000000000000000000000000000040
+:1000C0000000000000000000000000000000000030
+:1000D0000000000000000000000000000000000020
+:1000E0000000000000000000000000000000000010
+:1000F0000000000000000000000000000000000000
+:1001000000000000000000000000000000000000EF
+:1001100000000000000000000000000000000000DF
+:1001200000000000000000000000000000000000CF
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000000000000000000000000000008F
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000000000000006F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000000000001F
+:1001E000000000000000000000000000000000000F
+:1001F00000000000000000000000000000000000FF
+:1002000000000000000000000000000000000000EE
+:1002100000040404040400040000000000000000C6
+:10022000000A0A0A000000000000000000000000B0
+:10023000000609081C08081F00000000000000005C
+:10024000000E15140E05150E000000000000000041
+:100250000018190204081303000000000000000049
+:10026000000814140815120D000000000000000022
+:100270000004040400000000000000000000000072
+:10028000000204080808040200000000000000004A
+:100290000008040202020408000000000000000040
+:1002A0000004150E040E15040000000000000000FC
+:1002B000000004041F04040000000000000000000F
+:1002C000000000000000040408000000000000001E
+:1002D000000000000E000000000000000000000010
+:1002E000000000000000000400000000000000000A
+:1002F00000000102040810000000000000000000DF
+:1003000000040A1111110A0400000000000000009E
+:1003100000040C040404040E0000000000000000AF
+:10032000000E11010608101F000000000000000070
+:10033000001F01020601110E000000000000000075
+:100340000002060A121F0202000000000000000066
+:10035000001F101E0101110E00000000000000002F
+:10036000000608101E11110E000000000000000021
+:10037000001F01020408080800000000000000003F
+:10038000000E11110E11110E0000000000000000FF
+:10039000000E11110F01020C00000000000000000F
+:1003A0000000000400000004000000000000000045
+:1003B0000000000400000404080000000000000029
+:1003C0000002040810080402000000000000000001
+:1003D0000000001F001F00000000000000000000DF
+:1003E00000080402010204080000000000000000F0
+:1003F000000E1102040400040000000000000000D0
+:10040000000E11171517100E00000000000000006C
+:1004100000040A11111F111100000000000000006B
+:10042000001E11111E11111E00000000000000002E
+:10043000000E11101010110E00000000000000004E
+:10044000001E11111111111E00000000000000001B
+:10045000001F10101E10101F000000000000000000
+:10046000001F10101E1010100000000000000000FF
+:10047000000E11101013110F00000000000000000A
+:10048000001111111F1111110000000000000000E7
+:10049000000E04040404040E00000000000000002C
+:1004A000000101010101110E000000000000000028
+:1004B00000111214181412110000000000000000B6
+:1004C000001010101010101F0000000000000000AD
+:1004D00000111B1515111111000000000000000093
+:1004E0000011111915131111000000000000000087
+:1004F000000E11111111110E00000000000000008B
+:10050000001E11111E10101000000000000000005D
+:10051000000E11111115120D000000000000000066
+:10052000001E11111E141211000000000000000036
+:10053000000E11100E01110E00000000000000005E
+:10054000001F040404040404000000000000000074
+:10055000001111111111110E000000000000000027
+:10056000001111110A0A040400000000000000003C
+:10057000001111111515150A0000000000000000FF
+:100580000011110A040A111100000000000000000F
+:100590000011110A0404040400000000000000001F
+:1005A000001F01020408101F0000000000000000EE
+:1005B000000004081F080400000000000000000004
+:1005C00000101010101601020407000000000000C7
+:1005D000000004021F0204000000000000000000F0
+:1005E0000000040E150404000000000000000000DC
+:1005F000000A0A1F0A1F0A0A00000000000000008B
+:10060000000000001F0000000000000000000000CB
+:100610000000000E010F110F00000000000000009C
+:100620000010101E1111111E00000000000000003B
+:100630000000000F1010100F00000000000000006C
+:100640000001010F1111110F000000000000000057
+:100650000000000E111F100E00000000000000003E
+:10066000000204040E040404000000000000000066
+:100670000000000F1111110F010E0000000000001A
+:100680000010101E111111110000000000000000E8
+:100690000004000C0404040E000000000000000030
+:1006A0000004000404040404040800000000000026
+:1006B000000808090A0C0A090000000000000000F8
+:1006C000000C04040404040E0000000000000000FC
+:1006D0000000001A151515150000000000000000AC
+:1006E0000000001E111111110000000000000000A8
+:1006F0000000000E1111110E0000000000000000AB
+:100700000000001E1111111E10100000000000005A
+:100710000000000F1111110F010100000000000086
+:100720000000000B0C08080800000000000000009A
+:100730000000000F100E011E00000000000000006D
+:100740000004040E04040402000000000000000085
+:10075000000000111111110F000000000000000046
+:1007600000000011110A0A0400000000000000004F
+:10077000000000111115150A000000000000000023
+:10078000000000110A040A1100000000000000002F
+:10079000000000111111110F010E000000000000F7
+:1007A0000000001F0204081F0000000000000000FD
+:1007B0000008080808090305070100000000000000
+:1007C000000A0A0A0A0A0A0A0000000000000000E3
+:1007D00000180418041903050701000000000000B8
+:1007E000000004001F0004000000000000000000E2
+:1007F000001F1F1F1F1F1F1F000000000000000020
+:1008000000000000000000000000000000000000E8
+:1008100000000000000000000000000000000000D8
+:1008200000000000000000000000000000000000C8
+:1008300000000000000000000000000000000000B8
+:1008400000000000000000000000000000000000A8
+:100850000000000000000000000000000000000098
+:100860000000000000000000000000000000000088
+:100870000000000000000000000000000000000078
+:100880000000000000000000000000000000000068
+:100890000000000000000000000000000000000058
+:1008A0000000000000000000000000000000000048
+:1008B0000000000000000000000000000000000038
+:1008C0000000000000000000000000000000000028
+:1008D0000000000000000000000000000000000018
+:1008E0000000000000000000000000000000000008
+:1008F00000000000000000000000000000000000F8
+:1009000000000000000000000000000000000000E7
+:1009100000000000000000000000000000000000D7
+:1009200000000000000000000000000000000000C7
+:1009300000000000000000000000000000000000B7
+:1009400000000000000000000000000000000000A7
+:100950000000000000000000000000000000000097
+:100960000000000000000000000000000000000087
+:100970000000000000000000000000000000000077
+:100980000000000000000000000000000000000067
+:100990000000000000000000000000000000000057
+:1009A0000000000000000000000000000000000047
+:1009B0000000000000000000000000000000000037
+:1009C0000000000000000000000000000000000027
+:1009D0000000000000000000000000000000000017
+:1009E0000000000000000000000000000000000007
+:1009F00000000000000000000000000000000000F7
+:100A000080808080808080808080000000000000E6
+:100A1000B8B8B8808080808080800000000000002E
+:100A200087878780808080808080000000000000B1
+:100A3000BFBFBF80808080808080000000000000F9
+:100A4000808080B8B8B8B8808080000000000000C6
+:100A5000B8B8B8B8B8B8B88080800000000000000E
+:100A6000878787B8B8B8B880808000000000000091
+:100A7000BFBFBFB8B8B8B8808080000000000000D9
+:100A8000808080878787878080800000000000004A
+:100A9000B8B8B88787878780808000000000000092
+:100AA0008787878787878780808000000000000015
+:100AB000BFBFBF878787878080800000000000005D
+:100AC000808080BFBFBFBF8080800000000000002A
+:100AD000B8B8B8BFBFBFBF80808000000000000072
+:100AE000878787BFBFBFBF808080000000000000F5
+:100AF000BFBFBFBFBFBFBF8080800000000000003D
+:100B000080808080808080B8B8B80000000000003D
+:100B1000B8B8B880808080B8B8B800000000000085
+:100B200087878780808080B8B8B800000000000008
+:100B3000BFBFBF80808080B8B8B800000000000050
+:100B4000808080B8B8B8B8B8B8B80000000000001D
+:100B5000B8B8B8B8B8B8B8B8B8B800000000000065
+:100B6000878787B8B8B8B8B8B8B8000000000000E8
+:100B7000BFBFBFB8B8B8B8B8B8B800000000000030
+:100B800080808087878787B8B8B8000000000000A1
+:100B9000B8B8B887878787B8B8B8000000000000E9
+:100BA00087878787878787B8B8B80000000000006C
+:100BB000BFBFBF87878787B8B8B8000000000000B4
+:100BC000808080BFBFBFBFB8B8B800000000000081
+:100BD000B8B8B8BFBFBFBFB8B8B8000000000000C9
+:100BE000878787BFBFBFBFB8B8B80000000000004C
+:100BF000BFBFBFBFBFBFBFB8B8B800000000000094
+:100C0000000E11171517100E000000000000000064
+:100C100000040A11111F1111000000000000000063
+:100C2000001E11111E11111E000000000000000026
+:100C3000000E11101010110E000000000000000046
+:100C4000001E11111111111E000000000000000013
+:100C5000001F10101E10101F0000000000000000F8
+:100C6000001F10101E1010100000000000000000F7
+:100C7000000E11101013110F000000000000000002
+:100C8000001111111F1111110000000000000000DF
+:100C9000000E04040404040E000000000000000024
+:100CA000000101010101110E000000000000000020
+:100CB00000111214181412110000000000000000AE
+:100CC000001010101010101F0000000000000000A5
+:100CD00000111B151511111100000000000000008B
+:100CE000001111191513111100000000000000007F
+:100CF000000E11111111110E000000000000000083
+:100D0000001E11111E101010000000000000000055
+:100D1000000E11111115120D00000000000000005E
+:100D2000001E11111E14121100000000000000002E
+:100D3000000E11100E01110E000000000000000056
+:100D4000001F04040404040400000000000000006C
+:100D5000001111111111110E00000000000000001F
+:100D6000001111110A0A0404000000000000000034
+:100D7000001111111515150A0000000000000000F7
+:100D80000011110A040A1111000000000000000007
+:100D90000011110A04040404000000000000000017
+:100DA000001F01020408101F0000000000000000E6
+:100DB000000004081F0804000000000000000000FC
+:100DC00000101010101601020407000000000000BF
+:100DD000000004021F0204000000000000000000E8
+:100DE0000000040E150404000000000000000000D4
+:100DF000000A0A1F0A1F0A0A000000000000000083
+:100E000080808080808080878787000000000000CD
+:100E1000B8B8B88080808087878700000000000015
+:100E20008787878080808087878700000000000098
+:100E3000BFBFBF80808080878787000000000000E0
+:100E4000808080B8B8B8B8878787000000000000AD
+:100E5000B8B8B8B8B8B8B8878787000000000000F5
+:100E6000878787B8B8B8B887878700000000000078
+:100E7000BFBFBFB8B8B8B8878787000000000000C0
+:100E80008080808787878787878700000000000031
+:100E9000B8B8B88787878787878700000000000079
+:100EA00087878787878787878787000000000000FC
+:100EB000BFBFBF8787878787878700000000000044
+:100EC000808080BFBFBFBF87878700000000000011
+:100ED000B8B8B8BFBFBFBF87878700000000000059
+:100EE000878787BFBFBFBF878787000000000000DC
+:100EF000BFBFBFBFBFBFBF87878700000000000024
+:100F000080808080808080BFBFBF00000000000024
+:100F1000B8B8B880808080BFBFBF0000000000006C
+:100F200087878780808080BFBFBF000000000000EF
+:100F3000BFBFBF80808080BFBFBF00000000000037
+:100F4000808080B8B8B8B8BFBFBF00000000000004
+:100F5000B8B8B8B8B8B8B8BFBFBF0000000000004C
+:100F6000878787B8B8B8B8BFBFBF000000000000CF
+:100F7000BFBFBFB8B8B8B8BFBFBF00000000000017
+:100F800080808087878787BFBFBF00000000000088
+:100F9000B8B8B887878787BFBFBF000000000000D0
+:100FA00087878787878787BFBFBF00000000000053
+:100FB000BFBFBF87878787BFBFBF0000000000009B
+:100FC000808080BFBFBFBFBFBFBF00000000000068
+:100FD000B8B8B8BFBFBFBFBFBFBF000000000000B0
+:100FE000878787BFBFBFBFBFBFBF00000000000033
+:100FF000BFBFBFBFBFBFBFBFBFBF0000000000007B
+:00000001FF
diff --git a/quartus/roms/saa5050/saa5050.rom b/quartus/roms/saa5050/saa5050.rom
new file mode 100644
index 0000000..71565e3
--- /dev/null
+++ b/quartus/roms/saa5050/saa5050.rom
Binary files differ
diff --git a/quartus/saa5050.vhd b/quartus/saa5050.vhd
new file mode 100644
index 0000000..57dd999
--- /dev/null
+++ b/quartus/saa5050.vhd
@@ -0,0 +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;
diff --git a/quartus/saa5050_rom.qip b/quartus/saa5050_rom.qip
new file mode 100644
index 0000000..e9513f7
--- /dev/null
+++ b/quartus/saa5050_rom.qip
@@ -0,0 +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"]
diff --git a/quartus/saa5050_rom.vhd b/quartus/saa5050_rom.vhd
new file mode 100644
index 0000000..7541c0b
--- /dev/null
+++ b/quartus/saa5050_rom.vhd
@@ -0,0 +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
diff --git a/quartus/seg7.vhd b/quartus/seg7.vhd
new file mode 100644
index 0000000..a61e679
--- /dev/null
+++ b/quartus/seg7.vhd
@@ -0,0 +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;
+
diff --git a/quartus/sn76489-1.0/COPYING b/quartus/sn76489-1.0/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/quartus/sn76489-1.0/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/quartus/sn76489-1.0/README b/quartus/sn76489-1.0/README
new file mode 100644
index 0000000..3363014
--- /dev/null
+++ b/quartus/sn76489-1.0/README
@@ -0,0 +1,143 @@
+
+An SN76489AN Compatible Implementation in VHDL
+==============================================
+Version: $Date: 2006/06/18 19:28:40 $
+
+Copyright (c) 2005, 2006, Arnim Laeuger (arnim.laeuger@gmx.net)
+See the file COPYING.
+
+
+Integration
+-----------
+
+The sn76489 design exhibits all interface signals as the original chip. It
+only differs in the audio data output which is provided as an 8 bit signed
+vector instead of an analog output pin.
+
+ generic (
+ clock_div_16_g : integer := 1
+ -- Set to '1' when operating the design in SN76489 mode. The primary clock
+ -- input is divided by 16 in this variant. The data sheet mentions the
+ -- SN76494 which contains a divide-by-2 clock input stage. Set the generic
+ -- to '0' to enable this mode.
+ );
+ port (
+ clock_i : in std_logic;
+ -- Primary clock input
+ -- Drive with the target frequency or any integer multiple of it.
+
+ clock_en_i : in std_logic;
+ -- Clock enable
+ -- A '1' on this input qualifies a valid rising edge on clock_i. A '0'
+ -- disables the next rising clock edge, effectivley halting the design
+ -- until the next enabled rising clock edge.
+ -- Can be used to run the core at lower frequencies than applied on
+ -- clock_i.
+
+ res_n_i : in std_logic;
+ -- Asynchronous low active reset input.
+ -- Sets all sequential elements to a known state.
+
+ ce_n_i : in std_logic;
+ -- Chip enable, low active.
+
+ we_n_i : in std_logic;
+ -- Write enable, low active.
+
+ ready_o : out std_logic;
+ -- Ready indication to microprocessor.
+
+ d_i : in std_logic_vector(0 to 7);
+ -- Data input
+ -- MSB 0 ... 7 LSB
+
+ aout_o : out signed(0 to 7)
+ -- Audio output, signed vector
+ -- MSB/SIGN 0 ... 7 LSB
+ );
+
+
+Both 8 bit vector ports are defined (0 to 7) which declares bit 0 to be the
+MSB and bit 7 to be the LSB. This has been implemented according to TI's data
+sheet, thus all register/data format figures apply 1:1 for this design.
+Many systems will flip the system data bus bit wise before it is connected to
+this PSG. This is simply achieved with the following VHDL construct:
+
+ signal data_s : std_logic_vector(7 downto 0);
+
+ ...
+ d_i => data_s,
+ ...
+
+d_i and data_s will be assigned from left to right, resulting in the expected
+bit assignment:
+
+ d_i data_s
+ 0 7
+ 1 6
+ ...
+ 6 1
+ 7 0
+
+
+As this design is fully synchronous, care has to be taken when the design
+replaces an SN76489 in asynchronous mode. No problems are expected when
+interfacing the code to other synchronous components.
+
+
+Design Hierarchy
+----------------
+
+ sn76489_top
+ |
+ +-- sn76489_latch_ctrl
+ |
+ +-- sn76489_clock_div
+ |
+ +-- sn76489_tone
+ | |
+ | \-- sn76489_attentuator
+ |
+ +-- sn76489_tone
+ | |
+ | \-- sn76489_attentuator
+ |
+ +-- sn76489_tone
+ | |
+ | \-- sn76489_attentuator
+ |
+ \-- sn76489_noise
+ |
+ \-- sn76489_attentuator
+
+Resulting compilation sequence:
+
+ sn76489_comp_pack-p.vhd
+ sn76489_top.vhd
+ sn76489_latch_ctrl.vhd
+ sn76489_latch_ctrl-c.vhd
+ sn76489_clock_div.vhd
+ sn76489_clock_div-c.vhd
+ sn76489_attenuator.vhd
+ sn76489_attenuator-c.vhd
+ sn76489_tone.vhd
+ sn76489_tone-c.vhd
+ sn76489_noise.vhd
+ sn76489_noise-c.vhd
+ sn76489_top-c.vhd
+
+Skip the files containing VHDL configurations when analyzing the code for
+synthesis.
+
+
+References
+----------
+
+* TI Data sheet SN76489.pdf
+ ftp://ftp.whtech.com/datasheets%20&%20manuals/SN76489.pdf
+
+* John Kortink's article on the SN76489:
+ http://web.inter.nl.net/users/J.Kortink/home/articles/sn76489/
+
+* Maxim's "SN76489 notes" in
+ http://www.smspower.org/maxim/docs/SN76489.txt
diff --git a/quartus/sn76489-1.0/sn76489_attenuator-c.vhd b/quartus/sn76489-1.0/sn76489_attenuator-c.vhd
new file mode 100644
index 0000000..b97da9d
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_attenuator-c.vhd
@@ -0,0 +1,14 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_attenuator-c.vhd,v 1.2 2005/10/10 22:12:38 arnim Exp $
+--
+-------------------------------------------------------------------------------
+
+configuration sn76489_attenuator_rtl_c0 of sn76489_attenuator is
+
+ for rtl
+ end for;
+
+end sn76489_attenuator_rtl_c0;
diff --git a/quartus/sn76489-1.0/sn76489_attenuator.vhd b/quartus/sn76489-1.0/sn76489_attenuator.vhd
new file mode 100644
index 0000000..444064e
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_attenuator.vhd
@@ -0,0 +1,114 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_attenuator.vhd,v 1.7 2006/02/27 20:30:10 arnim Exp $
+--
+-- Attenuator Module
+--
+-------------------------------------------------------------------------------
+--
+-- Copyright (c) 2005, 2006, Arnim Laeuger (arnim.laeuger@gmx.net)
+--
+-- 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.
+--
+-------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity sn76489_attenuator is
+
+ port (
+ attenuation_i : in std_logic_vector(0 to 3);
+ factor_i : in signed(0 to 1);
+ product_o : out signed(0 to 7)
+ );
+
+end sn76489_attenuator;
+
+
+architecture rtl of sn76489_attenuator is
+
+begin
+
+ -----------------------------------------------------------------------------
+ -- Process attenuate
+ --
+ -- Purpose:
+ -- Determine the attenuation and generate the resulting product.
+ --
+ -- The maximum attenuation value is 31 which corresponds to volume off.
+ -- As described in the data sheet, the maximum "playing" attenuation is
+ -- 28 = 16 + 8 + 4
+ --
+ -- The table for the volume constants is derived from the following
+ -- formula (each step is 2dB voltage):
+ -- v(0) = 31
+ -- v(n+1) = v(n) * 0.79432823
+ --
+ attenuate: process (attenuation_i,
+ factor_i)
+
+ type volume_t is array (natural range 0 to 15) of natural;
+ constant volume_c : volume_t :=
+ (31, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3, 2, 2, 2, 1, 0);
+
+ variable attenuation_v : unsigned(attenuation_i'range);
+ variable volume_v : signed(product_o'range);
+
+ begin
+
+ attenuation_v := unsigned(attenuation_i);
+
+ -- volume look-up table
+ volume_v := to_signed(volume_c(to_integer(attenuation_v)),
+ product_o'length);
+
+ -- this replaces a multiplier and consumes a bit fewer
+ -- resources
+ case to_integer(factor_i) is
+ when +1 =>
+ product_o <= volume_v;
+ when -1 =>
+ product_o <= -volume_v;
+ when others =>
+ product_o <= (others => '0');
+ end case;
+
+ end process attenuate;
+ --
+ -----------------------------------------------------------------------------
+
+end rtl;
diff --git a/quartus/sn76489-1.0/sn76489_clock_div-c.vhd b/quartus/sn76489-1.0/sn76489_clock_div-c.vhd
new file mode 100644
index 0000000..7dfd851
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_clock_div-c.vhd
@@ -0,0 +1,14 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_clock_div-c.vhd,v 1.2 2005/10/10 22:12:38 arnim Exp $
+--
+-------------------------------------------------------------------------------
+
+configuration sn76489_clock_div_rtl_c0 of sn76489_clock_div is
+
+ for rtl
+ end for;
+
+end sn76489_clock_div_rtl_c0;
diff --git a/quartus/sn76489-1.0/sn76489_clock_div.vhd b/quartus/sn76489-1.0/sn76489_clock_div.vhd
new file mode 100644
index 0000000..eab86be
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_clock_div.vhd
@@ -0,0 +1,134 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_clock_div.vhd,v 1.4 2005/10/10 21:51:27 arnim Exp $
+--
+-- Clock Divider Circuit
+--
+-------------------------------------------------------------------------------
+--
+-- Copyright (c) 2005, Arnim Laeuger (arnim.laeuger@gmx.net)
+--
+-- 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.
+--
+-------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity sn76489_clock_div 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;
+ clk_en_o : out boolean
+ );
+
+end sn76489_clock_div;
+
+
+library ieee;
+use ieee.numeric_std.all;
+
+architecture rtl of sn76489_clock_div is
+
+ signal cnt_s,
+ cnt_q : unsigned(3 downto 0);
+
+begin
+
+ -----------------------------------------------------------------------------
+ -- Process seq
+ --
+ -- Purpose:
+ -- Implements the sequential counter element.
+ --
+ seq: process (clock_i, res_n_i)
+ begin
+ if res_n_i = '0' then
+ cnt_q <= (others => '0');
+ elsif clock_i'event and clock_i = '1' then
+ cnt_q <= cnt_s;
+ end if;
+ end process seq;
+ --
+ -----------------------------------------------------------------------------
+
+
+ -----------------------------------------------------------------------------
+ -- Process comb
+ --
+ -- Purpose:
+ -- Implements the combinational counter logic.
+ --
+ comb: process (clock_en_i,
+ cnt_q)
+ begin
+ -- default assignments
+ cnt_s <= cnt_q;
+ clk_en_o <= false;
+
+ if clock_en_i = '1' then
+
+ if cnt_q = 0 then
+ clk_en_o <= true;
+
+ if clock_div_16_g = 1 then
+ cnt_s <= to_unsigned(15, cnt_q'length);
+ elsif clock_div_16_g = 0 then
+ cnt_s <= to_unsigned( 1, cnt_q'length);
+ else
+ -- pragma translate_off
+ assert false
+ report "Generic clock_div_16_g must be either 0 or 1."
+ severity failure;
+ -- pragma translate_on
+ end if;
+
+ else
+ cnt_s <= cnt_q - 1;
+
+ end if;
+
+ end if;
+
+ end process comb;
+ --
+ -----------------------------------------------------------------------------
+
+end rtl;
diff --git a/quartus/sn76489-1.0/sn76489_comp_pack-p.vhd b/quartus/sn76489-1.0/sn76489_comp_pack-p.vhd
new file mode 100644
index 0000000..06b12c8
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_comp_pack-p.vhd
@@ -0,0 +1,96 @@
+-------------------------------------------------------------------------------
+--
+-- $Id: sn76489_comp_pack-p.vhd,v 1.6 2006/02/27 20:30:10 arnim Exp $
+--
+-- Copyright (c) 2005, 2006, Arnim Laeuger (arnim.laeuger@gmx.net)
+--
+-- All rights reserved
+--
+-------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+package sn76489_comp_pack is
+
+ component sn76489_attenuator
+ port (
+ attenuation_i : in std_logic_vector(0 to 3);
+ factor_i : in signed(0 to 1);
+ product_o : out signed(0 to 7)
+ );
+ end component;
+
+ component sn76489_tone
+ port (
+ clock_i : in std_logic;
+ clk_en_i : in boolean;
+ res_n_i : in std_logic;
+ we_i : in boolean;
+ d_i : in std_logic_vector(0 to 7);
+ r2_i : in std_logic;
+ ff_o : out std_logic;
+ tone_o : out signed(0 to 7)
+ );
+ end component;
+
+ component sn76489_noise
+ port (
+ clock_i : in std_logic;
+ clk_en_i : in boolean;
+ res_n_i : in std_logic;
+ we_i : in boolean;
+ d_i : in std_logic_vector(0 to 7);
+ r2_i : in std_logic;
+ tone3_ff_i : in std_logic;
+ noise_o : out signed(0 to 7)
+ );
+ end component;
+
+ component sn76489_latch_ctrl
+ port (
+ clock_i : in std_logic;
+ clk_en_i : in boolean;
+ res_n_i : in std_logic;
+ ce_n_i : in std_logic;
+ we_n_i : in std_logic;
+ d_i : in std_logic_vector(0 to 7);
+ ready_o : out std_logic;
+ tone1_we_o : out boolean;
+ tone2_we_o : out boolean;
+ tone3_we_o : out boolean;
+ noise_we_o : out boolean;
+ r2_o : out std_logic
+ );
+ end component;
+
+ component sn76489_clock_div
+ 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;
+ clk_en_o : out boolean
+ );
+ end component;
+
+ component sn76489_top
+ 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;
+
+end sn76489_comp_pack;
diff --git a/quartus/sn76489-1.0/sn76489_latch_ctrl-c.vhd b/quartus/sn76489-1.0/sn76489_latch_ctrl-c.vhd
new file mode 100644
index 0000000..abc09e0
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_latch_ctrl-c.vhd
@@ -0,0 +1,14 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_latch_ctrl-c.vhd,v 1.2 2005/10/10 22:12:38 arnim Exp $
+--
+-------------------------------------------------------------------------------
+
+configuration sn76489_latch_ctrl_rtl_c0 of sn76489_latch_ctrl is
+
+ for rtl
+ end for;
+
+end sn76489_latch_ctrl_rtl_c0;
diff --git a/quartus/sn76489-1.0/sn76489_latch_ctrl.vhd b/quartus/sn76489-1.0/sn76489_latch_ctrl.vhd
new file mode 100644
index 0000000..789720c
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_latch_ctrl.vhd
@@ -0,0 +1,138 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_latch_ctrl.vhd,v 1.6 2006/02/27 20:30:10 arnim Exp $
+--
+-- Latch Control Unit
+--
+-------------------------------------------------------------------------------
+--
+-- Copyright (c) 2005, 2006, Arnim Laeuger (arnim.laeuger@gmx.net)
+--
+-- 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.
+--
+-------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+entity sn76489_latch_ctrl is
+
+ port (
+ clock_i : in std_logic;
+ clk_en_i : in boolean;
+ res_n_i : in std_logic;
+ ce_n_i : in std_logic;
+ we_n_i : in std_logic;
+ d_i : in std_logic_vector(0 to 7);
+ ready_o : out std_logic;
+ tone1_we_o : out boolean;
+ tone2_we_o : out boolean;
+ tone3_we_o : out boolean;
+ noise_we_o : out boolean;
+ r2_o : out std_logic
+ );
+
+end sn76489_latch_ctrl;
+
+
+library ieee;
+use ieee.numeric_std.all;
+
+architecture rtl of sn76489_latch_ctrl is
+
+ signal reg_q : std_logic_vector(0 to 2);
+ signal we_q : boolean;
+ signal ready_q : std_logic;
+
+begin
+
+ -----------------------------------------------------------------------------
+ -- Process seq
+ --
+ -- Purpose:
+ -- Implements the sequential elements.
+ --
+ seq: process (clock_i, res_n_i)
+ begin
+ if res_n_i = '0' then
+ reg_q <= (others => '0');
+ we_q <= false;
+ ready_q <= '0';
+
+ elsif clock_i'event and clock_i = '1' then
+ -- READY Flag Output ----------------------------------------------------
+ if ready_q = '0' and we_q then
+ if clk_en_i then
+ -- assert READY when write access happened
+ ready_q <= '1';
+ end if;
+ elsif ce_n_i = '1' then
+ -- deassert READY when access has finished
+ ready_q <= '0';
+ end if;
+
+ -- Register Selection ---------------------------------------------------
+ if ce_n_i = '0' and we_n_i = '0' then
+ if clk_en_i then
+ if d_i(0) = '1' then
+ reg_q <= d_i(1 to 3);
+ end if;
+ we_q <= true;
+ end if;
+ else
+ we_q <= false;
+ end if;
+
+ end if;
+ end process seq;
+ --
+ -----------------------------------------------------------------------------
+
+
+ -----------------------------------------------------------------------------
+ -- Output mapping
+ -----------------------------------------------------------------------------
+ tone1_we_o <= reg_q(0 to 1) = "00" and we_q;
+ tone2_we_o <= reg_q(0 to 1) = "01" and we_q;
+ tone3_we_o <= reg_q(0 to 1) = "10" and we_q;
+ noise_we_o <= reg_q(0 to 1) = "11" and we_q;
+
+ r2_o <= reg_q(2);
+
+ ready_o <= ready_q
+ when ce_n_i = '0' else
+ '1';
+
+end rtl;
diff --git a/quartus/sn76489-1.0/sn76489_noise-c.vhd b/quartus/sn76489-1.0/sn76489_noise-c.vhd
new file mode 100644
index 0000000..28ded84
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_noise-c.vhd
@@ -0,0 +1,19 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_noise-c.vhd,v 1.2 2005/10/10 22:12:38 arnim Exp $
+--
+-------------------------------------------------------------------------------
+
+configuration sn76489_noise_rtl_c0 of sn76489_noise is
+
+ for rtl
+
+ for attenuator_b : sn76489_attenuator
+ use configuration work.sn76489_attenuator_rtl_c0;
+ end for;
+
+ end for;
+
+end sn76489_noise_rtl_c0;
diff --git a/quartus/sn76489-1.0/sn76489_noise.vhd b/quartus/sn76489-1.0/sn76489_noise.vhd
new file mode 100644
index 0000000..8b2ee0e
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_noise.vhd
@@ -0,0 +1,281 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_noise.vhd,v 1.6 2006/02/27 20:30:10 arnim Exp $
+--
+-- Noise Generator
+--
+-------------------------------------------------------------------------------
+--
+-- Copyright (c) 2005, 2006, Arnim Laeuger (arnim.laeuger@gmx.net)
+--
+-- 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.
+--
+-------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity sn76489_noise is
+
+ port (
+ clock_i : in std_logic;
+ clk_en_i : in boolean;
+ res_n_i : in std_logic;
+ we_i : in boolean;
+ d_i : in std_logic_vector(0 to 7);
+ r2_i : in std_logic;
+ tone3_ff_i : in std_logic;
+ noise_o : out signed(0 to 7)
+ );
+
+end sn76489_noise;
+
+
+use work.sn76489_comp_pack.sn76489_attenuator;
+
+architecture rtl of sn76489_noise is
+
+ signal nf_q : std_logic_vector(0 to 1);
+ signal fb_q : std_logic;
+ signal a_q : std_logic_vector(0 to 3);
+ signal freq_cnt_q : unsigned(0 to 6);
+ signal freq_ff_q : std_logic;
+
+ signal shift_source_s,
+ shift_source_q : std_logic;
+ signal shift_rise_edge_s : boolean;
+
+ signal lfsr_q : std_logic_vector(0 to 15);
+
+ signal freq_s : signed(0 to 1);
+
+begin
+
+ -----------------------------------------------------------------------------
+ -- Process cpu_regs
+ --
+ -- Purpose:
+ -- Implements the registers writable by the CPU.
+ --
+ cpu_regs: process (clock_i, res_n_i)
+ begin
+ if res_n_i = '0' then
+ nf_q <= (others => '0');
+ fb_q <= '0';
+ a_q <= (others => '1');
+
+ elsif clock_i'event and clock_i = '1' then
+ if clk_en_i and we_i then
+ if r2_i = '0' then
+ -- access to control register
+ -- both access types can write to the control register!
+ nf_q <= d_i(6 to 7);
+ fb_q <= d_i(5);
+
+ else
+ -- access to attenuator register
+ -- both access types can write to the attenuator register!
+ a_q <= d_i(4 to 7);
+
+ end if;
+ end if;
+ end if;
+ end process cpu_regs;
+ --
+ -----------------------------------------------------------------------------
+
+
+ -----------------------------------------------------------------------------
+ -- Process freq_gen
+ --
+ -- Purpose:
+ -- Implements the frequency generation components.
+ --
+ freq_gen: process (clock_i, res_n_i)
+ begin
+ if res_n_i = '0' then
+ freq_cnt_q <= (others => '0');
+ freq_ff_q <= '0';
+
+ elsif clock_i'event and clock_i = '1' then
+ if clk_en_i then
+ if freq_cnt_q = 0 then
+ -- reload frequency counter according to NF setting
+ case nf_q is
+ when "00" =>
+ freq_cnt_q <= to_unsigned(16 * 2 - 1, freq_cnt_q'length);
+ when "01" =>
+ freq_cnt_q <= to_unsigned(16 * 4 - 1, freq_cnt_q'length);
+ when "10" =>
+ freq_cnt_q <= to_unsigned(16 * 8 - 1, freq_cnt_q'length);
+ when others =>
+ null;
+ end case;
+
+ freq_ff_q <= not freq_ff_q;
+
+ else
+ -- decrement frequency counter
+ freq_cnt_q <= freq_cnt_q - 1;
+
+ end if;
+
+ end if;
+ end if;
+ end process freq_gen;
+ --
+ -----------------------------------------------------------------------------
+
+
+ -----------------------------------------------------------------------------
+ -- Multiplex the source of the LFSR's shift enable
+ -----------------------------------------------------------------------------
+ shift_source_s <= tone3_ff_i
+ when nf_q = "11" else
+ freq_ff_q;
+
+ -----------------------------------------------------------------------------
+ -- Process rise_edge
+ --
+ -- Purpose:
+ -- Detect the rising edge of the selected LFSR shift source.
+ --
+ rise_edge: process (clock_i, res_n_i)
+ begin
+ if res_n_i = '0' then
+ shift_source_q <= '0';
+
+ elsif clock_i'event and clock_i = '1' then
+ if clk_en_i then
+ shift_source_q <= shift_source_s;
+ end if;
+ end if;
+ end process rise_edge;
+ --
+ -----------------------------------------------------------------------------
+
+ -- detect rising edge on shift source
+ shift_rise_edge_s <= shift_source_q = '0' and shift_source_s = '1';
+
+
+ -----------------------------------------------------------------------------
+ -- Process lfsr
+ --
+ -- Purpose:
+ -- Implements the LFSR that generates noise.
+ -- Note: This implementation shifts the register right, i.e. from index
+ -- 15 towards 0 => bit 15 is the input, bit 0 is the output
+ --
+ -- Tapped bits according to MAME's sn76496.c, implemented in function
+ -- lfsr_tapped_f.
+ --
+ lfsr: process (clock_i, res_n_i)
+
+ function lfsr_tapped_f(lfsr : in std_logic_vector) return std_logic is
+ constant tapped_bits_c : std_logic_vector(0 to 15)
+ -- tapped bits are 0, 2, 15
+ := "1010000000000001";
+ variable parity_v : std_logic;
+ begin
+ parity_v := '0';
+
+ for idx in lfsr'low to lfsr'high loop
+ parity_v := parity_v xor (lfsr(idx) and tapped_bits_c(idx));
+ end loop;
+
+ return parity_v;
+ end;
+
+ begin
+ if res_n_i = '0' then
+ -- reset LFSR to "0000000000000001"
+ lfsr_q <= (others => '0');
+ lfsr_q(lfsr_q'right) <= '1';
+
+ elsif clock_i'event and clock_i = '1' then
+ if clk_en_i then
+ if we_i and r2_i = '0' then
+ -- write to noise register
+ -- -> reset LFSR
+ lfsr_q <= (others => '0');
+ lfsr_q(lfsr_q'right) <= '1';
+
+ elsif shift_rise_edge_s then
+
+ -- shift LFSR left towards MSB
+ for idx in lfsr_q'right-1 downto lfsr_q'left loop
+ lfsr_q(idx) <= lfsr_q(idx+1);
+ end loop;
+
+ -- determine input bit
+ if fb_q = '0' then
+ -- "Periodic" Noise
+ -- -> input to LFSR is output
+ lfsr_q(lfsr_q'right) <= lfsr_q(lfsr_q'left);
+ else
+ -- "White" Noise
+ -- -> input to LFSR is parity of tapped bits
+ lfsr_q(lfsr_q'right) <= lfsr_tapped_f(lfsr_q);
+ end if;
+
+ end if;
+
+ end if;
+ end if;
+ end process lfsr;
+ --
+ -----------------------------------------------------------------------------
+
+
+ -----------------------------------------------------------------------------
+ -- Map output of LFSR to signed value for attenuator.
+ -----------------------------------------------------------------------------
+ freq_s <= to_signed(+1, 2)
+ when lfsr_q(0) = '1' else
+ to_signed( 0, 2);
+
+
+ -----------------------------------------------------------------------------
+ -- The attenuator itself
+ -----------------------------------------------------------------------------
+ attenuator_b : sn76489_attenuator
+ port map (
+ attenuation_i => a_q,
+ factor_i => freq_s,
+ product_o => noise_o
+ );
+
+end rtl;
diff --git a/quartus/sn76489-1.0/sn76489_tone-c.vhd b/quartus/sn76489-1.0/sn76489_tone-c.vhd
new file mode 100644
index 0000000..119e2f3
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_tone-c.vhd
@@ -0,0 +1,19 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_tone-c.vhd,v 1.2 2005/10/10 22:12:38 arnim Exp $
+--
+-------------------------------------------------------------------------------
+
+configuration sn76489_tone_rtl_c0 of sn76489_tone is
+
+ for rtl
+
+ for attenuator_b : sn76489_attenuator
+ use configuration work.sn76489_attenuator_rtl_c0;
+ end for;
+
+ end for;
+
+end sn76489_tone_rtl_c0;
diff --git a/quartus/sn76489-1.0/sn76489_tone.vhd b/quartus/sn76489-1.0/sn76489_tone.vhd
new file mode 100644
index 0000000..b71af8b
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_tone.vhd
@@ -0,0 +1,191 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_tone.vhd,v 1.5 2006/02/27 20:30:10 arnim Exp $
+--
+-- Tone Generator
+--
+-------------------------------------------------------------------------------
+--
+-- Copyright (c) 2005, 2006, Arnim Laeuger (arnim.laeuger@gmx.net)
+--
+-- 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.
+--
+-------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity sn76489_tone is
+
+ port (
+ clock_i : in std_logic;
+ clk_en_i : in boolean;
+ res_n_i : in std_logic;
+ we_i : in boolean;
+ d_i : in std_logic_vector(0 to 7);
+ r2_i : in std_logic;
+ ff_o : out std_logic;
+ tone_o : out signed(0 to 7)
+ );
+
+end sn76489_tone;
+
+
+use work.sn76489_comp_pack.sn76489_attenuator;
+
+architecture rtl of sn76489_tone is
+
+ signal f_q : std_logic_vector(0 to 9);
+ signal a_q : std_logic_vector(0 to 3);
+ signal freq_cnt_q : unsigned(0 to 9);
+ signal freq_ff_q : std_logic;
+
+ signal freq_s : signed(0 to 1);
+
+ function all_zero(a : in std_logic_vector) return boolean is
+ variable result_v : boolean;
+ begin
+ result_v := true;
+
+ for idx in a'low to a'high loop
+ if a(idx) /= '0' then
+ result_v := false;
+ end if;
+ end loop;
+
+ return result_v;
+ end;
+
+begin
+
+ -----------------------------------------------------------------------------
+ -- Process cpu_regs
+ --
+ -- Purpose:
+ -- Implements the registers writable by the CPU.
+ --
+ cpu_regs: process (clock_i, res_n_i)
+ begin
+ if res_n_i = '0' then
+ f_q <= (others => '0');
+ a_q <= (others => '1');
+
+ elsif clock_i'event and clock_i = '1' then
+ if clk_en_i and we_i then
+ if r2_i = '0' then
+ -- access to frequency register
+ if d_i(0) = '0' then
+ f_q(0 to 5) <= d_i(2 to 7);
+ else
+ f_q(6 to 9) <= d_i(4 to 7);
+ end if;
+
+ else
+ -- access to attenuator register
+ -- both access types can write to the attenuator register!
+ a_q <= d_i(4 to 7);
+
+ end if;
+ end if;
+ end if;
+ end process cpu_regs;
+ --
+ -----------------------------------------------------------------------------
+
+
+ -----------------------------------------------------------------------------
+ -- Process freq_gen
+ --
+ -- Purpose:
+ -- Implements the frequency generation components.
+ --
+ freq_gen: process (clock_i, res_n_i)
+ begin
+ if res_n_i = '0' then
+ freq_cnt_q <= (others => '0');
+ freq_ff_q <= '0';
+
+ elsif clock_i'event and clock_i = '1' then
+ if clk_en_i then
+ if freq_cnt_q = 0 then
+ -- update counter from frequency register
+ freq_cnt_q <= unsigned(f_q);
+
+ -- and toggle the frequency flip-flop if enabled
+ if not all_zero(f_q) then
+ freq_ff_q <= not freq_ff_q;
+ else
+ -- if frequency setting is 0, then keep flip-flop at +1
+ freq_ff_q <= '1';
+ end if;
+
+ else
+ -- decrement frequency counter
+ freq_cnt_q <= freq_cnt_q - 1;
+
+ end if;
+ end if;
+ end if;
+ end process freq_gen;
+ --
+ -----------------------------------------------------------------------------
+
+
+ -----------------------------------------------------------------------------
+ -- Map frequency flip-flop to signed value for attenuator.
+ -----------------------------------------------------------------------------
+ freq_s <= to_signed(+1, 2)
+ when freq_ff_q = '1' else
+ to_signed(-1, 2);
+
+
+ -----------------------------------------------------------------------------
+ -- The attenuator itself
+ -----------------------------------------------------------------------------
+ attenuator_b : sn76489_attenuator
+ port map (
+ attenuation_i => a_q,
+ factor_i => freq_s,
+ product_o => tone_o
+ );
+
+
+ -----------------------------------------------------------------------------
+ -- Output mapping
+ -----------------------------------------------------------------------------
+ ff_o <= freq_ff_q;
+
+end rtl;
diff --git a/quartus/sn76489-1.0/sn76489_top-c.vhd b/quartus/sn76489-1.0/sn76489_top-c.vhd
new file mode 100644
index 0000000..8f709b9
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_top-c.vhd
@@ -0,0 +1,31 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_top-c.vhd,v 1.3 2005/10/10 22:12:38 arnim Exp $
+--
+-------------------------------------------------------------------------------
+
+configuration sn76489_top_struct_c0 of sn76489_top is
+
+ for struct
+
+ for clock_div_b : sn76489_clock_div
+ use configuration work.sn76489_clock_div_rtl_c0;
+ end for;
+
+ for latch_ctrl_b : sn76489_latch_ctrl
+ use configuration work.sn76489_latch_ctrl_rtl_c0;
+ end for;
+
+ for all : sn76489_tone
+ use configuration work.sn76489_tone_rtl_c0;
+ end for;
+
+ for noise_b : sn76489_noise
+ use configuration work.sn76489_noise_rtl_c0;
+ end for;
+
+ end for;
+
+end sn76489_top_struct_c0;
diff --git a/quartus/sn76489-1.0/sn76489_top.vhd b/quartus/sn76489-1.0/sn76489_top.vhd
new file mode 100644
index 0000000..277f601
--- /dev/null
+++ b/quartus/sn76489-1.0/sn76489_top.vhd
@@ -0,0 +1,210 @@
+-------------------------------------------------------------------------------
+--
+-- Synthesizable model of TI's SN76489AN.
+--
+-- $Id: sn76489_top.vhd,v 1.9 2006/02/27 20:30:10 arnim Exp $
+--
+-- Chip Toplevel
+--
+-- References:
+--
+-- * TI Data sheet SN76489.pdf
+-- ftp://ftp.whtech.com/datasheets%20&%20manuals/SN76489.pdf
+--
+-- * John Kortink's article on the SN76489:
+-- http://web.inter.nl.net/users/J.Kortink/home/articles/sn76489/
+--
+-- * Maxim's "SN76489 notes" in
+-- http://www.smspower.org/maxim/docs/SN76489.txt
+--
+-------------------------------------------------------------------------------
+--
+-- Copyright (c) 2005, 2006, Arnim Laeuger (arnim.laeuger@gmx.net)
+--
+-- 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.
+--
+-------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity 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 sn76489_top;
+
+
+library ieee;
+use ieee.numeric_std.all;
+use work.sn76489_comp_pack.all;
+
+architecture struct of sn76489_top is
+
+ signal clk_en_s : boolean;
+
+ signal tone1_we_s,
+ tone2_we_s,
+ tone3_we_s,
+ noise_we_s : boolean;
+ signal r2_s : std_logic;
+
+ signal tone1_s,
+ tone2_s,
+ tone3_s,
+ noise_s : signed(0 to 7);
+
+ signal tone3_ff_s : std_logic;
+
+begin
+
+ -----------------------------------------------------------------------------
+ -- Clock Divider
+ -----------------------------------------------------------------------------
+ clock_div_b : sn76489_clock_div
+ generic map (
+ clock_div_16_g => clock_div_16_g
+ )
+ port map (
+ clock_i => clock_i,
+ clock_en_i => clock_en_i,
+ res_n_i => res_n_i,
+ clk_en_o => clk_en_s
+ );
+
+
+ -----------------------------------------------------------------------------
+ -- Latch Control = CPU Interface
+ -----------------------------------------------------------------------------
+ latch_ctrl_b : sn76489_latch_ctrl
+ port map (
+ clock_i => clock_i,
+ clk_en_i => clk_en_s,
+ res_n_i => res_n_i,
+ ce_n_i => ce_n_i,
+ we_n_i => we_n_i,
+ d_i => d_i,
+ ready_o => ready_o,
+ tone1_we_o => tone1_we_s,
+ tone2_we_o => tone2_we_s,
+ tone3_we_o => tone3_we_s,
+ noise_we_o => noise_we_s,
+ r2_o => r2_s
+ );
+
+
+ -----------------------------------------------------------------------------
+ -- Tone Channel 1
+ -----------------------------------------------------------------------------
+ tone1_b : sn76489_tone
+ port map (
+ clock_i => clock_i,
+ clk_en_i => clk_en_s,
+ res_n_i => res_n_i,
+ we_i => tone1_we_s,
+ d_i => d_i,
+ r2_i => r2_s,
+ ff_o => open,
+ tone_o => tone1_s
+ );
+
+ -----------------------------------------------------------------------------
+ -- Tone Channel 2
+ -----------------------------------------------------------------------------
+ tone2_b : sn76489_tone
+ port map (
+ clock_i => clock_i,
+ clk_en_i => clk_en_s,
+ res_n_i => res_n_i,
+ we_i => tone2_we_s,
+ d_i => d_i,
+ r2_i => r2_s,
+ ff_o => open,
+ tone_o => tone2_s
+ );
+
+ -----------------------------------------------------------------------------
+ -- Tone Channel 3
+ -----------------------------------------------------------------------------
+ tone3_b : sn76489_tone
+ port map (
+ clock_i => clock_i,
+ clk_en_i => clk_en_s,
+ res_n_i => res_n_i,
+ we_i => tone3_we_s,
+ d_i => d_i,
+ r2_i => r2_s,
+ ff_o => tone3_ff_s,
+ tone_o => tone3_s
+ );
+
+ -----------------------------------------------------------------------------
+ -- Noise Channel
+ -----------------------------------------------------------------------------
+ noise_b : sn76489_noise
+ port map (
+ clock_i => clock_i,
+ clk_en_i => clk_en_s,
+ res_n_i => res_n_i,
+ we_i => noise_we_s,
+ d_i => d_i,
+ r2_i => r2_s,
+ tone3_ff_i => tone3_ff_s,
+ 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;
+
+end struct;
diff --git a/quartus/vidproc.vhd b/quartus/vidproc.vhd
new file mode 100644
index 0000000..6d5f91f
--- /dev/null
+++ b/quartus/vidproc.vhd
@@ -0,0 +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;
+