diff --git a/avr/main.c b/avr/main.c index d609297..e0396fa 100644 --- a/avr/main.c +++ b/avr/main.c @@ -1,28 +1,28 @@ /* - MIT License - - Copyright (c) 2025, maniek86 (Piotr Grzesik) - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. + MIT License + + Copyright (c) 2025, maniek86 (Piotr Grzesik) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. */ -// +// // FPGA bitstream loader, CMOS storage and reset circuit handler for the M8SBC-486 homebrew computer project // @@ -30,7 +30,7 @@ #define EE_ADDR_CONF 0x10 #define CMOS_SIZE 32 -#define BAUD 57600 +#define BAUD 57600 // 115200 can't be achieved with 16 MHz CLK #include @@ -56,26 +56,28 @@ extern const uint8_t bitstream_end[] PROGMEM; #define pgm_get_far_address(var) ((uint32_t)(&(var))) #endif - #define FPGA_PROG_PORT PORTE #define FPGA_PROG_DDR DDRE -#define FPGA_PROG_BIT PE5 // PROG_B, output +#define FPGA_PROG_BIT PE5 // PROG_B, output #define FPGA_INIT_PIN PINE -#define FPGA_INIT_BIT PE6 // INIT_B, input +#define FPGA_INIT_BIT PE6 // INIT_B, input #define FPGA_DONE_PIN PINE -#define FPGA_DONE_BIT PE4 // DONE, input +#define FPGA_DONE_BIT PE4 // DONE, input #define RESET_OUT_PORT PORTF #define RESET_OUT_DDR DDRF -#define RESET_OUT_BIT PF0 // RESET_OUT, output, active high +#define RESET_OUT_BIT PF0 // RESET_OUT, output, active high #define FPGA_REQ_PIN PINF -#define FPGA_REQ_BIT PF1 // FPGA_REQ_RESET input, active low +#define FPGA_REQ_BIT PF1 // FPGA_REQ_RESET input, active low +#define RESET_BTN_PORT PORTB #define RESET_BTN_PIN PINB -#define RESET_BTN_BIT PB4 // RESET_BTN, input, active low +#define RESET_BTN_DDR DDRB +#define RESET_BTN_BIT PB4 // RESET_BTN, input, active low +#define RESET_BTN_PRESSED (!(RESET_BTN_PIN & (1 << RESET_BTN_BIT))) // SPI pins: PB1 - SCK (CCLK), PB2 - MOSI (DIN) #define SPI_DDR DDRB @@ -83,389 +85,379 @@ extern const uint8_t bitstream_end[] PROGMEM; // UART1 debug (PD3 TX1, PD2 RX1) static void uart1_init(void) { - - UBRR1H = UBRRH_VALUE; - UBRR1L = UBRRL_VALUE; - - #if USE_2X - UCSR1A |= (1 << U2X1); - #else - UCSR1A &= ~(1 << U2X1); - #endif - - UCSR1B = (1 << TXEN1); - UCSR1C = (1 << UCSZ11) | (1 << UCSZ10); + + UBRR1H = UBRRH_VALUE; + UBRR1L = UBRRL_VALUE; + + #if USE_2X + UCSR1A |= (1 << U2X1); + #else + UCSR1A &= ~(1 << U2X1); + #endif + + UCSR1B = (1 << TXEN1); + UCSR1C = (1 << UCSZ11) | (1 << UCSZ10); } static void uart1_putc(char c) { - while (!(UCSR1A & (1<> 4) & 0xF); - uart1_puthex_nibble(val & 0xF); + uart1_puthex_nibble((val >> 4) & 0xF); + uart1_puthex_nibble(val & 0xF); } static void uart1_puthex32(uint32_t val) { - for (int i = 28; i >= 0; i -= 4) { - uart1_puthex_nibble((val >> i) & 0xF); - } + for (int i = 28; i >= 0; i -= 4) { + uart1_puthex_nibble((val >> i) & 0xF); + } } static void uart1_puts(const char *str) { - while (*str != '\0') { - uart1_putc(*str); - str++; - } + while (*str != '\0') { + uart1_putc(*str); + str++; + } } - // Load bitstream from flash into FPGA int load_fpga_from_flash(void) { - uart1_puts("Bitstream load:\r\n"); - uint32_t start_addr = pgm_get_far_address(bitstream); - uint32_t len = bitstream_length(); - - spi_init_fast(); - - FPGA_PROG_DDR |= (1<=0; b--) { - - PORTB &= ~(1<>b) & 1) { - PORTE |= (1<=0; b--) { + + PORTB &= ~(1<>b) & 1) { + PORTE |= (1<7) { - cmos_rec_bit = 0; - if(cmos_rec_addr=CMOS_SIZE) { // 34th byte - if(cmos_receiver_data==0xAA) { // Receive OK! - uint32_t checksum = 0; - - uart1_puts("Receive OK.\r\nWriting to EEPROM "); - for(int i=0; i7 - } - - - - } - - return 0; + uint8_t cmos_receiver_data = 0; + uint8_t cmos_rec_bit = 0; + uint8_t cmos_rec_addr = 0; + uint8_t cmos_rec_started = 0; + + DDRF &= ~(1<7) { + cmos_rec_bit = 0; + if(cmos_rec_addr=CMOS_SIZE) { // 34th byte + if(cmos_receiver_data==0xAA) { // Receive OK! + uint32_t checksum = 0; + + uart1_puts("Receive OK.\r\nWriting to EEPROM "); + for(int i=0; i7 + } + } + + return 0; } - diff --git a/bios/c_src/cmos.c b/bios/c_src/cmos.c index fd6b7b4..db02ada 100644 --- a/bios/c_src/cmos.c +++ b/bios/c_src/cmos.c @@ -5,115 +5,106 @@ static uint8_t cmos_data[32]; #define CMOS_BASE 0x40 uint8_t cmos_read() { - uint8_t cmos_checksum = 0; - for(int i=0; i<31; i++) { - outb(0x70, CMOS_BASE + i); - cmos_data[i] = inb(0x71); - cmos_checksum += cmos_data[i]; // cmos_checksum skips 0x1F - } - outb(0x70, CMOS_BASE + 0x1F); - cmos_data[31] = inb(0x71); - - if(cmos_checksum != cmos_data[31]) { - memset(cmos_data, 0, 32); - cmos_save(); - return 0; - } - - return 1; + uint8_t cmos_checksum = 0; + for(int i=0; i<31; i++) { + outb(0x70, CMOS_BASE + i); + cmos_data[i] = inb(0x71); + cmos_checksum += cmos_data[i]; // cmos_checksum skips 0x1F + } + outb(0x70, CMOS_BASE + 0x1F); + cmos_data[31] = inb(0x71); + + if(cmos_checksum != cmos_data[31]) { + memset(cmos_data, 0, 32); + cmos_save(); + return 0; + } + + return 1; } void cmos_save() { - uint8_t cmos_checksum = 0; - - for(int i=0; i<31; i++) { - outb(0x70, CMOS_BASE + i); - outb(0x71, cmos_data[i]); - cmos_checksum += cmos_data[i]; - } - outb(0x70, CMOS_BASE + 0x1F); - outb(0x71, cmos_checksum); + uint8_t cmos_checksum = 0; + + for(int i=0; i<31; i++) { + outb(0x70, CMOS_BASE + i); + outb(0x71, cmos_data[i]); + cmos_checksum += cmos_data[i]; + } + outb(0x70, CMOS_BASE + 0x1F); + outb(0x71, cmos_checksum); } - uint8_t cmos_get(enum CMOS_SETTINGS setting) { - switch(setting) { - - case CMOS_QUICK_MEMTEST: - if((cmos_data[0] & 0b00000001) > 0) return 1; - return 0; - - case CMOS_LBA_ENABLED: - if((cmos_data[0] & 0b00000010) > 0) return 1; - return 0; - - case CMOS_LOCK_CMOS: - if((cmos_data[0] & 0b00000100) > 0) return 1; - return 0; - - - default: - return 0; - } + switch(setting) { + case CMOS_QUICK_MEMTEST: + if((cmos_data[0] & 0b00000001) > 0) return 1; + return 0; + case CMOS_LBA_ENABLED: + if((cmos_data[0] & 0b00000010) > 0) return 1; + return 0; + case CMOS_LOCK_CMOS: + if((cmos_data[0] & 0b00000100) > 0) return 1; + return 0; + + default: + return 0; + } } void cmos_set(enum CMOS_SETTINGS setting, uint8_t value) { - switch(setting) { - - case CMOS_QUICK_MEMTEST: - if(value > 0) { - cmos_data[0] |= 0b00000001; - } else { - cmos_data[0] &= ~0b00000001; - } - break; - - case CMOS_LBA_ENABLED: - if(value > 0) { - cmos_data[0] |= 0b00000010; - } else { - cmos_data[0] &= ~0b00000010; - } - break; - - case CMOS_LOCK_CMOS: - if(value > 0) { - cmos_data[0] |= 0b00000100; - } else { - cmos_data[0] &= ~0b00000100; - } - break; - - default: - break; - } + switch(setting) { + case CMOS_QUICK_MEMTEST: + if(value > 0) { + cmos_data[0] |= 0b00000001; + } else { + cmos_data[0] &= ~0b00000001; + } + break; + case CMOS_LBA_ENABLED: + if(value > 0) { + cmos_data[0] |= 0b00000010; + } else { + cmos_data[0] &= ~0b00000010; + } + break; + case CMOS_LOCK_CMOS: + if(value > 0) { + cmos_data[0] |= 0b00000100; + } else { + cmos_data[0] &= ~0b00000100; + } + break; + + default: + break; + } } void cmos_lock() { - outb(0x70, 0xFF); - outb(0x71, 0x17); + outb(0x70, 0xFF); + outb(0x71, 0x17); } - uint8_t cmos_is_m8sbc() { - uint8_t b1, b2; - - outb(0x70, 0xFC); - b1 = inb(0x71); - outb(0x70, 0xFD); - b2 = inb(0x71); - - if(b1 == 0x48 && b2 == 0x86) return 1; - return 0; + uint8_t b1, b2; + + outb(0x70, 0xFC); + b1 = inb(0x71); + outb(0x70, 0xFD); + b2 = inb(0x71); + + if(b1 == 0x48 && b2 == 0x86) return 1; + return 0; } uint16_t cmos_chp_version() { - uint8_t b1, b2; + uint8_t b1, b2; - outb(0x70, 0xFE); - b1 = inb(0x71); - outb(0x70, 0xFF); - b2 = inb(0x71); + outb(0x70, 0xFE); + b1 = inb(0x71); + outb(0x70, 0xFF); + b2 = inb(0x71); - return (uint16_t)((b1<<8) | (b2 & 0xFF)); -} \ No newline at end of file + return (uint16_t)((b1<<8) | (b2 & 0xFF)); +} diff --git a/bios/c_src/cmos.h b/bios/c_src/cmos.h index 9275da2..362f00b 100644 --- a/bios/c_src/cmos.h +++ b/bios/c_src/cmos.h @@ -6,9 +6,9 @@ #include "utils.h" enum CMOS_SETTINGS { - CMOS_QUICK_MEMTEST, - CMOS_LBA_ENABLED, - CMOS_LOCK_CMOS + CMOS_QUICK_MEMTEST, + CMOS_LBA_ENABLED, + CMOS_LOCK_CMOS }; uint8_t cmos_read(); // returns 0 if checksum was invalid @@ -23,4 +23,4 @@ uint8_t cmos_is_m8sbc(); uint16_t cmos_chp_version(); -#endif \ No newline at end of file +#endif diff --git a/bios/c_src/setup.c b/bios/c_src/setup.c index caa906a..a4edbfb 100644 --- a/bios/c_src/setup.c +++ b/bios/c_src/setup.c @@ -1,18 +1,18 @@ #include "setup.h" enum bios_settings_setting { - OPTION_EMPTY, - OPTION_QUICK_MEMTEST, - OPTION_LBA_REPORTING, - OPTION_LOCK_CMOS, - OPTION_OPEN_ABOUT + OPTION_EMPTY, + OPTION_QUICK_MEMTEST, + OPTION_LBA_REPORTING, + OPTION_LOCK_CMOS, + OPTION_OPEN_ABOUT }; struct bios_settings_struct { - enum bios_settings_setting setting; - const char *option_name; - const char *option_help; + enum bios_settings_setting setting; + const char *option_name; + const char *option_help; }; static int select = 0; @@ -20,73 +20,73 @@ static int select = 0; #define SETTINGS_AMOUNT 5 static const struct bios_settings_struct bios_settings[SETTINGS_AMOUNT] = { - {OPTION_QUICK_MEMTEST, "Fast memory test", "This option enables quick memory test which reduces boot time."}, - {OPTION_LBA_REPORTING, "Enable LBA support reporting", "This option controls LBA support BIOS reporting (INT 13h ax=0x41)."}, - {OPTION_LOCK_CMOS, "Lock CMOS after boot", "Enabling this option locks CMOS 0x40-0x5F NVRAM area after boot."}, - {OPTION_EMPTY, "", ""}, - {OPTION_OPEN_ABOUT, "Open About", "SeaPig information and acknowledgments."} + {OPTION_QUICK_MEMTEST, "Fast memory test", "This option enables quick memory test which reduces boot time."}, + {OPTION_LBA_REPORTING, "Enable LBA support reporting", "This option controls LBA support BIOS reporting (INT 13h ax=0x41)."}, + {OPTION_LOCK_CMOS, "Lock CMOS after boot", "Enabling this option locks CMOS 0x40-0x5F NVRAM area after boot."}, + {OPTION_EMPTY, "", ""}, + {OPTION_OPEN_ABOUT, "Open About", "SeaPig information and acknowledgments."} }; // OPTION_EMPTY cant be used twice in a row, or be first or last static void draw_option_text(const char* text, const char* value, int x, int y, int selected) { - vga_print_string(text, x, y, 0x70); - vga_print_char(':', x + 30, y, 0x70); - vga_print_string(value, x + 32, y, (selected == 1) ? 0x1F : 0x70); + vga_print_string(text, x, y, 0x70); + vga_print_char(':', x + 30, y, 0x70); + vga_print_string(value, x + 32, y, (selected == 1) ? 0x1F : 0x70); } static void draw_options() { - int y = 12; - for(int i=0; i text_w) { - cx = 0; - cy++; - continue; - } - - // Add a separating space if needed - if(cx != 0) { - if(cx < text_w) { - vga_print_char(' ', text_x0 + cx, text_y0 + cy, 0x1F); - cx++; - } else { - cx = 0; - cy++; - continue; - } - } - - // Print the word; if it's too long, split across lines - int printed = 0; - while(printed < wlen && cy < text_h) { - if(cx >= text_w) { - cx = 0; - cy++; - if(cy >= text_h) break; - } - vga_print_char(text[i + printed], text_x0 + cx, text_y0 + cy, 0x1F); - cx++; - printed++; - } - - i += wlen; - } - - for(int x=0; x < 80; x++) { - vga_print_char(' ', x, 24, 0x0F); - } - draw_modified(); - vga_print_string("ESC or Enter to continue", 1, 24, 0x0F); - - kb_clear_buffer(); - - // Wait for ESC/ENTER to close - while(1) { - if(kb_is_available()) { - uint8_t scancode = kb_get_scancode(); - if(scancode == 0x01 || scancode == 0x1C) { // ESC or Enter - break; - } - } - } + // Draw box + const int pos_x = 18; + const int pos_y = 7; + const int w = 44; + const int h = 10; + + for(int x = pos_x; x < pos_x + w; x++) { + for(int y = pos_y; y < pos_y + h; y++) { + vga_print_char(' ', x, y, 0x1F); + if(y == pos_y || y == pos_y + h - 1) vga_print_char('=', x, y, 0x1F); + } + } + + int title_x = 40 - ((int)strlen(title) / 2); + vga_print_string(title, title_x, pos_y, 0x1F); + + // text area inside the box (leave 1 char margin) + const int text_x0 = pos_x + 1; + const int text_y0 = pos_y + 2; + const int text_w = w - 2; + const int text_h = h - 3; // title line + bottom border + + // clear text area + for(int y = 0; y < text_h; y++) { + for(int x = 0; x < text_w; x++) { + vga_print_char(' ', text_x0 + x, text_y0 + y, 0x1F); + } + } + + // word-wrapping text printer: + int i = 0; + int cx = 0; + int cy = 0; + + while(text[i] != '\0' && cy < text_h) { + // Skip leading spaces (but still allow explicit newlines) + while(text[i] == ' ') i++; + + if(text[i] == '\n') { + cx = 0; + cy++; + i++; + continue; + } + + if(text[i] == '\0') break; + + // Determine next "word" length (until space/newline/NUL) + int wlen = 0; + while(text[i + wlen] != '\0' && text[i + wlen] != ' ' && text[i + wlen] != '\n') + wlen++; + + if(wlen == 0) { + i++; + continue; + } + + // If word doesn't fit on this line, go to next line (if not at line start) + if(cx != 0 && (cx + 1 + wlen) > text_w) { + cx = 0; + cy++; + continue; + } + + // Add a separating space if needed + if(cx != 0) { + if(cx < text_w) { + vga_print_char(' ', text_x0 + cx, text_y0 + cy, 0x1F); + cx++; + } else { + cx = 0; + cy++; + continue; + } + } + + // Print the word; if it's too long, split across lines + int printed = 0; + while(printed < wlen && cy < text_h) { + if(cx >= text_w) { + cx = 0; + cy++; + if(cy >= text_h) break; + } + vga_print_char(text[i + printed], text_x0 + cx, text_y0 + cy, 0x1F); + cx++; + printed++; + } + + i += wlen; + } + + for(int x=0; x < 80; x++) { + vga_print_char(' ', x, 24, 0x0F); + } + draw_modified(); + vga_print_string("ESC or Enter to continue", 1, 24, 0x0F); + + kb_clear_buffer(); + + // Wait for ESC/ENTER to close + while(1) { + if(kb_is_available()) { + uint8_t scancode = kb_get_scancode(); + if(scancode == 0x01 || scancode == 0x1C) { // ESC or Enter + break; + } + } + } } void setup_display(uint16_t cpuid, int is_cyrix, int mem_total, int fpu_present, char *ide_name, int ide_detected) { - - l_cpuid = cpuid; - l_is_cyrix = is_cyrix; - l_mem_total = mem_total; - l_fpu_present = fpu_present; - l_ide_name = ide_name; - l_ide_detected = ide_detected; - - l_is_m8sbc = cmos_is_m8sbc(); - if(l_is_m8sbc) { - l_chp_version = cmos_chp_version(); - } else { - l_chp_version = 0; - } - - l_ide_name[38] = '\0'; // trim too long name - - - bios_redraw(); - - if(ide_detected == 0) { - dialog_text("Warning", "The system did not detect any IDE hard drives. You may attempt to continue booting by exiting this setup, but it is likely to result in failure."); - bios_redraw(); - } - - kb_clear_buffer(); - - while(1) { - static uint8_t extended = 0; - - if(kb_is_available()) { - uint8_t scancode = kb_get_scancode(); - - if(!extended) { - if(scancode==0x01) { // ESC - if(modified == 1) { - if(dialog_yesno(0, "Exit without saving?")) break; - bios_redraw(); - } else { - break; - } - } - - if(scancode==0xE0) { - extended = 1; - } - - if(scancode==0x1C) { // Enter - char option_value[16] = {0}; // old & new - enum OPTION_TYPE_ENUM { - OPTION_TYPE_OTHER, - OPTION_TYPE_YESNO - } OPTION_TYPE; - - // Option fetch - - switch(bios_settings[select].setting) { - case OPTION_QUICK_MEMTEST: - OPTION_TYPE = OPTION_TYPE_YESNO; - option_value[0] = cmos_get(CMOS_QUICK_MEMTEST); - break; - case OPTION_LBA_REPORTING: - OPTION_TYPE = OPTION_TYPE_YESNO; - option_value[0] = cmos_get(CMOS_LBA_ENABLED); - break; - case OPTION_LOCK_CMOS: - OPTION_TYPE = OPTION_TYPE_YESNO; - option_value[0] = cmos_get(CMOS_LOCK_CMOS); - break; - case OPTION_OPEN_ABOUT: - OPTION_TYPE = OPTION_TYPE_OTHER; - break; - - default: - OPTION_TYPE = OPTION_TYPE_OTHER; - break; - } - - // Option change - - if(OPTION_TYPE == OPTION_TYPE_YESNO) { - uint8_t old_option_val = option_value[0]; - option_value[0] = dialog_yesno(option_value[0], bios_settings[select].option_name); - if(old_option_val!=option_value[0]) modified = 1; - } - - // Option update / action - - switch(bios_settings[select].setting) { - case OPTION_QUICK_MEMTEST: - cmos_set(CMOS_QUICK_MEMTEST, option_value[0]); - break; - case OPTION_LBA_REPORTING: - cmos_set(CMOS_LBA_ENABLED, option_value[0]); - break; - case OPTION_LOCK_CMOS: - cmos_set(CMOS_LOCK_CMOS, option_value[0]); - break; - case OPTION_OPEN_ABOUT: - about_display(); - break; - - default: - break; - } - - bios_redraw(); - } - - if(scancode==0x3B) { // F1 help - dialog_text(bios_settings[select].option_name, bios_settings[select].option_help); - bios_redraw(); - } - - if(scancode==0x44) { // F10 save - if(dialog_yesno(0, "Save settings to CMOS?")) { - cmos_save(); - modified = 0; - } - bios_redraw(); - } - } else { - extended = 0; - - if(scancode==0x48) { // up arrow - if(select>0) { - select--; - if(bios_settings[select].setting == OPTION_EMPTY) select--; - draw_options(); - } - - } - if(scancode==0x50) { // down arrow - if(select<(SETTINGS_AMOUNT-1)) { - select++; - if(bios_settings[select].setting == OPTION_EMPTY) select++; - draw_options(); - } - - } - } - - } - } + + l_cpuid = cpuid; + l_is_cyrix = is_cyrix; + l_mem_total = mem_total; + l_fpu_present = fpu_present; + l_ide_name = ide_name; + l_ide_detected = ide_detected; + + l_is_m8sbc = cmos_is_m8sbc(); + if(l_is_m8sbc) { + l_chp_version = cmos_chp_version(); + } else { + l_chp_version = 0; + } + + l_ide_name[38] = '\0'; // trim too long name + + + bios_redraw(); + + if(ide_detected == 0) { + dialog_text("Warning", "The system did not detect any IDE hard drives. You may attempt to continue booting by exiting this setup, but it is likely to result in failure."); + bios_redraw(); + } + + kb_clear_buffer(); + + while(1) { + static uint8_t extended = 0; + + if(kb_is_available()) { + uint8_t scancode = kb_get_scancode(); + + if(!extended) { + if(scancode==0x01) { // ESC + if(modified == 1) { + if(dialog_yesno(0, "Exit without saving?")) break; + bios_redraw(); + } else { + break; + } + } + + if(scancode==0xE0) { + extended = 1; + } + + if(scancode==0x1C) { // Enter + char option_value[16] = {0}; // old & new + enum OPTION_TYPE_ENUM { + OPTION_TYPE_OTHER, + OPTION_TYPE_YESNO + } OPTION_TYPE; + + // Option fetch + + switch(bios_settings[select].setting) { + case OPTION_QUICK_MEMTEST: + OPTION_TYPE = OPTION_TYPE_YESNO; + option_value[0] = cmos_get(CMOS_QUICK_MEMTEST); + break; + case OPTION_LBA_REPORTING: + OPTION_TYPE = OPTION_TYPE_YESNO; + option_value[0] = cmos_get(CMOS_LBA_ENABLED); + break; + case OPTION_LOCK_CMOS: + OPTION_TYPE = OPTION_TYPE_YESNO; + option_value[0] = cmos_get(CMOS_LOCK_CMOS); + break; + case OPTION_OPEN_ABOUT: + OPTION_TYPE = OPTION_TYPE_OTHER; + break; + + default: + OPTION_TYPE = OPTION_TYPE_OTHER; + break; + } + + // Option change + + if(OPTION_TYPE == OPTION_TYPE_YESNO) { + uint8_t old_option_val = option_value[0]; + option_value[0] = dialog_yesno(option_value[0], bios_settings[select].option_name); + if(old_option_val!=option_value[0]) modified = 1; + } + + // Option update / action + + switch(bios_settings[select].setting) { + case OPTION_QUICK_MEMTEST: + cmos_set(CMOS_QUICK_MEMTEST, option_value[0]); + break; + case OPTION_LBA_REPORTING: + cmos_set(CMOS_LBA_ENABLED, option_value[0]); + break; + case OPTION_LOCK_CMOS: + cmos_set(CMOS_LOCK_CMOS, option_value[0]); + break; + case OPTION_OPEN_ABOUT: + about_display(); + break; + + default: + break; + } + + bios_redraw(); + } + + if(scancode==0x3B) { // F1 help + dialog_text(bios_settings[select].option_name, bios_settings[select].option_help); + bios_redraw(); + } + + if(scancode==0x44) { // F10 save + if(dialog_yesno(0, "Save settings to CMOS?")) { + cmos_save(); + modified = 0; + } + bios_redraw(); + } + } else { + extended = 0; + + if(scancode==0x48) { // up arrow + if(select>0) { + select--; + if(bios_settings[select].setting == OPTION_EMPTY) select--; + draw_options(); + } + + } + if(scancode==0x50) { // down arrow + if(select<(SETTINGS_AMOUNT-1)) { + select++; + if(bios_settings[select].setting == OPTION_EMPTY) select++; + draw_options(); + } + + } + } + + } + } } diff --git a/chipset/CMOS.vhd b/chipset/CMOS.vhd index 31a677a..4f83295 100644 --- a/chipset/CMOS.vhd +++ b/chipset/CMOS.vhd @@ -1,540 +1,531 @@ ----------------------------------------------------------------------------------- --- Company: maniek86.xyz --- Engineer: Piotr Grzesik --- --- Create Date: 19:21:33 11/27/2025 --- Design Name: --- Module Name: CMOS - Behavioral --- Project Name: Hamster 1 chipset --- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: --- Description: Simple CMOS RTC (non volatile) implementation --- --- Dependencies: --- --- Revision: --- Revision 0.01 - File Created --- Additional Comments: --- ----------------------------------------------------------------------------------- -LIBRARY IEEE; -USE IEEE.STD_LOGIC_1164.ALL; -USE IEEE.NUMERIC_STD.ALL; - -ENTITY CMOS IS - PORT ( - CLK_IN : IN STD_LOGIC; - DATA_IN : IN STD_LOGIC_VECTOR(7 downto 0); - DATA_OUT : OUT STD_LOGIC_VECTOR(7 downto 0); - CMOS_CS : IN STD_LOGIC; - WR : IN STD_LOGIC; - RD : IN STD_LOGIC; - A0 : IN STD_LOGIC; - - CLK_PIT : IN STD_LOGIC; - - AVR_CLK : IN STD_LOGIC; - AVR_IO : INOUT STD_LOGIC; - - FPGA_VER : IN STD_LOGIC_VECTOR(31 downto 0); - RESET : IN STD_LOGIC - ); -END CMOS; - -ARCHITECTURE Behavioral OF CMOS IS - -- Clock divider counter - SIGNAL PIT_DIVIDER : INTEGER RANGE 0 TO 1193182 := 0; - SIGNAL TICK_1HZ : STD_LOGIC := '0'; - - -- Time Registers - SIGNAL SECONDS : INTEGER RANGE 0 TO 60 := 0; - SIGNAL MINUTES : INTEGER RANGE 0 TO 60 := 0; - SIGNAL HOURS : INTEGER RANGE 0 TO 24 := 0; - SIGNAL WEEKDAY : INTEGER RANGE 0 TO 8 := 7; -- 1-7 (Sun-Sat) - SIGNAL DAY : INTEGER RANGE 0 TO 32 := 1; - SIGNAL MONTH : INTEGER RANGE 0 to 13 := 11; - SIGNAL YEAR : INTEGER RANGE 0 TO 100 := 25; - SIGNAL CENTURY : INTEGER RANGE 0 TO 99 := 20; - - -- Helper signal for calendar logic - SIGNAL MAX_DAYS_IN_MONTH : INTEGER RANGE 28 TO 31; - SIGNAL IS_LEAP_YEAR : BOOLEAN; - - SIGNAL CURRENT_REGISTER : STD_LOGIC_VECTOR(7 downto 0) := x"00"; - TYPE CMOS_REGISTERS_TYPE IS ARRAY (0 TO 31 ) OF std_logic_vector (7 DOWNTO 0); - SIGNAL CMOS_REGISTERS: CMOS_REGISTERS_TYPE :=( - x"00",x"00",x"00",x"00",-- 0x00 - x"00",x"00",x"00",x"00",-- 0x04 - x"00",x"00",x"00",x"00",-- 0x08 - x"00",x"00",x"00",x"00",-- 0x0C - x"00",x"00",x"00",x"00",-- 0x10 - x"00",x"00",x"00",x"00",-- 0x14 - x"00",x"00",x"00",x"00",-- 0x18 - x"00",x"00",x"00",x"00"-- 0x1C +---------------------------------------------------------------------------------- +-- Company: maniek86.xyz +-- Engineer: Piotr Grzesik +-- +-- Create Date: 19:21:33 11/27/2025 +-- Design Name: +-- Module Name: CMOS - Behavioral +-- Project Name: Hamster 1 chipset +-- Target Devices: M8SBC-486 REV 1.0 +-- Tool versions: +-- Description: Simple CMOS RTC (non volatile) implementation +-- +-- Dependencies: +-- +-- Revision: +-- Revision 0.01 - File Created +-- Additional Comments: +-- +---------------------------------------------------------------------------------- +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +ENTITY CMOS IS + PORT ( + CLK_IN : IN STD_LOGIC; + DATA_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + DATA_OUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + CMOS_CS : IN STD_LOGIC; + WR : IN STD_LOGIC; + RD : IN STD_LOGIC; + A0 : IN STD_LOGIC; + + CLK_PIT : IN STD_LOGIC; + + AVR_CLK : IN STD_LOGIC; + AVR_IO : INOUT STD_LOGIC; + + FPGA_VER : IN STD_LOGIC_VECTOR(31 DOWNTO 0); + RESET : IN STD_LOGIC ); - - SIGNAL CMOS_WRITE_PROTECT : STD_LOGIC := '0'; - - SIGNAL TRANSFER_CONFIG : STD_LOGIC := '1'; -- Init - SIGNAL TRANSFER_CONFIG_NEXT_END : STD_LOGIC := '0'; - - SIGNAL RECEIVED_CONFIG : STD_LOGIC := '0'; - SIGNAL RECEIVED_PREAM : STD_LOGIC := '0'; - SIGNAL PREAM_COUNT : INTEGER RANGE 0 TO 7 := 0; - SIGNAL S1_AVR_CLK : STD_LOGIC := '0'; - SIGNAL S1_AVR_DIN : STD_LOGIC := '0'; - SIGNAL S2_AVR_CLK : STD_LOGIC := '0'; - SIGNAL S2_AVR_DIN : STD_LOGIC := '0'; - SIGNAL LAST_AVR_CLK : STD_LOGIC := '0'; - - SIGNAL CONFIG_COUNT : INTEGER RANGE 0 TO 31 := 0; - SIGNAL CONFIG_C_BIT : INTEGER RANGE 0 TO 7 := 0; - SIGNAL CONFIG_TEMP : STD_LOGIC_VECTOR(7 downto 0) := x"00"; - - SIGNAL AVR_OUT : STD_LOGIC := '0'; - - SIGNAL RAM_WRITE_EN, BUS_WRITER_EN : STD_LOGIC; - SIGNAL CFG_WRITER_EN : STD_LOGIC := '0'; - SIGNAL CFG_WRITER_ADDR : INTEGER RANGE 0 to 31 := 0; - SIGNAL RAM_WRITE_VAL, CFG_WRITER_VAL, RAM_OUT : STD_LOGIC_VECTOR(7 downto 0); - SIGNAL BUS_WRITER_VAL : STD_LOGIC_VECTOR(7 downto 0) := x"00"; - SIGNAL RAM_WRITE_ADDR, BUS_WRITER_ADDR : INTEGER RANGE 0 to 31; - - CONSTANT CYCLES_WAIT_TO_TRANSFER : INTEGER := 100000; -- How many CPU cycles to wait before attempting to store data - - - - SIGNAL TRANSFER_TIMER : INTEGER RANGE 0 to CYCLES_WAIT_TO_TRANSFER+1 := 0; - SIGNAL CONFIG_DATA_DIRTY : STD_LOGIC := '0'; - SIGNAL LAST_CONFIG_DATA_DIRTY : STD_LOGIC := '0'; - SIGNAL CONFIG_DO_WRITE : STD_LOGIC := '0'; - SIGNAL TRANSFER_DIRTY : STD_LOGIC := '0'; - SIGNAL CONFIG_WRITE_PHASE : INTEGER RANGE 0 to 2 := 0; - SIGNAL CFG_SKIP_CLK : STD_LOGIC := '0'; - +END CMOS; + +ARCHITECTURE Behavioral OF CMOS IS + -- Clock divider counter + SIGNAL PIT_DIVIDER : INTEGER RANGE 0 TO 1193182 := 0; + SIGNAL TICK_1HZ : STD_LOGIC := '0'; + + -- Time Registers + SIGNAL SECONDS : INTEGER RANGE 0 TO 60 := 0; + SIGNAL MINUTES : INTEGER RANGE 0 TO 60 := 0; + SIGNAL HOURS : INTEGER RANGE 0 TO 24 := 0; + SIGNAL WEEKDAY : INTEGER RANGE 0 TO 8 := 7; -- 1-7 (Sun-Sat) + SIGNAL DAY : INTEGER RANGE 0 TO 32 := 1; + SIGNAL MONTH : INTEGER RANGE 0 TO 13 := 11; + SIGNAL YEAR : INTEGER RANGE 0 TO 100 := 25; + SIGNAL CENTURY : INTEGER RANGE 0 TO 99 := 20; + + -- Helper signal for calendar logic + SIGNAL MAX_DAYS_IN_MONTH : INTEGER RANGE 28 TO 31; + SIGNAL IS_LEAP_YEAR : BOOLEAN; + + SIGNAL CURRENT_REGISTER : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"00"; + TYPE CMOS_REGISTERS_TYPE IS ARRAY (0 TO 31 ) OF std_logic_vector (7 DOWNTO 0); + SIGNAL CMOS_REGISTERS: CMOS_REGISTERS_TYPE :=( + x"00",x"00",x"00",x"00",-- 0x00 + x"00",x"00",x"00",x"00",-- 0x04 + x"00",x"00",x"00",x"00",-- 0x08 + x"00",x"00",x"00",x"00",-- 0x0C + x"00",x"00",x"00",x"00",-- 0x10 + x"00",x"00",x"00",x"00",-- 0x14 + x"00",x"00",x"00",x"00",-- 0x18 + x"00",x"00",x"00",x"00"-- 0x1C + ); + + SIGNAL CMOS_WRITE_PROTECT : STD_LOGIC := '0'; + + SIGNAL TRANSFER_CONFIG : STD_LOGIC := '1'; -- Init + SIGNAL TRANSFER_CONFIG_NEXT_END : STD_LOGIC := '0'; + + SIGNAL RECEIVED_CONFIG : STD_LOGIC := '0'; + SIGNAL RECEIVED_PREAM : STD_LOGIC := '0'; + SIGNAL PREAM_COUNT : INTEGER RANGE 0 TO 7 := 0; + SIGNAL S1_AVR_CLK : STD_LOGIC := '0'; + SIGNAL S1_AVR_DIN : STD_LOGIC := '0'; + SIGNAL S2_AVR_CLK : STD_LOGIC := '0'; + SIGNAL S2_AVR_DIN : STD_LOGIC := '0'; + SIGNAL LAST_AVR_CLK : STD_LOGIC := '0'; + + SIGNAL CONFIG_COUNT : INTEGER RANGE 0 TO 31 := 0; + SIGNAL CONFIG_C_BIT : INTEGER RANGE 0 TO 7 := 0; + SIGNAL CONFIG_TEMP : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"00"; + + SIGNAL AVR_OUT : STD_LOGIC := '0'; + + SIGNAL RAM_WRITE_EN, BUS_WRITER_EN : STD_LOGIC; + SIGNAL CFG_WRITER_EN : STD_LOGIC := '0'; + SIGNAL CFG_WRITER_ADDR : INTEGER RANGE 0 TO 31 := 0; + SIGNAL BUS_WRITER_VAL : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"00"; + SIGNAL RAM_WRITE_VAL, CFG_WRITER_VAL, RAM_OUT : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL RAM_WRITE_ADDR, BUS_WRITER_ADDR : INTEGER RANGE 0 TO 31; + + CONSTANT CYCLES_WAIT_TO_TRANSFER : INTEGER := 100000; -- How many CPU cycles to wait before attempting to store data + + SIGNAL TRANSFER_TIMER : INTEGER RANGE 0 TO CYCLES_WAIT_TO_TRANSFER+1 := 0; + SIGNAL CONFIG_DATA_DIRTY : STD_LOGIC := '0'; + SIGNAL LAST_CONFIG_DATA_DIRTY : STD_LOGIC := '0'; + SIGNAL CONFIG_DO_WRITE : STD_LOGIC := '0'; + SIGNAL TRANSFER_DIRTY : STD_LOGIC := '0'; + SIGNAL CONFIG_WRITE_PHASE : INTEGER RANGE 0 TO 2 := 0; + SIGNAL CFG_SKIP_CLK : STD_LOGIC := '0'; + SIGNAL BUS_ACCESS : STD_LOGIC; - SIGNAL CMOS_IN_RANGE : STD_LOGIC; - -BEGIN - - -- AVR communication process - -- On bitstream load, the FPGA awaits for 33 bytes sent serially on two IO reusable FPGA config lines from ATMega - -- Protocol: DIN - CLK source, INIT - Data. CLK is always driven by AVR which after initial config awaits for DIN to get pulled low - -- Clocked on raising clock - -- Restore: (FPGA in, AVR out) - -- 11110101 [byte 0] [byte 1] [byte 2] ... [byte 31] - -- - -- Store: (FPGA out, AVR in) - -- 11110101 [byte 0] [byte 1] [byte 2] ... [byte 31] 10101010 - PROCESS(CLK_IN) - VARIABLE AVR_OUT_TMP : STD_LOGIC; - VARIABLE CONFIG_TEMP_VAR : STD_LOGIC_VECTOR (7 downto 0); - BEGIN - IF FALLING_EDGE(CLK_IN) THEN - S1_AVR_CLK <= AVR_CLK; -- 2-FF sync - S1_AVR_DIN <= AVR_IO; - S2_AVR_CLK <= S1_AVR_CLK; - S2_AVR_DIN <= S1_AVR_DIN; - - - IF WR = '0' AND A0 = '1' AND CMOS_CS = '0' AND CMOS_IN_RANGE = '1' AND CMOS_WRITE_PROTECT = '0' THEN -- write oqcuired - TRANSFER_TIMER <= 0; - CONFIG_DATA_DIRTY <= '1'; - ELSE - - IF RECEIVED_CONFIG = '1' AND CONFIG_DO_WRITE = '0' THEN -- When config is received and we are not in write - IF TRANSFER_TIMER >= CYCLES_WAIT_TO_TRANSFER THEN -- Timer time out - IF CONFIG_DATA_DIRTY = '1' OR TRANSFER_DIRTY = '1' THEN - -- Initialize write - CONFIG_COUNT <= 0; - CONFIG_C_BIT <= 0; - CONFIG_DO_WRITE <= '1'; - TRANSFER_DIRTY <= '0'; - TRANSFER_CONFIG <= '1'; - TRANSFER_CONFIG_NEXT_END <= '0'; - CONFIG_WRITE_PHASE <= 0; - CFG_WRITER_EN <= '0'; - CONFIG_DATA_DIRTY <= '0'; - - CFG_SKIP_CLK <= '1'; - END IF; - ELSE - IF CONFIG_DATA_DIRTY /= LAST_CONFIG_DATA_DIRTY THEN - TRANSFER_TIMER <= 0; - ELSE - TRANSFER_TIMER <= TRANSFER_TIMER + 1; - END IF; - END IF; - END IF; - END IF; - - - LAST_CONFIG_DATA_DIRTY <= CONFIG_DATA_DIRTY; - - CFG_WRITER_ADDR <= CONFIG_COUNT; - - -- if RD or WR became 0, transfer is dirty!!! - - IF LAST_AVR_CLK /= S2_AVR_CLK AND S2_AVR_CLK = '1' THEN - -- happens on rising edge - IF RECEIVED_CONFIG = '0' THEN - - CONFIG_TEMP(7 downto 0) <= CONFIG_TEMP(6 downto 0) & S2_AVR_DIN; - - IF RECEIVED_PREAM = '1' THEN - - IF CONFIG_C_BIT = 7 THEN - CONFIG_C_BIT <= 0; - CFG_WRITER_EN <= '1'; - CFG_WRITER_VAL <= CONFIG_TEMP; - - IF CONFIG_COUNT = 31 THEN - -- Finished - TRANSFER_CONFIG_NEXT_END <= '1'; - ELSE - CONFIG_COUNT <= CONFIG_COUNT + 1; - END IF; - ELSE - CFG_WRITER_EN <= '0'; - CONFIG_C_BIT <= CONFIG_C_BIT + 1; - IF TRANSFER_CONFIG_NEXT_END = '1' THEN - TRANSFER_CONFIG <= '0'; - RECEIVED_CONFIG <= '1'; - END IF; - END IF; - ELSE - -- wait for 11110101 - IF CONFIG_TEMP = X"F5" THEN - RECEIVED_PREAM <= '1'; - ELSE - IF PREAM_COUNT = 7 THEN - PREAM_COUNT <= 0; - ELSE - PREAM_COUNT <= PREAM_COUNT + 1; - END IF; - END IF; - - END IF; - - ELSE --RECEIVED_CONFIG = '1' - -- write data loop if write is in progress - -- if BUS_ACCESS becomes '1' during write then discard data - IF CFG_SKIP_CLK = '1' THEN - CFG_SKIP_CLK <= '0'; -- To not start in middle of clk - ELSE - IF CONFIG_DO_WRITE = '1' THEN - IF BUS_ACCESS = '0' THEN -- Bus access to cfg writer - --IF TRANSFER_DIRTY = '1' THEN -- Cancel access but continue clocking - -- Even if write occurs while phase 0, config_count should be 0 anyway - -- We need to clock till the end to not begin another transfer - -- while AVR is still probing for data - - --ELSE -- Write loop (normal state) - CASE CONFIG_WRITE_PHASE IS - WHEN 0 => - CONFIG_TEMP_VAR := X"F5"; - WHEN 1 => - CONFIG_TEMP_VAR := RAM_OUT; - WHEN 2 => - CONFIG_TEMP_VAR := X"AA"; - END CASE; - - AVR_OUT_TMP := CONFIG_TEMP_VAR(7 - CONFIG_C_BIT); -- Send MSB first - - IF TRANSFER_DIRTY = '1' THEN - AVR_OUT <= '0'; -- cancel - ELSE - IF AVR_OUT_TMP = '1' THEN - AVR_OUT <= 'Z'; -- replace with Z later - ELSE - AVR_OUT <= '0'; - END IF; - END IF; - - IF CONFIG_C_BIT = 7 THEN - CONFIG_C_BIT <= 0; - CASE CONFIG_WRITE_PHASE IS - WHEN 0 => - CONFIG_WRITE_PHASE <= 1; - WHEN 1 => - IF CONFIG_COUNT = 31 THEN - CONFIG_WRITE_PHASE <= 2; - ELSE - CONFIG_COUNT <= CONFIG_COUNT + 1; - END IF; - WHEN 2 => - -- Finish - TRANSFER_CONFIG <= '0'; - CONFIG_DO_WRITE <= '0'; - END CASE; - ELSE - CONFIG_C_BIT <= CONFIG_C_BIT + 1; - END IF; - - --END IF; -- transfer_dirty - ELSE -- If BUS access becomes 1 (bus access to CPU) - TRANSFER_DIRTY <= '1'; - AVR_OUT <= '0'; - END IF; - END IF; -- CONFIG_DO_WRITE - END IF; -- CFG_SKIP_CLK - - END IF; -- RECEIVED_CONFIG - END IF; -- CLK CHECK - - LAST_AVR_CLK <= S2_AVR_CLK; - END IF; - END PROCESS; - - AVR_IO <= 'Z' WHEN RECEIVED_CONFIG = '0' ELSE AVR_OUT; - - RAM_WRITE_VAL <= CFG_WRITER_VAL WHEN TRANSFER_CONFIG = '1' AND BUS_ACCESS = '0' ELSE BUS_WRITER_VAL; - RAM_WRITE_ADDR <= CFG_WRITER_ADDR WHEN TRANSFER_CONFIG = '1' AND BUS_ACCESS = '0' ELSE BUS_WRITER_ADDR; + SIGNAL CMOS_IN_RANGE : STD_LOGIC; +BEGIN + + -- AVR communication process + -- On bitstream load, the FPGA awaits for 33 bytes sent serially on two IO reusable FPGA config lines from ATMega + -- Protocol: DIN - CLK source, INIT - Data. CLK is always driven by AVR which after initial config awaits for DIN to get pulled low + -- Clocked on raising clock + -- Restore: (FPGA in, AVR out) + -- 11110101 [byte 0] [byte 1] [byte 2] ... [byte 31] + -- + -- Store: (FPGA out, AVR in) + -- 11110101 [byte 0] [byte 1] [byte 2] ... [byte 31] 10101010 + PROCESS(CLK_IN) + VARIABLE AVR_OUT_TMP : STD_LOGIC; + VARIABLE CONFIG_TEMP_VAR : STD_LOGIC_VECTOR (7 DOWNTO 0); + BEGIN + IF FALLING_EDGE(CLK_IN) THEN + S1_AVR_CLK <= AVR_CLK; -- 2-FF sync + S1_AVR_DIN <= AVR_IO; + S2_AVR_CLK <= S1_AVR_CLK; + S2_AVR_DIN <= S1_AVR_DIN; + + IF WR = '0' AND A0 = '1' AND CMOS_CS = '0' AND CMOS_IN_RANGE = '1' AND CMOS_WRITE_PROTECT = '0' THEN -- write oqcuired + TRANSFER_TIMER <= 0; + CONFIG_DATA_DIRTY <= '1'; + ELSE + + IF RECEIVED_CONFIG = '1' AND CONFIG_DO_WRITE = '0' THEN -- When config is received and we are not in write + IF TRANSFER_TIMER >= CYCLES_WAIT_TO_TRANSFER THEN -- Timer time out + IF CONFIG_DATA_DIRTY = '1' OR TRANSFER_DIRTY = '1' THEN + -- Initialize write + CONFIG_COUNT <= 0; + CONFIG_C_BIT <= 0; + CONFIG_DO_WRITE <= '1'; + TRANSFER_DIRTY <= '0'; + TRANSFER_CONFIG <= '1'; + TRANSFER_CONFIG_NEXT_END <= '0'; + CONFIG_WRITE_PHASE <= 0; + CFG_WRITER_EN <= '0'; + CONFIG_DATA_DIRTY <= '0'; + + CFG_SKIP_CLK <= '1'; + END IF; + ELSE + IF CONFIG_DATA_DIRTY /= LAST_CONFIG_DATA_DIRTY THEN + TRANSFER_TIMER <= 0; + ELSE + TRANSFER_TIMER <= TRANSFER_TIMER + 1; + END IF; + END IF; + END IF; + END IF; + + LAST_CONFIG_DATA_DIRTY <= CONFIG_DATA_DIRTY; + + CFG_WRITER_ADDR <= CONFIG_COUNT; + + -- if RD or WR became 0, transfer is dirty!!! + + IF LAST_AVR_CLK /= S2_AVR_CLK AND S2_AVR_CLK = '1' THEN + -- happens on rising edge + IF RECEIVED_CONFIG = '0' THEN + + CONFIG_TEMP(7 DOWNTO 0) <= CONFIG_TEMP(6 DOWNTO 0) & S2_AVR_DIN; + + IF RECEIVED_PREAM = '1' THEN + + IF CONFIG_C_BIT = 7 THEN + CONFIG_C_BIT <= 0; + CFG_WRITER_EN <= '1'; + CFG_WRITER_VAL <= CONFIG_TEMP; + + IF CONFIG_COUNT = 31 THEN + -- Finished + TRANSFER_CONFIG_NEXT_END <= '1'; + ELSE + CONFIG_COUNT <= CONFIG_COUNT + 1; + END IF; + ELSE + CFG_WRITER_EN <= '0'; + CONFIG_C_BIT <= CONFIG_C_BIT + 1; + IF TRANSFER_CONFIG_NEXT_END = '1' THEN + TRANSFER_CONFIG <= '0'; + RECEIVED_CONFIG <= '1'; + END IF; + END IF; + ELSE + -- wait for 11110101 + IF CONFIG_TEMP = X"F5" THEN + RECEIVED_PREAM <= '1'; + ELSE + IF PREAM_COUNT = 7 THEN + PREAM_COUNT <= 0; + ELSE + PREAM_COUNT <= PREAM_COUNT + 1; + END IF; + END IF; + + END IF; + + ELSE --RECEIVED_CONFIG = '1' + -- write data loop if write is in progress + -- if BUS_ACCESS becomes '1' during write then discard data + IF CFG_SKIP_CLK = '1' THEN + CFG_SKIP_CLK <= '0'; -- To not start in middle of clk + ELSE + IF CONFIG_DO_WRITE = '1' THEN + IF BUS_ACCESS = '0' THEN -- Bus access to cfg writer + --IF TRANSFER_DIRTY = '1' THEN -- Cancel access but continue clocking + -- Even if write occurs while phase 0, config_count should be 0 anyway + -- We need to clock till the end to not begin another transfer + -- while AVR is still probing for data + + --ELSE -- Write loop (normal state) + CASE CONFIG_WRITE_PHASE IS + WHEN 0 => + CONFIG_TEMP_VAR := X"F5"; + WHEN 1 => + CONFIG_TEMP_VAR := RAM_OUT; + WHEN 2 => + CONFIG_TEMP_VAR := X"AA"; + END CASE; + + AVR_OUT_TMP := CONFIG_TEMP_VAR(7 - CONFIG_C_BIT); -- Send MSB first + + IF TRANSFER_DIRTY = '1' THEN + AVR_OUT <= '0'; -- cancel + ELSE + IF AVR_OUT_TMP = '1' THEN + AVR_OUT <= 'Z'; -- replace with Z later + ELSE + AVR_OUT <= '0'; + END IF; + END IF; + + IF CONFIG_C_BIT = 7 THEN + CONFIG_C_BIT <= 0; + CASE CONFIG_WRITE_PHASE IS + WHEN 0 => + CONFIG_WRITE_PHASE <= 1; + WHEN 1 => + IF CONFIG_COUNT = 31 THEN + CONFIG_WRITE_PHASE <= 2; + ELSE + CONFIG_COUNT <= CONFIG_COUNT + 1; + END IF; + WHEN 2 => + -- Finish + TRANSFER_CONFIG <= '0'; + CONFIG_DO_WRITE <= '0'; + END CASE; + ELSE + CONFIG_C_BIT <= CONFIG_C_BIT + 1; + END IF; + + --END IF; -- transfer_dirty + ELSE -- If BUS access becomes 1 (bus access to CPU) + TRANSFER_DIRTY <= '1'; + AVR_OUT <= '0'; + END IF; + END IF; -- CONFIG_DO_WRITE + END IF; -- CFG_SKIP_CLK + + END IF; -- RECEIVED_CONFIG + END IF; -- CLK CHECK + + LAST_AVR_CLK <= S2_AVR_CLK; + END IF; + END PROCESS; + + AVR_IO <= 'Z' WHEN RECEIVED_CONFIG = '0' ELSE AVR_OUT; + + RAM_WRITE_VAL <= CFG_WRITER_VAL WHEN TRANSFER_CONFIG = '1' AND BUS_ACCESS = '0' ELSE BUS_WRITER_VAL; + RAM_WRITE_ADDR <= CFG_WRITER_ADDR WHEN TRANSFER_CONFIG = '1' AND BUS_ACCESS = '0' ELSE BUS_WRITER_ADDR; RAM_WRITE_EN <= CFG_WRITER_EN WHEN TRANSFER_CONFIG = '1' AND BUS_ACCESS = '0' ELSE BUS_WRITER_EN; - + PROCESS(CURRENT_REGISTER) -- cmos_in_range VARIABLE ADDR_INT : UNSIGNED(7 DOWNTO 0); BEGIN ADDR_INT := UNSIGNED(CURRENT_REGISTER); - IF ADDR_INT >= 64 AND ADDR_INT < 96 THEN -- 0x40 - 0x5F - CMOS_IN_RANGE <= '1'; - ELSE - CMOS_IN_RANGE <= '0'; + IF ADDR_INT >= 64 AND ADDR_INT < 96 THEN -- 0x40 - 0x5F + CMOS_IN_RANGE <= '1'; + ELSE + CMOS_IN_RANGE <= '0'; + END IF; + END PROCESS; + + PROCESS(CLK_IN) -- CMOS RAM process + BEGIN + IF FALLING_EDGE(CLK_IN) THEN + IF RAM_WRITE_EN = '1' THEN + CMOS_REGISTERS(RAM_WRITE_ADDR) <= RAM_WRITE_VAL; + END IF; + RAM_OUT <= CMOS_REGISTERS(RAM_WRITE_ADDR); -- (sync) END IF; - END PROCESS; - - PROCESS(CLK_IN) -- CMOS RAM process - BEGIN - IF FALLING_EDGE(CLK_IN) THEN - IF RAM_WRITE_EN = '1' THEN - CMOS_REGISTERS(RAM_WRITE_ADDR) <= RAM_WRITE_VAL; - END IF; - RAM_OUT <= CMOS_REGISTERS(RAM_WRITE_ADDR); -- (sync) - END IF; - END PROCESS; - --RAM_OUT <= CMOS_REGISTERS(RAM_WRITE_ADDR); -- also read_addr (async) - - - PROCESS(CLK_IN, CURRENT_REGISTER, RESET, CMOS_CS, WR, RECEIVED_CONFIG, A0, CMOS_WRITE_PROTECT, RD, SECONDS, MINUTES, HOURS, DAY, MONTH, YEAR, CENTURY, FPGA_VER, RAM_OUT, WEEKDAY, CMOS_IN_RANGE) - VARIABLE DATA_OUT_FINAL : STD_LOGIC_VECTOR(7 downto 0); - BEGIN - DATA_OUT_FINAL := x"00"; - - BUS_WRITER_ADDR <= to_integer(unsigned(CURRENT_REGISTER(4 downto 0))); -- for base dividable by 0x20 - --BUS_WRITER_ADDR <= to_integer(unsigned(CURRENT_REGISTER(5 downto 0)) - 16); -- for base dividable by 0x10 - + END PROCESS; + --RAM_OUT <= CMOS_REGISTERS(RAM_WRITE_ADDR); -- also read_addr (async) + + PROCESS(CLK_IN, CURRENT_REGISTER, RESET, CMOS_CS, WR, RECEIVED_CONFIG, A0, CMOS_WRITE_PROTECT, RD, SECONDS, MINUTES, HOURS, DAY, MONTH, YEAR, CENTURY, FPGA_VER, RAM_OUT, WEEKDAY, CMOS_IN_RANGE) + VARIABLE DATA_OUT_FINAL : STD_LOGIC_VECTOR(7 DOWNTO 0); + BEGIN + DATA_OUT_FINAL := x"00"; + + BUS_WRITER_ADDR <= to_integer(unsigned(CURRENT_REGISTER(4 DOWNTO 0))); -- for base dividable by 0x20 + --BUS_WRITER_ADDR <= to_integer(unsigned(CURRENT_REGISTER(5 DOWNTO 0)) - 16); -- for base dividable by 0x10 + IF RESET = '1' THEN CMOS_WRITE_PROTECT <= '0'; - END IF; - - IF CMOS_CS = '0' AND RESET = '0' THEN - IF WR = '0' THEN -- Write - - IF CMOS_IN_RANGE = '1' AND RECEIVED_CONFIG = '1' AND A0 = '1' AND CMOS_WRITE_PROTECT = '0' THEN -- range (0x20 - 0x40), check A1 as bus access is only at port 71 - BUS_WRITER_EN <= '1'; - BUS_ACCESS <= '1'; - ELSE - BUS_WRITER_EN <= '0'; - BUS_ACCESS <= '0'; - END IF; - - IF FALLING_EDGE(CLK_IN) THEN - IF (A0 = '0') THEN -- 0x70 - -- Cmos register - CURRENT_REGISTER <= DATA_IN; - ELSE -- 0x71 - - CASE CURRENT_REGISTER IS + END IF; + + IF CMOS_CS = '0' AND RESET = '0' THEN + IF WR = '0' THEN -- Write + + IF CMOS_IN_RANGE = '1' AND RECEIVED_CONFIG = '1' AND A0 = '1' AND CMOS_WRITE_PROTECT = '0' THEN -- range (0x20 - 0x40), check A1 as bus access is only at port 71 + BUS_WRITER_EN <= '1'; + BUS_ACCESS <= '1'; + ELSE + BUS_WRITER_EN <= '0'; + BUS_ACCESS <= '0'; + END IF; + + IF FALLING_EDGE(CLK_IN) THEN + IF (A0 = '0') THEN -- 0x70 + -- Cmos register + CURRENT_REGISTER <= DATA_IN; + ELSE -- 0x71 + + CASE CURRENT_REGISTER IS WHEN x"FF" => -- Chipset command register - + IF DATA_IN = x"17" THEN -- 0x17 - lock CMOS until reset CMOS_WRITE_PROTECT <= '1'; END IF; - - WHEN OTHERS => + + WHEN OTHERS => BUS_WRITER_VAL <= DATA_IN; END CASE; - - END IF; - - END IF; - - ELSIF RD = '0' THEN -- Read - IF CMOS_IN_RANGE = '1' AND RECEIVED_CONFIG = '1' AND A0 = '1' THEN - BUS_ACCESS <= '1'; - ELSE - BUS_ACCESS <= '0'; - END IF; - BUS_WRITER_EN <= '0'; - - IF (A0 = '0') THEN -- 0x70 - DATA_OUT_FINAL := CURRENT_REGISTER; - END IF; - IF (A0 = '1') THEN -- 0x71 - CASE CURRENT_REGISTER IS - WHEN x"00" => -- Seconds - DATA_OUT_FINAL := std_logic_vector(to_unsigned(SECONDS, 8)); - WHEN x"02" => -- Minutes - DATA_OUT_FINAL := std_logic_vector(to_unsigned(MINUTES, 8)); - WHEN x"04" => -- Hours - DATA_OUT_FINAL := std_logic_vector(to_unsigned(HOURS, 8)); - WHEN x"06" => -- Weekday - DATA_OUT_FINAL := std_logic_vector(to_unsigned(WEEKDAY, 8)); - WHEN x"07" => -- Day of month - DATA_OUT_FINAL := std_logic_vector(to_unsigned(DAY, 8)); - WHEN x"08" => -- Month - DATA_OUT_FINAL := std_logic_vector(to_unsigned(MONTH, 8)); - WHEN x"09" => -- Year - DATA_OUT_FINAL := std_logic_vector(to_unsigned(YEAR, 8)); - WHEN x"32" => -- Century - DATA_OUT_FINAL := std_logic_vector(to_unsigned(CENTURY, 8)); - WHEN x"0A" => -- Status register A - -- STATUS REGISTER A (Offset 0x0A) - -- Bit 7 (UIP): '0' -> Update NOT in progress (Always safe to read) - -- Bits 6-4 (Div): '010' -> 32.768kHz reference (Standard) - -- Bits 3-0 (Rate): '0110' -> 1kHz interrupt rate (Standard) - -- Result: 00100110 - DATA_OUT_FINAL := "00100110"; - WHEN x"0B" => -- Status register B - -- Bit 7 (SET): '0' -> Running normal - -- Bit 2 (DM): '1' -> BINARY MODE (Crucial! because we output std_logic_vector of integer) - -- Bit 1 (24/12): '1' -> 24 Hour Format - -- Result: 00000110 + + END IF; + END IF; + + ELSIF RD = '0' THEN -- Read + IF CMOS_IN_RANGE = '1' AND RECEIVED_CONFIG = '1' AND A0 = '1' THEN + BUS_ACCESS <= '1'; + ELSE + BUS_ACCESS <= '0'; + END IF; + BUS_WRITER_EN <= '0'; + + IF (A0 = '0') THEN -- 0x70 + DATA_OUT_FINAL := CURRENT_REGISTER; + END IF; + IF (A0 = '1') THEN -- 0x71 + CASE CURRENT_REGISTER IS + WHEN x"00" => -- Seconds + DATA_OUT_FINAL := std_logic_vector(to_unsigned(SECONDS, 8)); + WHEN x"02" => -- Minutes + DATA_OUT_FINAL := std_logic_vector(to_unsigned(MINUTES, 8)); + WHEN x"04" => -- Hours + DATA_OUT_FINAL := std_logic_vector(to_unsigned(HOURS, 8)); + WHEN x"06" => -- Weekday + DATA_OUT_FINAL := std_logic_vector(to_unsigned(WEEKDAY, 8)); + WHEN x"07" => -- Day of month + DATA_OUT_FINAL := std_logic_vector(to_unsigned(DAY, 8)); + WHEN x"08" => -- Month + DATA_OUT_FINAL := std_logic_vector(to_unsigned(MONTH, 8)); + WHEN x"09" => -- Year + DATA_OUT_FINAL := std_logic_vector(to_unsigned(YEAR, 8)); + WHEN x"32" => -- Century + DATA_OUT_FINAL := std_logic_vector(to_unsigned(CENTURY, 8)); + WHEN x"0A" => -- Status register A + -- STATUS REGISTER A (Offset 0x0A) + -- Bit 7 (UIP): '0' -> Update NOT in progress (Always safe to read) + -- Bits 6-4 (Div): '010' -> 32.768kHz reference (Standard) + -- Bits 3-0 (Rate): '0110' -> 1kHz interrupt rate (Standard) + -- Result: 00100110 + DATA_OUT_FINAL := "00100110"; + WHEN x"0B" => -- Status register B + -- Bit 7 (SET): '0' -> Running normal + -- Bit 2 (DM): '1' -> BINARY MODE (Crucial! because we output std_logic_vector of integer) + -- Bit 1 (24/12): '1' -> 24 Hour Format + -- Result: 00000110 DATA_OUT_FINAL := "00000110"; - + WHEN x"FC" => - DATA_OUT_FINAL := FPGA_VER(31 downto 24); + DATA_OUT_FINAL := FPGA_VER(31 DOWNTO 24); WHEN x"FD" => - DATA_OUT_FINAL := FPGA_VER(23 downto 16); + DATA_OUT_FINAL := FPGA_VER(23 DOWNTO 16); WHEN x"FE" => - DATA_OUT_FINAL := FPGA_VER(15 downto 8); + DATA_OUT_FINAL := FPGA_VER(15 DOWNTO 8); WHEN x"FF" => - DATA_OUT_FINAL := FPGA_VER(7 downto 0); - - WHEN OTHERS => - IF CMOS_IN_RANGE = '1' THEN - IF RECEIVED_CONFIG = '1' THEN - DATA_OUT_FINAL := RAM_OUT; - ELSE - DATA_OUT_FINAL := x"FF"; - END IF; - ELSE - DATA_OUT_FINAL := x"00"; - END IF; - END CASE; - - END IF; - ELSE - BUS_ACCESS <= '0'; - BUS_WRITER_EN <= '0'; - DATA_OUT_FINAL := x"00"; - END IF; - ELSE - BUS_ACCESS <= '0'; - BUS_WRITER_EN <= '0'; - END IF; -- CMOS CS check - - - DATA_OUT <= DATA_OUT_FINAL; -- def - - END PROCESS; - - -- 1. Frequency Divider Process - -- Assumes CLK_PIT is approx 1.1931818 MHz. - -- Generates a single cycle pulse (TICK_1HZ) every second. - PROCESS(CLK_PIT) - BEGIN - IF rising_edge(CLK_PIT) THEN - IF PIT_DIVIDER >= 1193181 THEN - PIT_DIVIDER <= 0; - TICK_1HZ <= '1'; - ELSE - PIT_DIVIDER <= PIT_DIVIDER + 1; - TICK_1HZ <= '0'; - END IF; - END IF; - END PROCESS; - - -- 2. Leap Year Calculation - -- A year is leap if divisible by 4. - -- (Simplified logic: Since YEAR is 0-99, checking last 2 bits = 00 covers mod 4) - IS_LEAP_YEAR <= (YEAR rem 4 = 0); - - -- 3. Max Days in Month Logic - PROCESS(MONTH, IS_LEAP_YEAR) - BEGIN - CASE MONTH IS - WHEN 4 | 6 | 9 | 11 => -- April, June, Sept, Nov - MAX_DAYS_IN_MONTH <= 30; - WHEN 2 => -- February - IF IS_LEAP_YEAR THEN - MAX_DAYS_IN_MONTH <= 29; - ELSE - MAX_DAYS_IN_MONTH <= 28; - END IF; - WHEN OTHERS => -- Jan, Mar, May, Jul, Aug, Oct, Dec - MAX_DAYS_IN_MONTH <= 31; - END CASE; - END PROCESS; - - -- 4. Main Time-Keeping Process - PROCESS(CLK_PIT) - BEGIN - IF rising_edge(CLK_PIT) THEN - IF TICK_1HZ = '1' THEN - -- Increment Seconds - IF SECONDS >= 59 THEN - SECONDS <= 0; - - -- Increment Minutes - IF MINUTES >= 59 THEN - MINUTES <= 0; - - -- Increment Hours - IF HOURS >= 23 THEN - HOURS <= 0; - - -- Increment Weekday (1-7) - IF WEEKDAY >= 7 THEN - WEEKDAY <= 1; - ELSE - WEEKDAY <= WEEKDAY + 1; - END IF; - - -- Increment Day/Month/Year - IF DAY >= MAX_DAYS_IN_MONTH THEN - DAY <= 1; - - -- Increment Month - IF MONTH >= 12 THEN - MONTH <= 1; - - -- Increment Year - IF YEAR >= 99 THEN - YEAR <= 0; - CENTURY <= CENTURY + 1; - ELSE - YEAR <= YEAR + 1; - END IF; - ELSE - MONTH <= MONTH + 1; - END IF; - ELSE - DAY <= DAY + 1; - END IF; -- End Day check - - ELSE - HOURS <= HOURS + 1; - END IF; -- End Hours check - ELSE - MINUTES <= MINUTES + 1; - END IF; -- End Minutes check - ELSE - SECONDS <= SECONDS + 1; - END IF; -- End Seconds check - END IF; -- End Tick check - END IF; - END PROCESS; - -END BEHAVIORAL; - + DATA_OUT_FINAL := FPGA_VER(7 DOWNTO 0); + + WHEN OTHERS => + IF CMOS_IN_RANGE = '1' THEN + IF RECEIVED_CONFIG = '1' THEN + DATA_OUT_FINAL := RAM_OUT; + ELSE + DATA_OUT_FINAL := x"FF"; + END IF; + ELSE + DATA_OUT_FINAL := x"00"; + END IF; + END CASE; + + END IF; + ELSE + BUS_ACCESS <= '0'; + BUS_WRITER_EN <= '0'; + DATA_OUT_FINAL := x"00"; + END IF; + ELSE + BUS_ACCESS <= '0'; + BUS_WRITER_EN <= '0'; + END IF; -- CMOS CS check + + DATA_OUT <= DATA_OUT_FINAL; -- def + + END PROCESS; + + -- 1. Frequency Divider Process + -- Assumes CLK_PIT is approx 1.1931818 MHz. + -- Generates a single cycle pulse (TICK_1HZ) every second. + PROCESS(CLK_PIT) + BEGIN + IF rising_edge(CLK_PIT) THEN + IF PIT_DIVIDER >= 1193181 THEN + PIT_DIVIDER <= 0; + TICK_1HZ <= '1'; + ELSE + PIT_DIVIDER <= PIT_DIVIDER + 1; + TICK_1HZ <= '0'; + END IF; + END IF; + END PROCESS; + + -- 2. Leap Year Calculation + -- A year is leap if divisible by 4. + -- (Simplified logic: Since YEAR is 0-99, checking last 2 bits = 00 covers mod 4) + IS_LEAP_YEAR <= (YEAR rem 4 = 0); + + -- 3. Max Days in Month Logic + PROCESS(MONTH, IS_LEAP_YEAR) + BEGIN + CASE MONTH IS + WHEN 4 | 6 | 9 | 11 => -- April, June, Sept, Nov + MAX_DAYS_IN_MONTH <= 30; + WHEN 2 => -- February + IF IS_LEAP_YEAR THEN + MAX_DAYS_IN_MONTH <= 29; + ELSE + MAX_DAYS_IN_MONTH <= 28; + END IF; + WHEN OTHERS => -- Jan, Mar, May, Jul, Aug, Oct, Dec + MAX_DAYS_IN_MONTH <= 31; + END CASE; + END PROCESS; + + -- 4. Main Time-Keeping Process + PROCESS(CLK_PIT) + BEGIN + IF rising_edge(CLK_PIT) THEN + IF TICK_1HZ = '1' THEN + -- Increment Seconds + IF SECONDS >= 59 THEN + SECONDS <= 0; + + -- Increment Minutes + IF MINUTES >= 59 THEN + MINUTES <= 0; + + -- Increment Hours + IF HOURS >= 23 THEN + HOURS <= 0; + + -- Increment Weekday (1-7) + IF WEEKDAY >= 7 THEN + WEEKDAY <= 1; + ELSE + WEEKDAY <= WEEKDAY + 1; + END IF; + + -- Increment Day/Month/Year + IF DAY >= MAX_DAYS_IN_MONTH THEN + DAY <= 1; + + -- Increment Month + IF MONTH >= 12 THEN + MONTH <= 1; + + -- Increment Year + IF YEAR >= 99 THEN + YEAR <= 0; + CENTURY <= CENTURY + 1; + ELSE + YEAR <= YEAR + 1; + END IF; + ELSE + MONTH <= MONTH + 1; + END IF; + ELSE + DAY <= DAY + 1; + END IF; -- End Day check + + ELSE + HOURS <= HOURS + 1; + END IF; -- End Hours check + ELSE + MINUTES <= MINUTES + 1; + END IF; -- End Minutes check + ELSE + SECONDS <= SECONDS + 1; + END IF; -- End Seconds check + END IF; -- End Tick check + END IF; + END PROCESS; + +END BEHAVIORAL; diff --git a/chipset/address_decoder.vhd b/chipset/address_decoder.vhd index 873bdce..f07ff0d 100644 --- a/chipset/address_decoder.vhd +++ b/chipset/address_decoder.vhd @@ -1,20 +1,20 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 01:03:23 09/21/2025 --- Design Name: --- Module Name: address_decoder - Behavioral +-- +-- Create Date: 01:03:23 09/21/2025 +-- Design Name: +-- Module Name: address_decoder - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: Address decoder for the M8SBC-486 -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.01 - File Created --- Additional Comments: +-- Additional Comments: -- ---------------------------------------------------------------------------------- LIBRARY IEEE; @@ -29,51 +29,51 @@ ENTITY address_decoder IS ADDR_A1 : IN STD_LOGIC; CPU_MIO : IN STD_LOGIC; -- 0 = IO, 1 = MEM CPU_WR : IN STD_LOGIC; -- 0 = read - + RAM_CACHEABLE : IN STD_LOGIC; ROM_CACHEABLE : IN STD_LOGIC; - + INT_ACK : IN STD_LOGIC; -- Override address decoder while interrupt ack is in progress - - RAM_CS : OUT STD_LOGIC; + + RAM_CS : OUT STD_LOGIC; ROM_CS : OUT STD_LOGIC; -- ROM_CS is connected just to OE. Allow it only at READ PIC_CS : OUT STD_LOGIC; PIT_CS : OUT STD_LOGIC; PS2_CS : OUT STD_LOGIC; - O61_CS : OUT STD_LOGIC; -- Write only 61h output port (latch used) + O61_CS : OUT STD_LOGIC; -- Write only 61h output port (latch used) ISA_CS : OUT STD_LOGIC; - CMOS_CS : OUT STD_LOGIC; - + CMOS_CS : OUT STD_LOGIC; + OUT_KEN : OUT STD_LOGIC; - OUT_BS16 : OUT STD_LOGIC; - OUT_BS8 : OUT STD_LOGIC + OUT_BS16 : OUT STD_LOGIC; + OUT_BS8 : OUT STD_LOGIC ); END address_decoder; ARCHITECTURE Behavioral OF address_decoder IS SIGNAL ADDR_INT : UNSIGNED(23 DOWNTO 0); - + SIGNAL ROM_CS_I : STD_LOGIC; SIGNAL PIC_CS_I : STD_LOGIC; SIGNAL PIT_CS_I : STD_LOGIC; SIGNAL PS2_CS_I : STD_LOGIC; SIGNAL O61_CS_I : STD_LOGIC; SIGNAL ISA_CS_I : STD_LOGIC; - SIGNAL CMOS_CS_I : STD_LOGIC; - - SIGNAL RAM_CACHE : STD_LOGIC; -- negated - SIGNAL ROM_CACHE : STD_LOGIC; -- negated - + SIGNAL CMOS_CS_I : STD_LOGIC; + + SIGNAL RAM_CACHE : STD_LOGIC; -- negated + SIGNAL ROM_CACHE : STD_LOGIC; -- negated + BEGIN ADDR_INT <= UNSIGNED(ADDR_IN & ADDR_A1 & ADDR_A0); - + -- RAM CS: MEM, 0x000000 to 0x09FFFF, 0x100000 to 0x3FFFFF and 0x4A0000 to 0x4FFFFF (wrap to access 384KB memory hole) PROCESS(ADDR_INT, ADDR_31, CPU_MIO, RAM_CACHEABLE) BEGIN RAM_CS <= '1'; -- inactive RAM_CACHE <= '1'; - IF NOT ((ADDR_31 = '1') OR (CPU_MIO = '0')) THEN -- inactive if addr>2GB or IO + IF NOT ((ADDR_31 = '1') OR (CPU_MIO = '0')) THEN -- inactive if addr>2GB or IO -- decode IF (ADDR_INT < x"0A0000") OR (ADDR_INT >= x"100000" AND ADDR_INT < x"400000") OR (ADDR_INT >= x"4A0000" AND ADDR_INT < x"500000") THEN RAM_CS <= '0'; @@ -83,115 +83,112 @@ BEGIN END IF; END IF; END PROCESS; - + -- ROM MEM CS: MEM, 0x0C8000 to 0x100000 and 2GB to the end (224KB in lower area. ROM IS 256KB, lower 32KB is accessible after 2GB) PROCESS(ADDR_INT, ADDR_31, CPU_MIO, ROM_CACHEABLE) BEGIN ROM_CS_I <= '1'; -- inactive ROM_CACHE <= '1'; - IF NOT (CPU_MIO = '0') THEN -- inactive if addr>2GB or IO + IF NOT (CPU_MIO = '0') THEN -- inactive if addr>2GB or IO -- decode IF ADDR_31 = '1' THEN -- If 2GB> ROM_CS_I <= '0'; IF ROM_CACHEABLE = '1' THEN ROM_CACHE <= '0'; END IF; - ELSE + ELSE IF (ADDR_INT >= x"0C8000") AND (ADDR_INT < x"100000") THEN -- If in range 0C8000 to 100000 ROM_CS_I <= '0'; IF ROM_CACHEABLE = '1' THEN ROM_CACHE <= '0'; END IF; END IF; - END IF; + END IF; END IF; END PROCESS; - + ROM_CS <= ROM_CS_I WHEN (CPU_WR = '0') ELSE '1'; -- Allow only at reads - - + -- IO devices mapping -- x86 IO has only 65536 ports, so for less complexity we can just check first 16 bits (or less if range is like x0h to x3h) - + -- PIC: IO, 20h to 21h PROCESS(ADDR_INT, CPU_MIO) BEGIN PIC_CS_I <= '1'; - IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 - IF (ADDR_INT(15 downto 1)) = "000000000010000" THEN + IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 + IF (ADDR_INT(15 DOWNTO 1)) = "000000000010000" THEN PIC_CS_I <= '0'; END IF; END IF; END PROCESS; - + PIC_CS <= PIC_CS_I; - + -- PIT: IO, 40h to 43h PROCESS(ADDR_INT, CPU_MIO) BEGIN PIT_CS_I <= '1'; - IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 - IF (ADDR_INT(15 downto 2)) = "00000000010000" THEN + IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 + IF (ADDR_INT(15 DOWNTO 2)) = "00000000010000" THEN PIT_CS_I <= '0'; END IF; END IF; END PROCESS; - + PIT_CS <= PIT_CS_I; - + -- KB: IO, 60h and 64h PROCESS(ADDR_INT, CPU_MIO) BEGIN PS2_CS_I <= '1'; - IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 - IF (ADDR_INT(15 downto 0)) = "0000000001100000" OR (ADDR_INT(15 downto 0)) = "0000000001100100" THEN + IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 + IF (ADDR_INT(15 DOWNTO 0)) = "0000000001100000" OR (ADDR_INT(15 DOWNTO 0)) = "0000000001100100" THEN PS2_CS_I <= '0'; END IF; END IF; END PROCESS; - + PS2_CS <= PS2_CS_I; - + -- OUTPUT 61h LATCH: IO, 61h PROCESS(ADDR_INT, CPU_MIO) BEGIN O61_CS_I <= '1'; - IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 - IF (ADDR_INT(15 downto 0)) = "0000000001100001" THEN + IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 + IF (ADDR_INT(15 DOWNTO 0)) = "0000000001100001" THEN O61_CS_I <= '0'; END IF; END IF; END PROCESS; - + O61_CS <= O61_CS_I; - + -- CMOS: IO, 70h to 71h PROCESS(ADDR_INT, CPU_MIO) BEGIN CMOS_CS_I <= '1'; - IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 - IF (ADDR_INT(15 downto 1)) = "000000000111000" THEN + IF (CPU_MIO = '0') THEN -- xxXXxxXX76543210 + IF (ADDR_INT(15 DOWNTO 1)) = "000000000111000" THEN CMOS_CS_I <= '0'; END IF; END IF; END PROCESS; - + CMOS_CS <= CMOS_CS_I; - - - + -- Special - IO and MEM both decoding -- ISA CS: MEM, 0x0A0000 to 0x0C8000 (160KB window) and rest of IO PROCESS(ADDR_INT, ADDR_31, CPU_MIO, PIC_CS_I, PIT_CS_I, PS2_CS_I, O61_CS_I, CMOS_CS_I, INT_ACK) BEGIN IF INT_ACK = '1' THEN -- ISA can be active if no interrupt is in progress ISA_CS_I <= '1'; -- inactive - IF NOT ((ADDR_31 = '1') OR (CPU_MIO = '0')) THEN -- inactive if addr>2GB or IO + IF NOT ((ADDR_31 = '1') OR (CPU_MIO = '0')) THEN -- inactive if addr>2GB or IO -- decode IF (ADDR_INT >= x"0A0000") AND (ADDR_INT < x"0C8000") THEN ISA_CS_I <= '0'; END IF; - ELSE + ELSE -- All other IO accesses IF (CPU_MIO = '0') AND (NOT ((PIC_CS_I = '0') OR (PIT_CS_I = '0') OR (PS2_CS_I = '0') OR (O61_CS_I = '0') OR (CMOS_CS_I = '0'))) THEN ISA_CS_I <= '0'; @@ -201,52 +198,50 @@ BEGIN ISA_CS_I <= '1'; END IF; END PROCESS; - + ISA_CS <= ISA_CS_I; - - + -- BS8/16 DECODER PROCESS(CPU_MIO, ROM_CS_I, PIC_CS_I, PIT_CS_I, PS2_CS_I, O61_CS_I, ISA_CS_I, CMOS_CS_I) BEGIN - -- RAM_CS - -- ROM_CS - -- - -- PIC_CS - -- PIT_CS - -- PS2_CS - -- O61_CS - -- ISA_CS - -- CPU_MIO + -- RAM_CS + -- ROM_CS + -- + -- PIC_CS + -- PIT_CS + -- PS2_CS + -- O61_CS + -- ISA_CS + -- CPU_MIO OUT_BS8 <= '1'; OUT_BS16 <= '1'; - + -- RAM is 32 bit, don't use BS8/16 - + -- Assume that code above is safe and never more than 1 device will pull its CS -- 8 bit MEM devices IF ROM_CS_I = '0' THEN OUT_BS8 <= '0'; END IF; - + -- IO devices IF (PIC_CS_I = '0') OR (PIT_CS_I = '0') OR (PS2_CS_I = '0') OR (O61_CS_I = '0') OR (CMOS_CS_I = '0') THEN -- No need to check is CPU_MIO is pointing to IO because all of the signals above check it before OUT_BS8 <= '0'; END IF; - + -- ISA (special). ISA BS might be overwriten by ISA transfer circuity, however keep it as 8-bit as default IF (ISA_CS_I = '0') THEN OUT_BS8 <= '0'; END IF; - + -- Duh, nothing is 16 bit here -- ISA later on will play with 16 bit - + END PROCESS; - + -- Cacheable OUT_KEN <= '0' WHEN ((ROM_CACHE = '0') OR (RAM_CACHE = '0')) ELSE '1'; END Behavioral; - diff --git a/chipset/be_decoder.vhd b/chipset/be_decoder.vhd index 5dbc00c..65a82ce 100644 --- a/chipset/be_decoder.vhd +++ b/chipset/be_decoder.vhd @@ -1,20 +1,20 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 22:02:19 09/20/2025 --- Design Name: --- Module Name: be_decoder - Behavioral +-- +-- Create Date: 22:02:19 09/20/2025 +-- Design Name: +-- Module Name: be_decoder - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: A0 and A1 decoder from the BE0-3 signals -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.01 - File Created --- Additional Comments: +-- Additional Comments: -- ---------------------------------------------------------------------------------- LIBRARY IEEE; @@ -25,14 +25,14 @@ USE IEEE.NUMERIC_STD.ALL; ENTITY be_decoder IS PORT ( - BE0 : in STD_LOGIC; - BE1 : in STD_LOGIC; - BE2 : in STD_LOGIC; - BE3 : in STD_LOGIC; - - A1 : OUT STD_LOGIC; - A0_BLE : OUT STD_LOGIC; - BHE : OUT STD_LOGIC + BE0 : IN STD_LOGIC; + BE1 : IN STD_LOGIC; + BE2 : IN STD_LOGIC; + BE3 : IN STD_LOGIC; + + A1 : OUT STD_LOGIC; + A0_BLE : OUT STD_LOGIC; + BHE : OUT STD_LOGIC ); END be_decoder; @@ -40,10 +40,9 @@ ARCHITECTURE Behavioral OF be_decoder IS BEGIN A1 <= BE0 AND BE1; - + BHE <= BE1 AND BE3; - + A0_BLE <= (BE0 AND BE2) OR (BE0 AND (NOT BE1)); - -END Behavioral; +END Behavioral; diff --git a/chipset/clock_section.vhd b/chipset/clock_section.vhd index 24e8b39..69acf2b 100644 --- a/chipset/clock_section.vhd +++ b/chipset/clock_section.vhd @@ -1,142 +1,135 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 13:21:07 09/22/2025 --- Design Name: --- Module Name: clock_section - Behavioral +-- +-- Create Date: 13:21:07 09/22/2025 +-- Design Name: +-- Module Name: clock_section - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: Main clock divider -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.01 - File Created --- Additional Comments: +-- Additional Comments: -- ---------------------------------------------------------------------------------- - - - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - -library UNISIM; -use UNISIM.vcomponents.all; - -entity clock_section is - generic ( - DIVIDE_BY : integer := 2 -- set to 2 or 3, see CLKDV_DIVIDE below too. Also see m8sbc_main.vhd to update timings & waitstates - ); - port ( - CLK_INPUT : in std_logic; -- 48 MHz input clock (on GCK pin) - CPU_CLK_OUT : out std_logic -- divided clock for CPU & FPGA - ); -end entity; - -architecture Behavioral of clock_section is - - -- Internal signals - signal CLKIN_buf : std_logic; - signal CLK0_raw : std_logic; - signal CLKFB : std_logic; - signal LOCKED_int : std_logic; - - signal CLK_SYS : std_logic; -- 48 MHz internal clock from DLL - signal cpu_clk : std_logic := '0'; - - -- Divider counter - signal cnt : unsigned(1 downto 0) := (others => '0'); -- 2 bits are enough for /2 or /3 - -begin - - ---------------------------------------------------------------- - -- Input buffer for 48 MHz source - ---------------------------------------------------------------- - CLKIN_IBUFG : IBUFG - port map ( - I => CLK_INPUT, - O => CLKIN_buf - ); - - ---------------------------------------------------------------- - -- DLL used only to deskew 48 MHz clock (ignore CLKDV) - ---------------------------------------------------------------- - CLKDLL_inst : CLKDLL - generic map ( - CLKDV_DIVIDE => 4.0, -- used if DIVIDE_BY isn't 2 or 3. For some reason some values make the DLL not lock/wake (including 2 and 3) - DUTY_CYCLE_CORRECTION => TRUE, - STARTUP_WAIT => TRUE - ) - port map ( - CLKIN => CLKIN_buf, - CLKFB => CLKFB, - RST => '0', - CLKDV => open, -- not used - CLK0 => CLK0_raw, -- 0° output for feedback and system clock - CLK90 => open, - CLK180 => open, - CLK270 => open, - CLK2X => open, - LOCKED => LOCKED_int - ); - - ---------------------------------------------------------------- - -- Feedback BUFG for DLL (keeps CLK0 and CLKIN phase-aligned) - ---------------------------------------------------------------- - BUFG_FB : BUFG - port map ( - I => CLK0_raw, - O => CLKFB - ); - - ---------------------------------------------------------------- - -- Global buffer for system clock (48 MHz) - ---------------------------------------------------------------- - BUFG_SYS : BUFG - port map ( - I => CLK0_raw, - O => CLK_SYS - ); - - ---------------------------------------------------------------- - -- Simple synchronous divider on CLK_SYS - ---------------------------------------------------------------- - process (CLK_SYS) - begin - if rising_edge(CLK_SYS) then - if LOCKED_int = '1' then -- only run when DLL is locked - if DIVIDE_BY = 2 then - -- /2: toggle output each cycle - cpu_clk <= not cpu_clk; - elsif DIVIDE_BY = 3 then - -- /3: count 0,1,2 and toggle on terminal count - if cnt = 2 then - cnt <= (others => '0'); - cpu_clk <= not cpu_clk; - else - cnt <= cnt + 1; - end if; - else - -- Fallback: no division, just pass through (optional) - cpu_clk <= CLK_SYS; - end if; - else - -- Optionally hold low until lock - cpu_clk <= '0'; - end if; - end if; - end process; - - CPU_CLK_OUT <= cpu_clk; - -end Behavioral; - - - +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +LIBRARY UNISIM; +USE UNISIM.vcomponents.ALL; + +ENTITY clock_section IS + GENERIC ( + DIVIDE_BY : INTEGER := 2 -- set to 2 or 3, see CLKDV_DIVIDE below too. Also see m8sbc_main.vhd to update timings & waitstates + ); + PORT ( + CLK_INPUT : IN STD_LOGIC; -- 48 MHz input clock (on GCK pin) + CPU_CLK_OUT : OUT STD_LOGIC -- divided clock for CPU & FPGA + ); +END ENTITY; + +ARCHITECTURE Behavioral OF clock_section IS + + -- Internal signals + SIGNAL CLKIN_buf : STD_LOGIC; + SIGNAL CLK0_raw : STD_LOGIC; + SIGNAL CLKFB : STD_LOGIC; + SIGNAL LOCKED_int : STD_LOGIC; + + SIGNAL CLK_SYS : STD_LOGIC; -- 48 MHz internal clock from DLL + SIGNAL cpu_clk : STD_LOGIC := '0'; + + -- Divider counter + SIGNAL cnt : unsigned(1 DOWNTO 0) := (OTHERS => '0'); -- 2 bits are enough for /2 or /3 +BEGIN + + ---------------------------------------------------------------- + -- Input buffer for 48 MHz source + ---------------------------------------------------------------- + CLKIN_IBUFG : IBUFG + PORT MAP ( + I => CLK_INPUT, + O => CLKIN_buf + ); + + ---------------------------------------------------------------- + -- DLL used only to deskew 48 MHz clock (ignore CLKDV) + ---------------------------------------------------------------- + CLKDLL_inst : CLKDLL + GENERIC MAP ( + CLKDV_DIVIDE => 4.0, -- used if DIVIDE_BY isn't 2 or 3. For some reason some values make the DLL not lock/wake (including 2 and 3) + DUTY_CYCLE_CORRECTION => TRUE, + STARTUP_WAIT => TRUE + ) + PORT MAP ( + CLKIN => CLKIN_buf, + CLKFB => CLKFB, + RST => '0', + CLKDV => OPEN, -- not used + CLK0 => CLK0_raw, -- 0° output for feedback and system clock + CLK90 => OPEN, + CLK180 => OPEN, + CLK270 => OPEN, + CLK2X => OPEN, + LOCKED => LOCKED_int + ); + + ---------------------------------------------------------------- + -- Feedback BUFG for DLL (keeps CLK0 and CLKIN phase-aligned) + ---------------------------------------------------------------- + BUFG_FB : BUFG + PORT MAP ( + I => CLK0_raw, + O => CLKFB + ); + + ---------------------------------------------------------------- + -- Global buffer for system clock (48 MHz) + ---------------------------------------------------------------- + BUFG_SYS : BUFG + PORT MAP ( + I => CLK0_raw, + O => CLK_SYS + ); + + ---------------------------------------------------------------- + -- Simple synchronous divider on CLK_SYS + ---------------------------------------------------------------- + PROCESS (CLK_SYS) + BEGIN + IF RISING_EDGE(CLK_SYS) THEN + IF LOCKED_int = '1' THEN -- only run when DLL is locked + IF DIVIDE_BY = 2 THEN + -- /2: toggle output each cycle + cpu_clk <= NOT cpu_clk; + ELSIF DIVIDE_BY = 3 THEN + -- /3: count 0,1,2 and toggle on terminal count + IF cnt = 2 THEN + cnt <= (OTHERS => '0'); + cpu_clk <= NOT cpu_clk; + ELSE + cnt <= cnt + 1; + END IF; + ELSE + -- Fallback: no division, just pass through (optional) + cpu_clk <= CLK_SYS; + END IF; + ELSE + -- Optionally hold low until lock + cpu_clk <= '0'; + END IF; + END IF; + END PROCESS; + + CPU_CLK_OUT <= cpu_clk; + +END Behavioral; ---------------------------------------------------------------------------------- -- @@ -192,7 +185,7 @@ end Behavioral; -- CLKFB => CLKFB, -- feedback from BUFG -- RST => '0', -- no reset -- CLKDV => CLKDV_raw, -- divided clock --- CLK0 => CLK0_raw, -- 0° output for feedback +-- CLK0 => CLK0_raw, -- 0° output for feedback -- CLK90 => open, -- CLK180 => open, -- CLK270 => open, diff --git a/chipset/clock_section_pit.vhd b/chipset/clock_section_pit.vhd index 37b648b..e6f6505 100644 --- a/chipset/clock_section_pit.vhd +++ b/chipset/clock_section_pit.vhd @@ -1,20 +1,20 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 13:21:07 09/22/2025 --- Design Name: --- Module Name: clock_section_pit - Behavioral +-- +-- Create Date: 13:21:07 09/22/2025 +-- Design Name: +-- Module Name: clock_section_pit - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: Clock divider for PIT -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.01 - File Created --- Additional Comments: +-- Additional Comments: -- ---------------------------------------------------------------------------------- LIBRARY IEEE; @@ -22,53 +22,50 @@ USE IEEE.STD_LOGIC_1164.ALL; LIBRARY UNISIM; USE UNISIM.VCOMPONENTS.ALL; - ENTITY clock_section_pit IS PORT ( CLK_INPUT : IN STD_LOGIc; -- 14.318 MHz in - CLK_OUT : OUT STD_LOGIC -- 1.193 MHz out + CLK_OUT : OUT STD_LOGIC -- 1.193 MHz out ); END clock_section_pit; ARCHITECTURE Behavioral OF clock_section_pit IS SIGNAL CLKDV_raw : STD_LOGIC; - SIGNAL CLK0_raw : STD_LOGIC; - SIGNAL CLKFB : STD_LOGIC; + SIGNAL CLK0_raw : STD_LOGIC; + SIGNAL CLKFB : STD_LOGIC; SIGNAL LOCKED_int : STD_LOGIC; BEGIN - CLKDLL_inst : CLKDLL - generic map ( - CLKDV_DIVIDE => 12.0, -- "invalid" but works?! + CLKDLL_inst : CLKDLL + GENERIC MAP ( + CLKDV_DIVIDE => 12.0, -- "invalid" but works?! -- We can divide by: 1.5,2.0,2.5,3.0,4.0,5.0,8.0 or 16.0 - DUTY_CYCLE_CORRECTION => TRUE, - STARTUP_WAIT => TRUE - ) - port map ( - CLKIN => CLK_INPUT, -- from input buffer (AT MAIN) - CLKFB => CLKFB, -- feedback from BUFG - RST => '0', -- no reset - CLKDV => CLKDV_raw, -- divided clock - CLK0 => CLK0_raw, -- 0° output for feedback - CLK90 => open, - CLK180 => open, - CLK270 => open, - CLK2X => open, - LOCKED => LOCKED_int - ); - + DUTY_CYCLE_CORRECTION => TRUE, + STARTUP_WAIT => TRUE + ) + PORT MAP ( + CLKIN => CLK_INPUT, -- from input buffer (AT MAIN) + CLKFB => CLKFB, -- feedback from BUFG + RST => '0', -- no reset + CLKDV => CLKDV_raw, -- divided clock + CLK0 => CLK0_raw, -- 0° output for feedback + CLK90 => OPEN, + CLK180 => OPEN, + CLK270 => OPEN, + CLK2X => OPEN, + LOCKED => LOCKED_int + ); - BUFG_FB : BUFG - port map ( - I => CLK0_raw, - O => CLKFB - ); + BUFG_FB : BUFG + PORT MAP ( + I => CLK0_raw, + O => CLKFB + ); - BUFG_CLKDV : BUFG - port map ( - I => CLKDV_raw, - O => CLK_OUT - ); + BUFG_CLKDV : BUFG + PORT MAP ( + I => CLKDV_raw, + O => CLK_OUT + ); END Behavioral; - diff --git a/chipset/isa_driver.vhd b/chipset/isa_driver.vhd index f320023..acb50cb 100644 --- a/chipset/isa_driver.vhd +++ b/chipset/isa_driver.vhd @@ -1,18 +1,18 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 23:21:17 10/14/2025 --- Design Name: --- Module Name: isa_driver - Behavioral +-- +-- Create Date: 23:21:17 10/14/2025 +-- Design Name: +-- Module Name: isa_driver - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: 8 and 16-bit ISA driver -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.02 - Rewrite to sync -- Revision 0.01 - File Created -- Additional Comments: ISA specs for 0.02 rewrite based on EISA System Architecture Second Edition by MINDSHARE, INC. TOM SHANLEY DON ANDERSON (1995) @@ -25,50 +25,48 @@ USE IEEE.NUMERIC_STD.ALL; ENTITY isa_driver IS PORT ( CLK : IN STD_LOGIC; - RESET : IN STD_LOGIC; + RESET : IN STD_LOGIC; ADS : IN STD_LOGIC; - RW : IN STD_LOGIC; + RW : IN STD_LOGIC; MIO : IN STD_LOGIC; - EN_ISA : IN STD_LOGIC; -- negated - - ISA_CLK_HIGH_CYCLES : IN INTEGER RANGE 1 TO 15; - ISA_CLK_LOW_CYCLES : IN INTEGER RANGE 1 TO 15; + EN_ISA : IN STD_LOGIC; -- negated + + ISA_CLK_HIGH_CYCLES : IN INTEGER RANGE 1 TO 15; + ISA_CLK_LOW_CYCLES : IN INTEGER RANGE 1 TO 15; WAITSTATE_16C : IN INTEGER RANGE 0 TO 15; -- From ADS to check 16B signals - WAITSTATE_END : IN INTEGER RANGE 0 TO 127; -- From check to end of transfer - + WAITSTATE_END : IN INTEGER RANGE 0 TO 127; -- From check to end of transfer + ISA_MEMCS16 : IN STD_LOGIC; ISA_IOCS16 : IN STD_LOGIC; ISA_IO_READY : IN STD_LOGIC; -- Input from ISA - + ISA_RDY : OUT STD_LOGIC; -- Output from driver ISA_MEM_WR : OUT STD_LOGIC; ISA_MEM_RD : OUT STD_LOGIC; ISA_IO_WR : OUT STD_LOGIC; ISA_IO_RD : OUT STD_LOGIC; - ISA_CLK : OUT STD_LOGIC; - - BS8_O : OUT STD_LOGIC; + ISA_CLK : OUT STD_LOGIC; + + BS8_O : OUT STD_LOGIC; BS16_O : OUT STD_LOGIC; - + CPU_16BTR : IN STD_LOGIC; -- Do not do 16-bit transfer if CPU does 8-bit one! - ISA_SBHE : OUT STD_LOGIC + ISA_SBHE : OUT STD_LOGIC ); END ISA_DRIVER; ARCHITECTURE behavioral OF isa_driver IS + TYPE drv_state_type IS (st1_wait_for_ads, st2_ts_wait_for_rise, st3_ts_wait_for_fall, st4_tc1_wait_for_rise, st5_tc1_wait_for_fall, st6_waitstates_wait); + SIGNAL drv_state, drv_next_state : drv_state_type; - TYPE drv_state_type IS (st1_wait_for_ads, st2_ts_wait_for_rise, st3_ts_wait_for_fall, st4_tc1_wait_for_rise, st5_tc1_wait_for_fall, st6_waitstates_wait ); - SIGNAL drv_state, drv_next_state : drv_state_type; - SIGNAL DIV_COUNT : INTEGER RANGE 0 TO 15 := 0; SIGNAL ISA_CLK_STATE : STD_LOGIC := '0'; - + SIGNAL RDY_I : STD_LOGIC; SIGNAL ISA_DO_16B : STD_LOGIC := '0'; - - SIGNAL WS_COUNT : INTEGER RANGE 0 TO 127 := 0; -BEGIN + SIGNAL WS_COUNT : INTEGER RANGE 0 TO 127 := 0; +BEGIN -- Standard 8-bit ISA cycle consists of 1 starting cycle + 4 ws cycles -- To sync clocks, we take CPU clock and divide it by x amount @@ -78,13 +76,12 @@ BEGIN PROCESS (CLK) BEGIN IF RISING_EDGE(CLK) THEN - IF ISA_CLK_STATE = '1' THEN -- Counting the HIGH duration IF DIV_COUNT >= (ISA_CLK_HIGH_CYCLES - 1) THEN ISA_CLK_STATE <= '0'; -- Toggle to Low DIV_COUNT <= 0; - ELSE + ELSE DIV_COUNT <= DIV_COUNT + 1; END IF; ELSE @@ -92,34 +89,31 @@ BEGIN IF DIV_COUNT >= (ISA_CLK_LOW_CYCLES - 1) THEN ISA_CLK_STATE <= '1'; -- Toggle to High DIV_COUNT <= 0; - ELSE + ELSE DIV_COUNT <= DIV_COUNT + 1; END IF; END IF; - END IF; END PROCESS; - - ISA_CLK <= ISA_CLK_STATE; + ISA_CLK <= ISA_CLK_STATE; SYNC_PROC: PROCESS (CLK) -- clk synced - BEGIN - IF RISING_EDGE(CLK) THEN - IF (RESET = '1') THEN + BEGIN + IF RISING_EDGE(CLK) THEN + IF RESET = '1' THEN WS_COUNT <= 0; ISA_DO_16B <= '0'; - ELSE - + ELSE + IF drv_state = st1_wait_for_ads THEN WS_COUNT <= 0; -- reset ISA_DO_16B <= '0'; END IF; - + IF drv_state = st2_ts_wait_for_rise THEN - END IF; - + IF drv_state = st4_tc1_wait_for_rise AND drv_next_state = st5_tc1_wait_for_fall THEN -- check CS16 signals IF MIO = '1' THEN -- MEM @@ -132,73 +126,69 @@ BEGIN END IF; END IF; END IF; - - if drv_state = st6_waitstates_wait THEN -- We need to count 5 rising edges before ending transaction + + IF drv_state = st6_waitstates_wait THEN -- We need to count 5 rising edges before ending transaction IF ISA_CLK_STATE = '0' AND DIV_COUNT >= (ISA_CLK_LOW_CYCLES - 1) THEN -- rise IF WS_COUNT < 5 THEN WS_COUNT <= WS_COUNT + 1; END IF; END IF; END IF; - - - + drv_state <= drv_next_state; - - + IF drv_state /= st1_wait_for_ads THEN - END IF; - - END IF; - END IF; - END PROCESS; - + + END IF; + END IF; + END PROCESS; + OUTPUT_DECODE: PROCESS (drv_state, drv_next_state, RW, MIO, WS_COUNT, ISA_DO_16B) -- out | RW: 0 - read, 1 - write - VARIABLE RD : STD_LOGIC; - VARIABLE WR : STD_LOGIC; - VARIABLE allow_drive : STD_LOGIC; - BEGIN - --insert statements to decode internal output signals + VARIABLE RD : STD_LOGIC; + VARIABLE WR : STD_LOGIC; + VARIABLE allow_drive : STD_LOGIC; + BEGIN + --insert statements to decode internal output signals -- "BS16 / BS8 must be driven active before the first RDY or BRDY is driven active" -- so we should be able to indicate 8/16 bit transfer even after ADS - + BS8_O <= '1'; BS16_O <= '1'; ISA_MEM_WR <= '1'; ISA_MEM_RD <= '1'; ISA_IO_WR <= '1'; ISA_IO_RD <= '1'; - + RDY_I <= '0'; -- ready - + IF drv_state /= st1_wait_for_ads THEN -- Hold CPU if we are in transfer RDY_I <= '1'; END IF; - - IF drv_state = st4_tc1_wait_for_rise THEN + + IF drv_state = st4_tc1_wait_for_rise THEN -- We should active BALE (pulse high) here but we dont have BALE! END IF; - + IF drv_state = st5_tc1_wait_for_fall OR drv_state = st6_waitstates_wait THEN IF ISA_DO_16B = '1' THEN - BS16_O <= '0'; - ELSE - BS8_O <= '0'; + BS16_O <= '0'; + ELSE + BS8_O <= '0'; END IF; END IF; - + IF drv_state = st6_waitstates_wait OR (drv_state = st5_tc1_wait_for_fall AND ISA_DO_16B = '1') THEN -- If device is 16-bit capable, assert control lines instantly -- Activate RW signals WR := '1'; RD := '1'; - + IF RW = '1' THEN -- write WR := '0'; ELSE -- read - RD := '0'; + RD := '0'; END IF; - + IF MIO = '1' THEN -- MEM ISA_MEM_WR <= WR; ISA_MEM_RD <= RD; @@ -206,43 +196,43 @@ BEGIN ISA_IO_WR <= WR; ISA_IO_RD <= RD; END IF; - + END IF; - - END PROCESS; - - NEXT_STATE_DECODE: PROCESS(drv_state, ADS, EN_ISA, WS_COUNT, ISA_CLK_STATE, DIV_COUNT) -- in - BEGIN - --declare default state for next_state to avoid latches - drv_next_state <= drv_state; -- default is to stay in current state - - CASE (drv_state) IS + + END PROCESS; + + NEXT_STATE_DECODE: PROCESS(drv_state, ADS, EN_ISA, WS_COUNT, ISA_CLK_STATE, ISA_CLK_LOW_CYCLES, ISA_IO_READY, ISA_DO_16B, DIV_COUNT) -- in + BEGIN + --declare default state for next_state to avoid latches + drv_next_state <= drv_state; -- default is to stay in current state + + CASE (drv_state) IS -- st1 - WHEN st1_wait_for_ads => -- Transfer begin, When ADS is 0 and EN_ISA and 0 we activate - IF (ADS = '0') AND (EN_ISA = '0') THEN - drv_next_state <= st2_ts_wait_for_rise; - END IF; - + WHEN st1_wait_for_ads => -- Transfer begin, When ADS is 0 and EN_ISA and 0 we activate + IF (ADS = '0') AND (EN_ISA = '0') THEN + drv_next_state <= st2_ts_wait_for_rise; + END IF; + -- st2 - WHEN st2_ts_wait_for_rise => -- Wait for sync to ISA clock - rising edge + WHEN st2_ts_wait_for_rise => -- Wait for sync to ISA clock - rising edge IF EN_ISA = '1' THEN drv_next_state <= st1_wait_for_ads; -- ISA CS for some reason deasserted - ELSE + ELSE IF ISA_CLK_STATE = '0' AND DIV_COUNT >= (ISA_CLK_LOW_CYCLES - 1) THEN -- rise drv_next_state <= st3_ts_wait_for_fall; END IF; END IF; - + -- st3 WHEN st3_ts_wait_for_fall => IF EN_ISA = '1' THEN - drv_next_state <= st1_wait_for_ads; - ELSE + drv_next_state <= st1_wait_for_ads; + ELSE IF ISA_CLK_STATE = '0' AND DIV_COUNT >= (ISA_CLK_LOW_CYCLES - 1) THEN -- fall drv_next_state <= st4_tc1_wait_for_rise; END IF; END IF; - + -- st4 WHEN st4_tc1_wait_for_rise => IF EN_ISA = '1' THEN @@ -252,7 +242,7 @@ BEGIN drv_next_state <= st5_tc1_wait_for_fall; END IF; END IF; - + -- st5 WHEN st5_tc1_wait_for_fall => IF EN_ISA = '1' THEN @@ -262,7 +252,7 @@ BEGIN drv_next_state <= st6_waitstates_wait; END IF; END IF; - + -- st6 WHEN st6_waitstates_wait => IF EN_ISA = '1' THEN @@ -278,21 +268,16 @@ BEGIN END IF; END IF; END IF; - - - - WHEN OTHERS => - drv_next_state <= st1_wait_for_ads; - END CASE; - END PROCESS; - + + WHEN OTHERS => + drv_next_state <= st1_wait_for_ads; + END CASE; + END PROCESS; + -- ISA_RDY - output from driver -- ISA_IO_READY - input from ISA -- RDY: 1 = wait, 0 = ready - ISA_RDY <= RDY_I; + ISA_RDY <= RDY_I; ISA_SBHE <= CPU_16BTR; - - END BEHAVIORAL; - diff --git a/chipset/keyboard_controller.vhd b/chipset/keyboard_controller.vhd index 8e010ce..ec4629e 100644 --- a/chipset/keyboard_controller.vhd +++ b/chipset/keyboard_controller.vhd @@ -1,38 +1,37 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 13:50:01 09/22/2025 --- Design Name: --- Module Name: keyboard_controller - Behavioral +-- +-- Create Date: 13:50:01 09/22/2025 +-- Design Name: +-- Module Name: keyboard_controller - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: PC style keyboard controller implementation -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.01 - File Created --- Additional Comments: +-- Additional Comments: -- ---------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; - ENTITY keyboard_controller IS PORT ( CLK : IN STD_LOGIC; -- for timeout PS2_CLK : IN STD_LOGIC; - PS2_DATA : IN STD_LOGIC; - RESET : IN STD_LOGIC; - - D_OUT : OUT STD_LOGIC_VECTOR(7 downto 0); -- data port 0x64 - DS_OUT : OUT STD_LOGIC_VECTOR(7 downto 0); -- status port 0x64 + PS2_DATA : IN STD_LOGIC; + RESET : IN STD_LOGIC; + + D_OUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- data port 0x60 + DS_OUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- status port 0x64 CLK_CPU : IN STD_LOGIC; -- to clear flag - RD_CLEAR : IN STD_LOGIC; -- to clear flag + RD_CLEAR : IN STD_LOGIC; -- to clear flag CLEAR_BUF : IN STD_LOGIC; INT_OUT : OUT STD_LOGIC ); @@ -40,9 +39,9 @@ END keyboard_controller; ARCHITECTURE Behavioral OF keyboard_controller IS - TYPE rom_type IS ARRAY (0 to 255) OF STD_LOGIC_VECTOR(7 downto 0); - - constant SET2_TO_SET1 : rom_type := ( -- NON EXT + TYPE rom_type IS ARRAY (0 TO 255) OF STD_LOGIC_VECTOR(7 DOWNTO 0); + + CONSTANT SET2_TO_SET1 : rom_type := ( -- NON EXT 16#1C# => X"1E", -- A 16#32# => X"30", -- B 16#21# => X"2E", -- C @@ -78,7 +77,6 @@ ARCHITECTURE Behavioral OF keyboard_controller IS 16#36# => X"07", -- 6 16#3D# => X"08", -- 7 16#3E# => X"09", -- 8 - 16#46# => X"0A", -- 9 16#0E# => X"29", -- ` 16#4E# => X"0C", -- - @@ -107,7 +105,6 @@ ARCHITECTURE Behavioral OF keyboard_controller IS 16#78# => X"57", -- F11 16#07# => X"58", -- F12 16#7E# => X"46", -- SCROLL - 16#54# => X"1A", -- [ 16#77# => X"45", -- NUM 16#7C# => X"37", -- KP * @@ -131,10 +128,10 @@ ARCHITECTURE Behavioral OF keyboard_controller IS 16#49# => X"34", -- . 16#4A# => X"35", -- / - others => X"00" -- Default/Error + OTHERS => X"00" -- Default/Error ); - - constant SET2_TO_SET1_EXT : rom_type := ( -- 0xE0 ext codes + + CONSTANT SET2_TO_SET1_EXT : rom_type := ( -- 0xE0 ext codes 16#1F# => X"5B", -- L WIN 16#14# => X"1D", -- R CTRL 16#27# => X"5C", -- R WIN @@ -152,35 +149,34 @@ ARCHITECTURE Behavioral OF keyboard_controller IS 16#74# => X"4D", -- R ARROW 16#4A# => X"35", -- KP / 16#5A# => X"1C", -- KP EN - - others => X"00" -- Default/Error + + OTHERS => X"00" -- Default/Error ); - CONSTANT int_pulse_dur : INTEGER := 7; -- 7 * 838 = about 5866 ns CONSTANT timeout_limit : INTEGER := 100000; -- 200 for tests, 100000 for final (100000 is about 83 ms) - TYPE kb_state_type IS (st1_wait, st2_fetch); - SIGNAL kb_state, kb_next_state : kb_state_type := st1_wait; - - SIGNAL timeout : INTEGER RANGE 0 to timeout_limit := 0; + TYPE kb_state_type IS (st1_wait, st2_fetch); + SIGNAL kb_state, kb_next_state : kb_state_type := st1_wait; + + SIGNAL timeout : INTEGER RANGE 0 TO timeout_limit := 0; SIGNAL REC_TIMEOUT : STD_LOGIC := '0'; - - SIGNAL kb_data : STD_LOGIC_VECTOR(7 downto 0); - SIGNAL kb_bit : INTEGER RANGE 0 to 9 := 0; - SIGNAL kb_data_read : STD_LOGIC_VECTOR(7 downto 0); - SIGNAL kb_parity : STD_LOGIC := '0'; - - SIGNAL pulse_int : STD_LOGIC := '0'; - SIGNAL int_hold : INTEGER RANGE 0 to int_pulse_dur := int_pulse_dur; - - SIGNAL dflag : STD_LOGIC := '0'; - SIGNAL last_RD_CLEAR : STD_LOGIC := '0'; - + + SIGNAL kb_data : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL kb_bit : INTEGER RANGE 0 TO 9 := 0; + SIGNAL kb_data_read : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL kb_parity : STD_LOGIC := '0'; + + SIGNAL pulse_int : STD_LOGIC := '0'; + SIGNAL int_hold : INTEGER RANGE 0 TO int_pulse_dur := int_pulse_dur; + + SIGNAL dflag : STD_LOGIC := '0'; + SIGNAL last_RD_CLEAR : STD_LOGIC := '0'; + SIGNAL scancode_ext : STD_LOGIC := '0'; SIGNAL scancode_release : STD_LOGIC := '0'; BEGIN - + PROCESS (CLK, RESET, REC_TIMEOUT, pulse_int, kb_bit) BEGIN IF FALLING_EDGE(CLK) THEN @@ -189,41 +185,41 @@ BEGIN timeout <= 0; REC_TIMEOUT <= '0'; int_hold <= 0; - ELSE + ELSE IF kb_state = st1_wait THEN timeout <= 0; ELSE IF timeout >= timeout_limit THEN REC_TIMEOUT <= '1'; - ELSE + ELSE timeout <= timeout + 1; END IF; END IF; - + IF REC_TIMEOUT = '1' AND kb_bit = 0 THEN -- reset was ACK kb_state <= st1_wait; REC_TIMEOUT <= '0'; - ELSE + ELSE kb_state <= kb_next_state; END IF; - + -- interrupt IF pulse_int = '1' THEN -- solution to hold pulse for few clock cycles IF int_hold < int_pulse_dur THEN int_hold <= int_hold + 1; END IF; - ELSE + ELSE int_hold <= 0; END IF; - + END IF; - + END IF; END PROCESS; - + PROCESS (PS2_CLK, PS2_DATA, RESET, REC_TIMEOUT, CLEAR_BUF) - VARIABLE data_parity : STD_LOGIC; - VARIABLE result_scancode : STD_LOGIC_VECTOR(7 downto 0); + VARIABLE data_parity : STD_LOGIC; + VARIABLE result_scancode : STD_LOGIC_VECTOR(7 DOWNTO 0); BEGIN IF RESET = '1' OR REC_TIMEOUT = '1' THEN kb_data <= X"00"; @@ -234,41 +230,41 @@ BEGIN kb_next_state <= st1_wait; kb_parity <= '0'; pulse_int <= '0'; - + scancode_ext <= '0'; scancode_release <= '0'; - ELSE + ELSE -- IF clear_int >= int_pulse_dur THEN -- pulse_int <= '0'; -- END IF; IF CLEAR_BUF = '1' THEN kb_data_read <= X"00"; - ELSE + ELSE IF FALLING_EDGE(PS2_CLK) THEN - + IF kb_state = st1_wait AND PS2_DATA = '0' THEN -- start bit kb_next_state <= st2_fetch; -- CLK (~1 MHz) is way faster than PS2_CLK (16 KHz max), so state should change in time pulse_int <= '0'; kb_bit <= 0; kb_data <= X"00"; END IF; - + IF kb_state = st2_fetch THEN IF kb_bit = 9 THEN -- stop bit kb_next_state <= st1_wait; - data_parity := NOT (kb_data(7) xor kb_data(6) xor kb_data(5) xor kb_data(4) xor kb_data(3) xor kb_data(2) xor kb_data(1) xor kb_data(0)); + data_parity := NOT (kb_data(7) XOR kb_data(6) XOR kb_data(5) XOR kb_data(4) XOR kb_data(3) XOR kb_data(2) XOR kb_data(1) XOR kb_data(0)); IF kb_parity = data_parity THEN -- proper data received - + -- Translation from scan code 2 to 1 -- kb data order: [E0] [F0] DATA -- E0 - extended, F0 - release, DATA - data IF kb_data = X"E0" THEN scancode_ext <= '1'; - + kb_data_read <= kb_data; -- Extended scan codes apply to the same keys in sets 1 and 2 so send E0 pulse_int <= '1'; - + ELSIF kb_data = X"F0" THEN scancode_release <= '1'; ELSE @@ -283,44 +279,44 @@ BEGIN IF scancode_release = '1' THEN -- key release result_scancode(7) := '1'; -- OR 0x80 END IF; - + kb_data_read <= result_scancode; pulse_int <= '1'; - + scancode_ext <= '0'; scancode_release <= '0'; END IF; - - + + -- generate interrupt -- old --kb_data_read <= kb_data; --pulse_int <= '1'; - ELSE + ELSE kb_data_read <= X"00"; END IF; - ELSE + ELSE IF kb_bit = 8 THEN -- parity bit kb_parity <= PS2_DATA; - ELSE - kb_data <= PS2_DATA & kb_data(7 downto 1); -- data bit + ELSE + kb_data <= PS2_DATA & kb_data(7 DOWNTO 1); -- data bit END IF; END IF; kb_bit <= kb_bit + 1; END IF; - + END IF; -- if falling - + END IF; -- if not clear_buf - + END IF; -- if not reset END PROCESS; - + PROCESS (CLK_CPU, int_hold, RESET) BEGIN IF RESET = '1' THEN dflag <= '0'; last_RD_CLEAR <= '1'; - ELSE + ELSE IF int_hold = 1 THEN dflag <= '1'; ELSE @@ -328,16 +324,15 @@ BEGIN IF last_RD_CLEAR = '0' AND RD_CLEAR = '1' THEN -- RISING edge dflag <= '0'; END IF; - + last_RD_CLEAR <= RD_CLEAR; END IF; END IF; END IF; END PROCESS; - + D_OUT <= kb_data_read; DS_OUT <= "0001010" & dflag; INT_OUT <= '1' WHEN (int_hold < int_pulse_dur AND int_hold > 0) ELSE '0'; END Behavioral; - diff --git a/chipset/m8sbc_main.vhd b/chipset/m8sbc_main.vhd index 855b73b..27f66ce 100644 --- a/chipset/m8sbc_main.vhd +++ b/chipset/m8sbc_main.vhd @@ -1,21 +1,21 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 22:47:54 09/17/2025 --- Design Name: --- Module Name: m8sbc_main - Behavioral +-- +-- Create Date: 22:47:54 09/17/2025 +-- Design Name: +-- Module Name: m8sbc_main - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: Main file connecting everything together -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.02 - isa_driver rewrite -- Revision 0.01 - File Created --- Additional Comments: +-- Additional Comments: -- ---------------------------------------------------------------------------------- LIBRARY IEEE; @@ -33,15 +33,15 @@ ENTITY m8sbc_main IS CLK_OUT_CPU : OUT STD_LOGIC; CLK_OUT_ISA : OUT STD_LOGIC; CLK_OUT_PIT : OUT STD_LOGIC; - + -- CPU Input pins - CPU_IN_ADDR : IN STD_LOGIC_VECTOR(23 downto 2); + CPU_IN_ADDR : IN STD_LOGIC_VECTOR(23 DOWNTO 2); CPU_IN_ADDR_31 : IN STD_LOGIC; CPU_IN_WR : IN STD_LOGIC; -- 0 = read, 1 = write - CPU_IN_ADS : IN STD_LOGIC; + CPU_IN_ADS : IN STD_LOGIC; CPU_IN_MIO : IN STD_LOGIC; -- 0 = IO, 1 = MEM CPU_IN_DC : IN STD_LOGIC; - CPU_IN_BE : IN STD_LOGIC_VECTOR( 3 downto 0); + CPU_IN_BE : IN STD_LOGIC_VECTOR( 3 DOWNTO 0); -- CPU Output pins CPU_OUT_RDY : OUT STD_LOGIC; CPU_OUT_BS8 : OUT STD_LOGIC; @@ -49,177 +49,171 @@ ENTITY m8sbc_main IS CPU_OUT_KEN : OUT STD_LOGIC; CPU_OUT_NMI : OUT STD_LOGIC; -- CPU InOut pins - CPU_DATA : INOUT STD_LOGIC_VECTOR( 7 downto 0); - + CPU_DATA : INOUT STD_LOGIC_VECTOR( 7 DOWNTO 0); + -- Generated address lines ADDR_A0 : OUT STD_LOGIC; ADDR_A1 : OUT STD_LOGIC; - + -- Reset RESET_SYS_IN : IN STD_LOGIC; RESET_REQ_OUT : OUT STD_LOGIC; - + -- Config pins RAM_CACHE_EN : IN STD_LOGIC; ROM_CACHE_EN : IN STD_LOGIC; - + -- RAM control lines RAM_CS0 : OUT STD_LOGIC; RAM_CS1 : OUT STD_LOGIC; - RAM_WE_B : OUT STD_LOGIC_VECTOR( 3 downto 0); - RAM_OE_B : OUT STD_LOGIC_VECTOR( 3 downto 0); - + RAM_WE_B : OUT STD_LOGIC_VECTOR( 3 DOWNTO 0); + RAM_OE_B : OUT STD_LOGIC_VECTOR( 3 DOWNTO 0); + -- ROM ROM_CS : OUT STD_LOGIC; - + -- Bus width transcievers control pins - TR_8B : OUT STD_LOGIC_VECTOR( 3 downto 0); - TR_16B_LOW : OUT STD_LOGIC; + TR_8B : OUT STD_LOGIC_VECTOR( 3 DOWNTO 0); + TR_16B_LOW : OUT STD_LOGIC; TR_16B_HIGH : OUT STD_LOGIC; - + -- Generic control lines MEM_WR : OUT STD_LOGIC; - MEM_RD : OUT STD_LOGIC; - IO_WR : OUT STD_LOGIC; - IO_RD : OUT STD_LOGIC; - + MEM_RD : OUT STD_LOGIC; + IO_WR : OUT STD_LOGIC; + IO_RD : OUT STD_LOGIC; + -- ISA bus ISA_MEM_WR : OUT STD_LOGIC; ISA_MEM_RD : OUT STD_LOGIC; - ISA_SBHE : OUT STD_LOGIC; + ISA_SBHE : OUT STD_LOGIC; ISA_MEMCS16 : IN STD_LOGIC; ISA_IOCS16 : IN STD_LOGIC; ISA_IO_READY : IN STD_LOGIC; - + -- PIC (interrupt controller, IO 0x20-0x21) PIC_CS : OUT STD_LOGIC; - PIC_INTA : OUT STD_LOGIC; - + PIC_INTA : OUT STD_LOGIC; + -- PIT (timer, IO 0x40-0x43) PIT_CS : OUT STD_LOGIC; PIT_LATCH_LE : OUT STD_LOGIC; - + -- Keyboard controller (IO 0x60) PS2_CLK : IN STD_LOGIC; - PS2_DATA : IN STD_LOGIC; + PS2_DATA : IN STD_LOGIC; PS2_INTERUPT : OUT STD_LOGIC; - + -- CMOS NVRAM AVR interface - AVR_CLK : IN STD_LOGIC; - AVR_IO : INOUT STD_LOGIC + AVR_CLK : IN STD_LOGIC; + AVR_IO : INOUT STD_LOGIC ); END m8sbc_main; - - ARCHITECTURE Behavioral OF m8sbc_main IS -- CONSTANTS -- Update Divider in CLKGEN! - - CONSTANT FPGA_VER : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"48860002"; -- first 2 bytes - chipset ident, last 2 bytes - version - - + + CONSTANT FPGA_VER : STD_LOGIC_VECTOR(31 DOWNTO 0) := x"48860002"; -- first 2 bytes - chipset ident, last 2 bytes - version + CONSTANT REVERSE_CLOCK : STD_LOGIC := '0'; -- Use 1 for 12 MHz, for 16> use 0 - + -- -- DIV = 4.0 - 12 MHz -- CONSTANT RAM_WAITSTATES : INTEGER RANGE 0 TO 127 := 0; -- CONSTANT RAM_BURST_WAITSTATES : INTEGER RANGE 0 TO 15 := 0; -- Read bursts -- CONSTANT ROM_WAITSTATES : INTEGER RANGE 0 TO 127 := 1; --- --- CONSTANT ONBOARD_IO_WAITSTATES : INTEGER RANGE 0 TO 127 := 12; --- CONSTANT PIC_INT_ACK_WAITSTATES : INTEGER RANGE 0 TO 127 := 12; --- --- CONSTANT ISA_CLK_LOW_CYCLES : INTEGER RANGE 1 TO 15 := 1; -- 6 MHz --- CONSTANT ISA_CLK_HIGH_CYCLES : INTEGER RANGE 1 TO 15 := 1; -- - +-- CONSTANT ONBOARD_IO_WAITSTATES : INTEGER RANGE 0 TO 127 := 12; +-- CONSTANT PIC_INT_ACK_WAITSTATES : INTEGER RANGE 0 TO 127 := 12; +-- +-- CONSTANT ISA_CLK_LOW_CYCLES : INTEGER RANGE 1 TO 15 := 1; -- 6 MHz +-- CONSTANT ISA_CLK_HIGH_CYCLES : INTEGER RANGE 1 TO 15 := 1; +-- -- DIV = 2.5 - 19.2 MHz -- CONSTANT RAM_WAITSTATES : INTEGER RANGE 0 TO 127 := 1; -- CONSTANT RAM_BURST_WAITSTATES : INTEGER RANGE 0 TO 15 := 0; -- CONSTANT ROM_WAITSTATES : INTEGER RANGE 0 TO 127 := 1; --- --- CONSTANT ONBOARD_IO_WAITSTATES : INTEGER RANGE 0 TO 127 := 19; --- CONSTANT PIC_INT_ACK_WAITSTATES : INTEGER RANGE 0 TO 127 := 19; --- --- CONSTANT ISA_CLK_LOW_CYCLES : INTEGER RANGE 1 TO 15 := 2; -- 6.4 MHz --- CONSTANT ISA_CLK_HIGH_CYCLES : INTEGER RANGE 1 TO 15 := 1; - +-- +-- CONSTANT ONBOARD_IO_WAITSTATES : INTEGER RANGE 0 TO 127 := 19; +-- CONSTANT PIC_INT_ACK_WAITSTATES : INTEGER RANGE 0 TO 127 := 19; +-- +-- CONSTANT ISA_CLK_LOW_CYCLES : INTEGER RANGE 1 TO 15 := 2; -- 6.4 MHz +-- CONSTANT ISA_CLK_HIGH_CYCLES : INTEGER RANGE 1 TO 15 := 1; -- DIV = 2.0 - 24 MHz CONSTANT RAM_WAITSTATES : INTEGER RANGE 0 TO 127 := 1; CONSTANT RAM_BURST_WAITSTATES : INTEGER RANGE 0 TO 15 := 0; CONSTANT ROM_WAITSTATES : INTEGER RANGE 0 TO 127 := 2; - - CONSTANT ONBOARD_IO_WAITSTATES : INTEGER RANGE 0 TO 127 := 23; - CONSTANT PIC_INT_ACK_WAITSTATES : INTEGER RANGE 0 TO 127 := 23; - - CONSTANT ISA_CLK_LOW_CYCLES : INTEGER RANGE 1 TO 15 := 2; -- 8 MHz - CONSTANT ISA_CLK_HIGH_CYCLES : INTEGER RANGE 1 TO 15 := 1; + CONSTANT ONBOARD_IO_WAITSTATES : INTEGER RANGE 0 TO 127 := 23; + CONSTANT PIC_INT_ACK_WAITSTATES : INTEGER RANGE 0 TO 127 := 23; + + CONSTANT ISA_CLK_LOW_CYCLES : INTEGER RANGE 1 TO 15 := 2; -- 8 MHz + CONSTANT ISA_CLK_HIGH_CYCLES : INTEGER RANGE 1 TO 15 := 1; -- COMPONENTS COMPONENT clock_section IS PORT ( - CLK_INPUT : IN std_logic; -- 48 MHz - CPU_CLK_OUT : OUT std_logic + CLK_INPUT : IN STD_LOGIC; -- 48 MHz + CPU_CLK_OUT : OUT STD_LOGIC ); END COMPONENT; - + COMPONENT clock_section_pit IS PORT ( - CLK_INPUT : IN STD_LOGIC; -- 14.318 MHz in - CLK_OUT : OUT STD_LOGIC -- 1.193 MHz out + CLK_INPUT : IN STD_LOGIC; -- 14.318 MHz in + CLK_OUT : OUT STD_LOGIC -- 1.193 MHz out ); END COMPONENT; - + COMPONENT ram_driver IS - PORT ( + PORT ( CLK : IN STD_LOGIC; - RESET : IN STD_LOGIC; - BE : IN STD_LOGIC_VECTOR(3 DOWNTO 0); + RESET : IN STD_LOGIC; + BE : IN STD_LOGIC_VECTOR(3 DOWNTO 0); ADS : IN STD_LOGIC; -- Active LOW - CPU_RW : IN STD_LOGIC; -- Inverted in x86! 0 - read, 1 - write - RAMCS : IN STD_LOGIC; -- Active LOW + CPU_RW : IN STD_LOGIC; -- Inverted in x86! 0 - read, 1 - write + RAMCS : IN STD_LOGIC; -- Active LOW ADDR21 : IN STD_LOGIC; -- switches between first and second bank (2MB) - + CS0 : OUT STD_LOGIC; CS1 : OUT STD_LOGIC; RDY : OUT STD_LOGIC; - WE : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); -- For each bytes - OE : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); - + WE : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); -- For each bytes + OE : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); + RAM_WAITSTATES : IN INTEGER RANGE 0 TO 127; - RAM_BURST_WAITSTATES : IN INTEGER RANGE 0 TO 15 + RAM_BURST_WAITSTATES : IN INTEGER RANGE 0 TO 15 ); END COMPONENT; - + COMPONENT transceiver_driver IS PORT ( - BE : IN STD_LOGIC_VECTOR(3 DOWNTO 0); - BS8 : IN STD_LOGIC; + BE : IN STD_LOGIC_VECTOR(3 DOWNTO 0); + BS8 : IN STD_LOGIC; BS16 : IN STD_LOGIC; - - TR_8B : OUT STD_LOGIC_VECTOR( 3 DOWNTO 0); - TR_16B_LOW : OUT STD_LOGIC; - TR_16B_HIGH : OUT STD_LOGIC - ); + + TR_8B : OUT STD_LOGIC_VECTOR( 3 DOWNTO 0); + TR_16B_LOW : OUT STD_LOGIC; + TR_16B_HIGH : OUT STD_LOGIC + ); END COMPONENT; - + COMPONENT be_decoder IS PORT ( - BE0 : in STD_LOGIC; - BE1 : in STD_LOGIC; - BE2 : in STD_LOGIC; - BE3 : in STD_LOGIC; - - A1 : OUT STD_LOGIC; - A0_BLE : OUT STD_LOGIC; - BHE : OUT STD_LOGIC + BE0 : IN STD_LOGIC; + BE1 : IN STD_LOGIC; + BE2 : IN STD_LOGIC; + BE3 : IN STD_LOGIC; + + A1 : OUT STD_LOGIC; + A0_BLE : OUT STD_LOGIC; + BHE : OUT STD_LOGIC ); END COMPONENT; - + COMPONENT address_decoder IS PORT ( ADDR_IN : IN STD_LOGIC_VECTOR(23 DOWNTO 2); @@ -228,463 +222,451 @@ ARCHITECTURE Behavioral OF m8sbc_main IS ADDR_A1 : IN STD_LOGIC; CPU_MIO : IN STD_LOGIC; -- 0 = IO, 1 = MEM CPU_WR : IN STD_LOGIC; -- 0 = read - + RAM_CACHEABLE : IN STD_LOGIC; ROM_CACHEABLE : IN STD_LOGIC; - + INT_ACK : IN STD_LOGIC; - - RAM_CS : OUT STD_LOGIC; + + RAM_CS : OUT STD_LOGIC; ROM_CS : OUT STD_LOGIC; -- ROM_CS, will activate only on READ PIC_CS : OUT STD_LOGIC; PIT_CS : OUT STD_LOGIC; PS2_CS : OUT STD_LOGIC; - O61_CS : OUT STD_LOGIC; -- Write only 61h output port (latch used) + O61_CS : OUT STD_LOGIC; -- Write only 61h output port (latch used) ISA_CS : OUT STD_LOGIC; - CMOS_CS : OUT STD_LOGIC; - + CMOS_CS : OUT STD_LOGIC; + OUT_KEN : OUT STD_LOGIC; - OUT_BS16 : OUT STD_LOGIC; - OUT_BS8 : OUT STD_LOGIC + OUT_BS16 : OUT STD_LOGIC; + OUT_BS8 : OUT STD_LOGIC ); END COMPONENT; - + COMPONENT wr_rd_generator IS PORT ( CLK : IN STD_LOGIC; - RESET : IN STD_LOGIC; + RESET : IN STD_LOGIC; ADS : IN STD_LOGIC; - RW : IN STD_LOGIC; + RW : IN STD_LOGIC; MIO : IN STD_LOGIC; - EN_WRRD : IN STD_LOGIC; - WAITSTATE_CNT : IN INTEGER RANGE 0 to 127; - - RDY : OUT STD_LOGIC; - MEM_WR : OUT STD_LOGIC; - MEM_RD : OUT STD_LOGIC; + EN_WRRD : IN STD_LOGIC; + WAITSTATE_CNT : IN INTEGER RANGE 0 TO 127; + + RDY : OUT STD_LOGIC; + MEM_WR : OUT STD_LOGIC; + MEM_RD : OUT STD_LOGIC; IO_WR : OUT STD_LOGIC; IO_RD : OUT STD_LOGIC - + ); END COMPONENT; - - + COMPONENT isa_driver IS PORT ( CLK : IN STD_LOGIC; - RESET : IN STD_LOGIC; + RESET : IN STD_LOGIC; ADS : IN STD_LOGIC; - RW : IN STD_LOGIC; + RW : IN STD_LOGIC; MIO : IN STD_LOGIC; - EN_ISA : IN STD_LOGIC; -- negated - + EN_ISA : IN STD_LOGIC; -- negated + ISA_CLK_HIGH_CYCLES : IN INTEGER RANGE 1 TO 15; -- ISA clock divisor from main clock - ISA_CLK_LOW_CYCLES : IN INTEGER RANGE 1 TO 15; - WAITSTATE_16C : IN INTEGER RANGE 0 to 15; -- From ADS to check 16B signals - WAITSTATE_END : IN INTEGER RANGE 0 to 127; -- From check to end of transfer - + ISA_CLK_LOW_CYCLES : IN INTEGER RANGE 1 TO 15; + WAITSTATE_16C : IN INTEGER RANGE 0 TO 15; -- From ADS to check 16B signals + WAITSTATE_END : IN INTEGER RANGE 0 TO 127; -- From check to end of transfer + ISA_MEMCS16 : IN STD_LOGIC; ISA_IOCS16 : IN STD_LOGIC; ISA_IO_READY : IN STD_LOGIC; -- Input from ISA - + ISA_RDY : OUT STD_LOGIC; -- Output from driver ISA_MEM_WR : OUT STD_LOGIC; ISA_MEM_RD : OUT STD_LOGIC; ISA_IO_WR : OUT STD_LOGIC; ISA_IO_RD : OUT STD_LOGIC; - ISA_CLK : OUT STD_LOGIC; - - BS8_O : OUT STD_LOGIC; + ISA_CLK : OUT STD_LOGIC; + + BS8_O : OUT STD_LOGIC; BS16_O : OUT STD_LOGIC; - + CPU_16BTR : IN STD_LOGIC; - ISA_SBHE : OUT STD_LOGIC + ISA_SBHE : OUT STD_LOGIC ); END COMPONENT; - COMPONENT keyboard_controller IS PORT ( CLK : IN STD_LOGIC; -- for timeout PS2_CLK : IN STD_LOGIC; - PS2_DATA : IN STD_LOGIC; - RESET : IN STD_LOGIC; - - D_OUT : OUT STD_LOGIC_VECTOR(7 downto 0); - DS_OUT : OUT STD_LOGIC_VECTOR(7 downto 0); + PS2_DATA : IN STD_LOGIC; + RESET : IN STD_LOGIC; + + D_OUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + DS_OUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); CLK_CPU : IN STD_LOGIC; - RD_CLEAR : IN STD_LOGIC; + RD_CLEAR : IN STD_LOGIC; CLEAR_BUF : IN STD_LOGIC; INT_OUT : OUT STD_LOGIC ); END COMPONENT; - + COMPONENT CMOS IS PORT ( - CLK_IN : IN STD_LOGIC; - DATA_IN : IN STD_LOGIC_VECTOR(7 downto 0); - DATA_OUT : OUT STD_LOGIC_VECTOR(7 downto 0); - CMOS_CS : IN STD_LOGIC; + CLK_IN : IN STD_LOGIC; + DATA_IN : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + DATA_OUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + CMOS_CS : IN STD_LOGIC; WR : IN STD_LOGIC; RD : IN STD_LOGIC; A0 : IN STD_LOGIC; - - CLK_PIT : IN STD_LOGIC; - - AVR_CLK : IN STD_LOGIC; - AVR_IO : INOUT STD_LOGIC; - - FPGA_VER : IN STD_LOGIC_VECTOR(31 downto 0); + + CLK_PIT : IN STD_LOGIC; + + AVR_CLK : IN STD_LOGIC; + AVR_IO : INOUT STD_LOGIC; + + FPGA_VER : IN STD_LOGIC_VECTOR(31 DOWNTO 0); RESET : IN STD_LOGIC ); END COMPONENT; - - -- SIGNALS SIGNAL CLK_CPU : STD_LOGIC; -- 12 MHz (def) SIGNAL CLK_14M_BUF : STD_LOGIC; SIGNAL CLK_PIT : STD_LOGIC; -- 1.183 MHz SIGNAL CLK_ISA : STD_LOGIC; - SIGNAL O_BS8 : STD_LOGIC; -- + SIGNAL O_BS8 : STD_LOGIC; -- SIGNAL O_BS16 : STD_LOGIC; -- equal to ADDRDEC_BS8 or ISA_BS8 depending on CS SIGNAL ADDRDEC_BS8 : STD_LOGIC; SIGNAL ADDRDEC_BS16 : STD_LOGIC; SIGNAL ISA_BS8 : STD_LOGIC; - SIGNAL ISA_BS16 : STD_LOGIC; - - SIGNAL I_CS_RAM : STD_LOGIC; - + SIGNAL ISA_BS16 : STD_LOGIC; + + SIGNAL I_CS_RAM : STD_LOGIC; + SIGNAL O_IO_RD : STD_LOGIC; SIGNAL O_IO_WR : STD_LOGIC; - + SIGNAL O_RDY_RAM : STD_LOGIC; SIGNAL O_RDY_WRRD : STD_LOGIC; SIGNAL O_RDY_ISA : STD_LOGIC; - - SIGNAL O_A0_BLE : STD_LOGIC; - SIGNAL O_A1 : STD_LOGIC; - SIGNAL O_BHE : STD_LOGIC; - - SIGNAL I_CS_ROM : STD_LOGIC; - SIGNAL I_CS_PIC : STD_LOGIC; - SIGNAL I_CS_PIT : STD_LOGIC; - SIGNAL I_CS_PS2 : STD_LOGIC; - SIGNAL I_CS_O61 : STD_LOGIC; - SIGNAL I_CS_ISA : STD_LOGIC; + + SIGNAL O_A0_BLE : STD_LOGIC; + SIGNAL O_A1 : STD_LOGIC; + SIGNAL O_BHE : STD_LOGIC; + + SIGNAL I_CS_ROM : STD_LOGIC; + SIGNAL I_CS_PIC : STD_LOGIC; + SIGNAL I_CS_PIT : STD_LOGIC; + SIGNAL I_CS_PS2 : STD_LOGIC; + SIGNAL I_CS_O61 : STD_LOGIC; + SIGNAL I_CS_ISA : STD_LOGIC; SIGNAL I_CS_CMOS : STD_LOGIC; - + SIGNAL S_EN : STD_LOGIC; SIGNAL S_ISA_EN : STD_LOGIC; - SIGNAL S_WAITSTATES : INTEGER RANGE 0 to 127; - SIGNAL S_WAITSTATES_ISA16 : INTEGER RANGE 0 to 127; - + SIGNAL S_WAITSTATES : INTEGER RANGE 0 TO 127; + SIGNAL S_WAITSTATES_ISA16 : INTEGER RANGE 0 TO 127; + SIGNAL MUX_MEM_WR : STD_LOGIC; -- to remove later SIGNAL MUX_MEM_RD : STD_LOGIC; - + SIGNAL MUX_ISA_IO_WR : STD_LOGIC; SIGNAL MUX_ISA_IO_RD : STD_LOGIC; - + SIGNAL IO_RD_P : STD_LOGIC; SIGNAL IO_WR_P : STD_LOGIC; SIGNAL ISA_MEM_WR_P : STD_LOGIC; SIGNAL ISA_MEM_RD_P : STD_LOGIC; - - SIGNAL O_CPU_DATA : STD_LOGIC_VECTOR(7 downto 0); - SIGNAL O_CPU_DATA_P_O : STD_LOGIC; -- PS2 or O61 - SIGNAL O61_DATA_L : STD_LOGIC_VECTOR(7 downto 0) := x"00"; - - SIGNAL O_PS2_DATA : STD_LOGIC_VECTOR(7 downto 0); - SIGNAL O_PS2_STATUS : STD_LOGIC_VECTOR(7 downto 0); - SIGNAL O_PS2_INT : STD_LOGIC; - SIGNAL PS2_RD_CLEAR : STD_LOGIC; - - SIGNAL O_CMOS_DATA_OUT : STD_LOGIC_VECTOR(7 downto 0); - + + SIGNAL O_CPU_DATA : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL O_CPU_DATA_P_O : STD_LOGIC; -- PS2 or O61 + SIGNAL O61_DATA_L : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"00"; + + SIGNAL O_PS2_DATA : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL O_PS2_STATUS : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL O_PS2_INT : STD_LOGIC; + SIGNAL PS2_RD_CLEAR : STD_LOGIC; + + SIGNAL O_CMOS_DATA_OUT : STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL I_INT_ACK : STD_LOGIC; - + SIGNAL EXTRA_BS8 : STD_LOGIC; SIGNAL EXTRA_BS16 : STD_LOGIC; - + SIGNAL CPU_O_KEN : STD_LOGIC; - + SIGNAL O_CPU_16BTR : STD_LOGIC; BEGIN ----------------------------------------- - ---- BEGIN ---- + ---- BEGIN ---- ----------------------------------------- - + CLKGEN: clock_section PORT MAP( CLK_INPUT => CLK_IN_MAIN, -- Input 48 MHz - CPU_CLK_OUT => CLK_CPU + CPU_CLK_OUT => CLK_CPU ); - + -- BUF for both PIT & ISA CLKIN_IBUFG : IBUFG PORT MAP( I => CLK_IN_14_318, O => CLK_14M_BUF ); - + CLKGEN_PIT: clock_section_pit PORT MAP( CLK_INPUT => CLK_14M_BUF, CLK_OUT => CLK_PIT ); - + RAMDRV: ram_driver PORT MAP( - CLK => CLK_CPU, - RESET => RESET_SYS_IN, - BE => CPU_IN_BE, + CLK => CLK_CPU, + RESET => RESET_SYS_IN, + BE => CPU_IN_BE, ADS => CPU_IN_ADS, CPU_RW => CPU_IN_WR, - RAMCS => I_CS_RAM, -- coming from ADRDECODER + RAMCS => I_CS_RAM, -- coming from ADRDECODER ADDR21 => CPU_IN_ADDR(21), -- Outputs CS0 => RAM_CS0, CS1 => RAM_CS1, RDY => O_RDY_RAM, - WE => RAM_WE_B, - OE => RAM_OE_B, - + WE => RAM_WE_B, + OE => RAM_OE_B, + RAM_WAITSTATES => RAM_WAITSTATES, RAM_BURST_WAITSTATES => RAM_BURST_WAITSTATES -- read "bursts" are currently only implemented ); - + TRANSCIEVERDRV: transceiver_driver PORT MAP( - BE => CPU_IN_BE, + BE => CPU_IN_BE, BS8 => O_BS8, -- input - BS16 => O_BS16, -- input - - TR_8B => TR_8B, + BS16 => O_BS16, -- input + + TR_8B => TR_8B, TR_16B_LOW => TR_16B_LOW, TR_16B_HIGH => TR_16B_HIGH ); - + BEDECODER: be_decoder PORT MAP( BE0 => CPU_IN_BE(0), BE1 => CPU_IN_BE(1), BE2 => CPU_IN_BE(2), BE3 => CPU_IN_BE(3), - - A1 => O_A1, + + A1 => O_A1, A0_BLE => O_A0_BLE, BHE => O_BHE ); - + ADRDECODER: address_decoder PORT MAP( - ADDR_IN => CPU_IN_ADDR, + ADDR_IN => CPU_IN_ADDR, ADDR_31 => CPU_IN_ADDR_31, ADDR_A0 => O_A0_BLE, ADDR_A1 => O_A1, CPU_MIO => CPU_IN_MIO, CPU_WR => CPU_IN_WR, - + RAM_CACHEABLE => RAM_CACHE_EN, ROM_CACHEABLE => ROM_CACHE_EN, - + INT_ACK => I_INT_ACK, - + -- outputs RAM_CS => I_CS_RAM, -- to ADRDECODER ROM_CS => I_CS_ROM, -- direct out PIC_CS => I_CS_PIC, -- out PIT_CS => I_CS_PIT, -- out PS2_CS => I_CS_PS2, -- to KBCTRL - O61_CS => I_CS_O61, -- to LE + O61_CS => I_CS_O61, -- to LE CMOS_CS => I_CS_CMOS, ISA_CS => I_CS_ISA, -- to ISA logic - + OUT_KEN => CPU_O_KEN, -- direct out - OUT_BS16 => ADDRDEC_BS16, + OUT_BS16 => ADDRDEC_BS16, OUT_BS8 => ADDRDEC_BS8 ); - + WRRDGEN: wr_rd_generator PORT MAP( CLK => CLK_CPU, - RESET => RESET_SYS_IN, + RESET => RESET_SYS_IN, ADS => CPU_IN_ADS, - RW => CPU_IN_WR, + RW => CPU_IN_WR, MIO => CPU_IN_MIO, EN_WRRD => S_EN, WAITSTATE_CNT => S_WAITSTATES, - + RDY => O_RDY_WRRD, MEM_WR => MUX_MEM_WR, MEM_RD => MUX_MEM_RD, - IO_WR => O_IO_WR, - IO_RD => O_IO_RD + IO_WR => O_IO_WR, + IO_RD => O_IO_RD ); - + ISA_DRV: isa_driver PORT MAP( CLK => CLK_CPU, - RESET => RESET_SYS_IN, + RESET => RESET_SYS_IN, ADS => CPU_IN_ADS, - RW => CPU_IN_WR, + RW => CPU_IN_WR, MIO => CPU_IN_MIO, EN_ISA => S_ISA_EN, -- from ADDR decoder - + ISA_CLK_HIGH_CYCLES => ISA_CLK_HIGH_CYCLES, - ISA_CLK_LOW_CYCLES => ISA_CLK_LOW_CYCLES, + ISA_CLK_LOW_CYCLES => ISA_CLK_LOW_CYCLES, WAITSTATE_16C => S_WAITSTATES_ISA16, WAITSTATE_END => S_WAITSTATES, - + ISA_MEMCS16 => ISA_MEMCS16, ISA_IOCS16 => ISA_IOCS16, ISA_IO_READY => ISA_IO_READY, -- Input from ISA - + ISA_RDY => O_RDY_ISA, -- Output from driver ISA_MEM_WR => ISA_MEM_WR_P, ISA_MEM_RD => ISA_MEM_RD_P, ISA_IO_WR => MUX_ISA_IO_WR, ISA_IO_RD => MUX_ISA_IO_RD, ISA_CLK => CLK_ISA, - - BS8_O => ISA_BS8, + + BS8_O => ISA_BS8, BS16_O => ISA_BS16, - + CPU_16BTR => O_CPU_16BTR, - ISA_SBHE => ISA_SBHE + ISA_SBHE => ISA_SBHE ); - + KBCTRL: keyboard_controller PORT MAP( CLK => CLK_PIT, -- 1.1 MHz, used for transfer timeout PS2_CLK => PS2_CLK, - PS2_DATA => PS2_DATA, - RESET => RESET_SYS_IN, - + PS2_DATA => PS2_DATA, + RESET => RESET_SYS_IN, + CLEAR_BUF => '0', - - D_OUT => O_PS2_DATA, + + D_OUT => O_PS2_DATA, DS_OUT => O_PS2_STATUS, CLK_CPU => CLK_CPU, - RD_CLEAR => PS2_RD_CLEAR, + RD_CLEAR => PS2_RD_CLEAR, INT_OUT => O_PS2_INT ); - + cmos_rtc: CMOS PORT MAP( - CLK_IN => CLK_CPU, - DATA_IN => CPU_DATA, - DATA_OUT => O_CMOS_DATA_OUT, - CMOS_CS => I_CS_CMOS, - WR => O_IO_WR, - RD => O_IO_RD, - A0 => O_A0_BLE, - - CLK_PIT => CLK_PIT, - - - AVR_CLK => AVR_CLK, - AVR_IO => AVR_IO, - - FPGA_VER => FPGA_VER, - RESET => RESET_SYS_IN + CLK_IN => CLK_CPU, + DATA_IN => CPU_DATA, + DATA_OUT => O_CMOS_DATA_OUT, + CMOS_CS => I_CS_CMOS, + WR => O_IO_WR, + RD => O_IO_RD, + A0 => O_A0_BLE, + + CLK_PIT => CLK_PIT, + + AVR_CLK => AVR_CLK, + AVR_IO => AVR_IO, + + FPGA_VER => FPGA_VER, + RESET => RESET_SYS_IN ); - + O_CPU_16BTR <= O_BHE; - + I_INT_ACK <= '0' WHEN (CPU_IN_DC = '0' AND CPU_IN_MIO = '0') ELSE '1'; - -- ISA MEM WR/RD driven by isa_driver - + -- If ISA active, forward outputs to ISA drv - IO_RD_P <= O_IO_RD WHEN I_CS_ISA = '1' ELSE MUX_ISA_IO_RD; - IO_WR_P <= O_IO_WR WHEN I_CS_ISA = '1' ELSE MUX_ISA_IO_WR; - + IO_RD_P <= O_IO_RD WHEN I_CS_ISA = '1' ELSE MUX_ISA_IO_RD; + IO_WR_P <= O_IO_WR WHEN I_CS_ISA = '1' ELSE MUX_ISA_IO_WR; + IO_RD <= IO_RD_P WHEN TRUE ELSE '1'; IO_WR <= IO_WR_P WHEN TRUE ELSE '1'; MEM_WR <= MUX_MEM_WR WHEN TRUE ELSE '1'; MEM_RD <= MUX_MEM_RD WHEN TRUE ELSE '1'; ISA_MEM_WR <= ISA_MEM_WR_P WHEN TRUE ELSE '1'; ISA_MEM_RD <= ISA_MEM_RD_P WHEN TRUE ELSE '1'; - - + EXTRA_BS8 <= ADDRDEC_BS8 WHEN I_CS_ISA = '1' ELSE ISA_BS8; EXTRA_BS16 <= ADDRDEC_BS16 WHEN I_CS_ISA = '1' ELSE ISA_BS16; - + O_BS8 <= '0' WHEN I_INT_ACK = '0' ELSE EXTRA_BS8; -- BS8 on INT ACK O_BS16 <= '1' WHEN I_INT_ACK = '0' ELSE EXTRA_BS16; - + -- WR/RD gen activator and WAITSTATE selector PROCESS(I_CS_ROM, I_CS_PIC, I_CS_PIT, I_CS_O61, I_CS_ISA, I_INT_ACK) VARIABLE SEL_BUS : STD_LOGIC_VECTOR(3 DOWNTO 0); BEGIN - + -- INTA cycle is basically: -- Activating I_INT_ACK by setting CPU_DC, CPU_MIO, CPU_WR to 0 -- CPU do 2 IO reads when I_INT_ACK is 0 -- A2-A31 is set to 0 -- PIC ignores CS on INT_ACK -- We send two INTA pulses to PIC (override IO_RD) - - SEL_BUS := I_CS_ROM & (I_CS_PIC AND I_CS_PIT AND I_CS_O61 AND I_CS_PS2 AND I_CS_CMOS) & I_CS_ISA & I_INT_ACK; - + + SEL_BUS := I_CS_ROM & (I_CS_PIC AND I_CS_PIT AND I_CS_O61 AND I_CS_PS2 AND I_CS_CMOS) & I_CS_ISA & I_INT_ACK; + S_EN <= '1'; S_ISA_EN <= '1'; S_WAITSTATES_ISA16 <= 0; S_WAITSTATES <= 0; - + CASE SEL_BUS IS - - WHEN "0111" => -- ROM active + + WHEN "0111" => -- ROM active S_EN <= '0'; S_WAITSTATES <= ROM_WAITSTATES; - + WHEN "1011" => -- Onboard IO device active (PIT, FPGA) S_EN <= '0'; S_WAITSTATES <= ONBOARD_IO_WAITSTATES; - + WHEN "1101" => -- ISA active - + S_EN <= '1'; -- activate isa S_ISA_EN <= '0'; WHEN "1110" => -- PIC INTA (because I_CS_ISA will be low on INTA addr) S_EN <= '0'; S_WAITSTATES <= PIC_INT_ACK_WAITSTATES; - + WHEN OTHERS => S_WAITSTATES <= 0; -- def no waitstates S_EN <= '1'; -- inactive (negated) S_ISA_EN <= '1'; S_WAITSTATES_ISA16 <= 0; END CASE; - - END PROCESS; - - - - - PIC_CS <= I_CS_PIC; - PIT_CS <= I_CS_PIT; - - + + PIC_CS <= I_CS_PIC; + PIT_CS <= I_CS_PIT; + -- Output from the FPGA to the CPU data bus driver - PROCESS(O_IO_RD, CPU_IN_WR, I_CS_PS2, I_CS_O61, I_CS_CMOS, CPU_IN_ADDR, O_PS2_STATUS, O_PS2_DATA, O61_DATA_L, O_CMOS_DATA_OUT) + PROCESS(O_IO_RD, CPU_IN_WR, I_CS_PS2, I_CS_O61, I_CS_CMOS, CPU_IN_ADDR, O_PS2_STATUS, O_PS2_DATA, O61_DATA_L, O_CMOS_DATA_OUT) BEGIN O_CPU_DATA <= "ZZZZZZZZ"; O_CPU_DATA_P_O <= '0'; - + PS2_RD_CLEAR <= '1'; IF (CPU_IN_WR = '0') THEN -- only allow bus drive on reads - IF (O_IO_RD = '0') THEN - + IF (O_IO_RD = '0') THEN + IF (I_CS_PS2 = '0') THEN -- PS2 read - + IF CPU_IN_ADDR(2) = '1' THEN -- 0x64 O_CPU_DATA <= O_PS2_STATUS; ELSE -- 0x60 O_CPU_DATA <= O_PS2_DATA; PS2_RD_CLEAR <= '0'; -- send clear signal to the PS2 END IF; - + O_CPU_DATA_P_O <= '1'; + ELSIF (I_CS_O61 = '0') THEN -- O61 read O_CPU_DATA <= O61_DATA_L; O_CPU_DATA_P_O <= '1'; - + ELSIF (I_CS_CMOS = '0') THEN -- CMOS read O_CPU_DATA <= O_CMOS_DATA_OUT; O_CPU_DATA_P_O <= '1'; @@ -692,61 +674,53 @@ BEGIN END IF; END IF; END PROCESS; - + CPU_DATA <= O_CPU_DATA WHEN (O_CPU_DATA_P_O = '1') ELSE "ZZZZZZZZ"; - - - + -- PORT O61 read fix -- As output port 61h is a latch, we cant read from it. However we can simulate that using this chipset -- So capture data when write occurs to 61h and send it back if something tries to read from it - + -- PIT latch Output port LE. -- Inverted. 74573 latch latches on 0, pass tho is on 1 PIT_LATCH_LE <= (NOT O_IO_WR) WHEN (I_CS_O61 = '0') ELSE '0'; -- Activate when WR and O61_CS - + PROCESS(CLK_CPU, RESET_SYS_IN) -- O61 write to temp buf BEGIN IF RESET_SYS_IN = '1' THEN - O61_DATA_L <= x"00"; - ELSE - + IF FALLING_EDGE(CLK_CPU) THEN -- decoders update on rising edge IF (I_CS_O61 = '0') AND (O_IO_WR = '0') THEN O61_DATA_L <= CPU_DATA; END IF; END IF; - + END IF; - END PROCESS; - - - - CLK_OUT_CPU <= NOT CLK_CPU WHEN REVERSE_CLOCK = '1' ELSE CLK_CPU; -- For some timings? reason, running below 16 MHz requires inverting clock + + CLK_OUT_CPU <= NOT CLK_CPU WHEN REVERSE_CLOCK = '1' ELSE CLK_CPU; -- For some timings? reason, running below 16 MHz requires inverting clock CLK_OUT_PIT <= CLK_PIT; CLK_OUT_ISA <= CLK_ISA; - CPU_OUT_BS8 <= O_BS8; -- TEMP + CPU_OUT_BS8 <= O_BS8; -- TEMP CPU_OUT_BS16 <= O_BS16; -- TEMP ADDR_A0 <= O_A0_BLE; ADDR_A1 <= O_A1; - + PS2_INTERUPT <= NOT O_PS2_INT; - ROM_CS <= I_CS_ROM; - + ROM_CS <= I_CS_ROM; + -- For some reason I inverted RDY behaviour on the generators before. 1 - is WAIT, 0 is READY !!!!!! -- ISA_IO_READY is 0 = wait CPU_OUT_RDY <= O_RDY_ISA OR O_RDY_RAM OR O_RDY_WRRD; - + RESET_REQ_OUT <= '1'; -- active LOW CPU_OUT_NMI <= '0'; - PIC_INTA <= O_IO_RD WHEN I_INT_ACK = '0' ELSE '1'; -- Int ack for 8259 is like RD. 486 holds INTA state both reads so we need to use IO_RD feature + PIC_INTA <= O_IO_RD WHEN I_INT_ACK = '0' ELSE '1'; -- Int ack for 8259 is like RD. 486 holds INTA state both reads so we need to use IO_RD feature CPU_OUT_KEN <= CPU_O_KEN; -- To fix: doesn't work on ROM - -END Behavioral; +END Behavioral; diff --git a/chipset/ram_driver.vhd b/chipset/ram_driver.vhd index 1ee861c..63fa4c7 100644 --- a/chipset/ram_driver.vhd +++ b/chipset/ram_driver.vhd @@ -1,110 +1,109 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 21:24:19 09/19/2025 --- Design Name: --- Module Name: ram_driver - Behavioral +-- +-- Create Date: 21:24:19 09/19/2025 +-- Design Name: +-- Module Name: ram_driver - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: Driver for 4MB SRAM organised as 8 x 512KB -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.01 - File Created --- Additional Comments: +-- Additional Comments: -- --- 13/01/2026: +-- 13/01/2026: -- RAM read performance improvement: If a read occurs after a read, keep RAM CS/OE active and skip waitstate -- This driver design waits for ADS signal in order to begin transfer. RAM CS/OE are inactive during first clock cycle when ADS asserts --- which already takes one cycle. RAM is doing nothing! Next cycle asserts CS/OE and that begins the RAM access time count. +-- which already takes one cycle. RAM is doing nothing! Next cycle asserts CS/OE and that begins the RAM access time count. -- But what if we see that CPU is constantly accessing the memory? We can keep the CS/OE active and skip one wait state -- Improvement: At 24 MHz FSB, 486DX2, 70ns RAM, 1 waitstate and 0 burst waitstate we went up from 17.5 MB/s to 26.8 MB/s (DOS/CACHECHK) -- This could be also implemented for writes? TODO -- -- ---------------------------------------------------------------------------------- -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; - +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; ENTITY ram_driver IS - PORT ( + PORT ( CLK : IN STD_LOGIC; - RESET : IN STD_LOGIC; - BE : IN STD_LOGIC_VECTOR(3 downto 0); + RESET : IN STD_LOGIC; + BE : IN STD_LOGIC_VECTOR(3 DOWNTO 0); ADS : IN STD_LOGIC; -- Active LOW - CPU_RW : IN STD_LOGIC; -- Inverted in x86! 0 - read, 1 - write - RAMCS : IN STD_LOGIC; -- Active LOW + CPU_RW : IN STD_LOGIC; -- Inverted in x86! 0 - read, 1 - write + RAMCS : IN STD_LOGIC; -- Active LOW ADDR21 : IN STD_LOGIC; -- switches between first and second bank (2MB) - + CS0 : OUT STD_LOGIC; CS1 : OUT STD_LOGIC; RDY : OUT STD_LOGIC; - WE : OUT STD_LOGIC_VECTOR(3 downto 0); -- For each bytes - OE : OUT STD_LOGIC_VECTOR(3 downto 0); - - RAM_WAITSTATES : IN INTEGER RANGE 0 to 127; - RAM_BURST_WAITSTATES : IN INTEGER RANGE 0 to 15 + WE : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); -- For each bytes + OE : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); + + RAM_WAITSTATES : IN INTEGER RANGE 0 TO 127; + RAM_BURST_WAITSTATES : IN INTEGER RANGE 0 TO 15 ); END ram_driver; ARCHITECTURE Behavioral OF ram_driver IS - --CONSTANT ram_waitstates : INTEGER := 0; - + --CONSTANT ram_waitstates : INTEGER := 0; + --Use descriptive names for the states, like st1_reset, st2_search - - TYPE drv_state_type IS (st1_wait_for_ads, st2_wait_state); - SIGNAL drv_state, drv_next_state : drv_state_type; - - --Declare internal signals for all outputs of the state-machine - --SIGNAL _i : std_logic; -- example output signal + + TYPE drv_state_type IS (st1_wait_for_ads, st2_wait_state); + SIGNAL drv_state, drv_next_state : drv_state_type; + + --Declare internal signals for all outputs of the state-machine + --SIGNAL _i : std_logic; -- example output signal SIGNAL RDY_I : STD_LOGIC; - - SIGNAL WS_COUNT : INTEGER RANGE 0 to 127 := 0; - SIGNAL WS_TO_WAIT : INTEGER RANGE 0 to 127 := 0; - + + SIGNAL WS_COUNT : INTEGER RANGE 0 TO 127 := 0; + SIGNAL WS_TO_WAIT : INTEGER RANGE 0 TO 127 := 0; + SIGNAL LAST_CS : STD_LOGIC := '1'; - SIGNAL EXTRA_WS : STD_LOGIC := '0'; - CONSTANT NCOUNT : INTEGER := 16; + SIGNAL EXTRA_WS : STD_LOGIC := '0'; + CONSTANT NCOUNT : INTEGER := 16; CONSTANT NACTIVE : STD_LOGIC := '0'; - + -- WR is held till the end of entire transaction - - SIGNAL LAST_CS0 : STD_LOGIC := '1'; - SIGNAL LAST_CS1 : STD_LOGIC := '1'; + + SIGNAL LAST_CS0 : STD_LOGIC := '1'; + SIGNAL LAST_CS1 : STD_LOGIC := '1'; SIGNAL KEEP_READ : STD_LOGIC := '0'; SIGNAL d_cs0 : STD_LOGIC; SIGNAL d_cs1 : STD_LOGIC; - BEGIN + CSDEC: PROCESS(ADDR21) BEGIN IF ADDR21 = '1' THEN d_cs1 <= '0'; d_cs0 <= '1'; - ELSE + ELSE d_cs0 <= '0'; d_cs1 <= '1'; END IF; END PROCESS; - + CS0 <= d_cs0; CS1 <= d_cs1; SYNC_PROC: PROCESS (CLK) VARIABLE ram_waitstates_total : INTEGER; - VARIABLE d_cs0 : STD_LOGIC; - VARIABLE d_cs1 : STD_LOGIC; - BEGIN - IF(RISING_EDGE(CLK)) THEN - IF (RESET = '1') THEN - drv_state <= st1_wait_for_ads; - -- reset outputs + VARIABLE d_cs0 : STD_LOGIC; + VARIABLE d_cs1 : STD_LOGIC; + BEGIN + IF(RISING_EDGE(CLK)) THEN + IF (RESET = '1') THEN + drv_state <= st1_wait_for_ads; + -- reset outputs WS_COUNT <= 0; EXTRA_WS <= '0'; @@ -113,47 +112,46 @@ BEGIN KEEP_READ <= '0'; LAST_CS0 <= '0'; LAST_CS1 <= '0'; - ELSE - + ELSE + IF (LAST_CS /= RAMCS) AND (NACTIVE = '1') THEN -- extend when previous address was pointing to other device ram_waitstates_total := RAM_WAITSTATES + NCOUNT; ELSE ram_waitstates_total := RAM_WAITSTATES; END IF; - + IF RAMCS = '1' OR CPU_RW = '1' THEN -- reset on switch to different device or on switch to write KEEP_READ <= '0'; LAST_CS0 <= '0'; LAST_CS1 <= '0'; END IF; - + IF drv_state = st1_wait_for_ads THEN IF drv_next_state = st2_wait_state AND RAMCS = '0' THEN -- on toggle from s1 to s2 (ADS) - + IF LAST_CS0 = d_cs0 AND LAST_CS1 = d_cs1 AND CPU_RW = '0' THEN -- eligible for quick read KEEP_READ <= '1'; ram_waitstates_total := RAM_BURST_WAITSTATES; END IF; - + IF ram_waitstates_total > 0 THEN -- go instantly high to indicate wait RDY_I <= '1'; - ELSE + ELSE RDY_I <= '0'; END IF; - + WS_TO_WAIT <= ram_waitstates_total; - + IF (LAST_CS /= RAMCS) AND (NACTIVE = '1') THEN EXTRA_WS <= '1'; - ELSE + ELSE EXTRA_WS <= '0'; END IF; - - + LAST_CS0 <= d_cs0; LAST_CS1 <= d_cs1; - + ELSE -- default low RDY_I <= '0'; END IF; @@ -162,79 +160,76 @@ BEGIN RDY_I <= '0'; -- toggle back on switch END IF; END IF; - + drv_state <= drv_next_state; - - + IF drv_state = st2_wait_state THEN WS_COUNT <= WS_COUNT + 1; - ELSE + ELSE WS_COUNT <= 0; END IF; - -- <= _i; + -- <= _i; -- assign other outputs to internal signals LAST_CS <= RAMCS; - - END IF; - END IF; - END PROCESS; - + END IF; + END IF; + END PROCESS; + OUTPUT_DECODE: PROCESS (drv_state, CPU_RW, BE, ADDR21, EXTRA_WS, WS_COUNT, KEEP_READ) -- RW: 0 - read, 1 - write VARIABLE allow_drive : STD_LOGIC; - BEGIN - --insert statements to decode internal output signals + BEGIN + --insert statements to decode internal output signals IF EXTRA_WS = '1' THEN IF WS_COUNT >= NCOUNT THEN allow_drive := '1'; - ELSE + ELSE allow_drive := '0'; END IF; - ELSE + ELSE allow_drive := '1'; END IF; - - IF (drv_state = st2_wait_state) AND (allow_drive = '1') then - IF CPU_RW = '1' THEN -- write + + IF (drv_state = st2_wait_state) AND (allow_drive = '1') THEN + IF CPU_RW = '1' THEN -- write OE <= "1111"; - WE <= BE; -- BE is valid during entire cycle + WE <= BE; -- BE is valid during entire cycle ELSE -- read WE <= "1111"; - -- OE <= BE; + -- OE <= BE; OE <= "0000"; -- This fixes L1 cache! BE should be ignored during cache fills, but we can ignore it all time during reads anyway END IF; - + ELSE -- not S2 IF KEEP_READ = '1' THEN OE <= "0000"; ELSE OE <= "1111"; END IF; - WE <= "1111"; - END IF; - END PROCESS; - + WE <= "1111"; + END IF; + END PROCESS; + NEXT_STATE_DECODE: PROCESS(drv_state, ADS, RAMCS, WS_COUNT, WS_TO_WAIT) - BEGIN - --declare default state for next_state to avoid latches - drv_next_state <= drv_state; -- default is to stay in current state - - CASE (drv_state) IS - WHEN st1_wait_for_ads => -- When ADS is 0 and RAMCS and 0 we activate - if (ADS = '0') AND (RAMCS = '0') then - drv_next_state <= st2_wait_state; - end if; - WHEN st2_wait_state => - if (ADS = '1') AND (WS_COUNT >= WS_TO_WAIT) then - drv_next_state <= st1_wait_for_ads; - end if; - WHEN OTHERS => - drv_next_state <= st1_wait_for_ads; - end case; - END PROCESS; - + BEGIN + --declare default state for next_state to avoid latches + drv_next_state <= drv_state; -- default is to stay in current state + + CASE (drv_state) IS + WHEN st1_wait_for_ads => -- When ADS is 0 and RAMCS and 0 we activate + IF (ADS = '0') AND (RAMCS = '0') THEN + drv_next_state <= st2_wait_state; + END IF; + WHEN st2_wait_state => + IF (ADS = '1') AND (WS_COUNT >= WS_TO_WAIT) THEN + drv_next_state <= st1_wait_for_ads; + END IF; + WHEN OTHERS => + drv_next_state <= st1_wait_for_ads; + END CASE; + END PROCESS; + RDY <= RDY_I; - -END Behavioral; +END Behavioral; diff --git a/chipset/transceiver_driver.vhd b/chipset/transceiver_driver.vhd index f62935b..add63f1 100644 --- a/chipset/transceiver_driver.vhd +++ b/chipset/transceiver_driver.vhd @@ -1,59 +1,57 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 19:41:48 09/20/2025 --- Design Name: --- Module Name: transceiver_driver - Behavioral +-- +-- Create Date: 19:41:48 09/20/2025 +-- Design Name: +-- Module Name: transceiver_driver - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: Driver for byte swapping transceivers -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.01 - File Created --- Additional Comments: +-- Additional Comments: -- ---------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; - ENTITY transceiver_driver IS - port ( - BE : IN STD_LOGIC_VECTOR(3 downto 0); - BS8 : IN STD_LOGIC; - BS16 : IN STD_LOGIC; - - TR_8B : OUT STD_LOGIC_VECTOR( 3 downto 0); - TR_16B_LOW : OUT STD_LOGIC; - TR_16B_HIGH : OUT STD_LOGIC - ); + PORT ( + BE : IN STD_LOGIC_VECTOR(3 DOWNTO 0); + BS8 : IN STD_LOGIC; + BS16 : IN STD_LOGIC; + + TR_8B : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); + TR_16B_LOW : OUT STD_LOGIC; + TR_16B_HIGH : OUT STD_LOGIC + ); END transceiver_driver; ARCHITECTURE Behavioral OF transceiver_driver IS BEGIN - PROCESS (BE, BS8, BS16) - VARIABLE bs_comb : STD_LOGIC_VECTOR(1 downto 0); + PROCESS (BE, BS8, BS16) + VARIABLE bs_comb : STD_LOGIC_VECTOR(1 DOWNTO 0); BEGIN bs_comb := BS8 & BS16; - CASE bs_comb IS - WHEN "01" => - -- BS8 active - + CASE bs_comb IS + WHEN "01" => + -- BS8 active + TR_8B <= "1111"; TR_16B_LOW <= '1'; TR_16B_HIGH <= '1'; - IF BE(0) = '0' THEN TR_8B(0) <= '0'; - ELSE + ELSE IF BE(1) = '0' THEN TR_8B(1) <= '0'; ELSE @@ -65,22 +63,21 @@ BEGIN END IF; END IF; END IF; - END IF; + END IF; - WHEN "10" => -- BS16 active - + TR_8B <= "1111"; - TR_16B_LOW <= '1'; -- Higher 8 bits to 8-15 + TR_16B_LOW <= '1'; -- Higher 8 bits to 8-15 TR_16B_HIGH <= '1'; -- Higher 8 bits to 24-31 - + IF BE(0) = '0' THEN -- start 0 TR_8B(0) <= '0'; -- 8b (0) IF BE(1) = '0' THEN -- 16b if 0-15 TR_16B_LOW <= '0'; END IF; - ELSE + ELSE IF BE(1) = '0' THEN -- start 8 TR_16B_LOW <= '0'; -- only 8b possible ELSE @@ -96,16 +93,12 @@ BEGIN END IF; END IF; END IF; - - - WHEN OTHERS => - TR_8B <= "1111"; + + WHEN OTHERS => + TR_8B <= "1111"; TR_16B_LOW <= '1'; TR_16B_HIGH <= '1'; - END CASE; - - - END PROCESS; - -END Behavioral; + END CASE; + END PROCESS; +END Behavioral; diff --git a/chipset/wr_rd_generator.vhd b/chipset/wr_rd_generator.vhd index 32768af..60d6358 100644 --- a/chipset/wr_rd_generator.vhd +++ b/chipset/wr_rd_generator.vhd @@ -1,20 +1,20 @@ ---------------------------------------------------------------------------------- -- Company: maniek86.xyz -- Engineer: Piotr Grzesik --- --- Create Date: 18:49:22 09/21/2025 --- Design Name: --- Module Name: wr_rd_generator - Behavioral +-- +-- Create Date: 18:49:22 09/21/2025 +-- Design Name: +-- Module Name: wr_rd_generator - Behavioral -- Project Name: Hamster 1 chipset -- Target Devices: M8SBC-486 REV 1.0 --- Tool versions: +-- Tool versions: -- Description: Intel bus style control signals generator with waitstate support -- --- Dependencies: +-- Dependencies: -- --- Revision: +-- Revision: -- Revision 0.01 - File Created --- Additional Comments: +-- Additional Comments: -- ---------------------------------------------------------------------------------- LIBRARY IEEE; @@ -24,71 +24,69 @@ USE IEEE.NUMERIC_STD.ALL; ENTITY wr_rd_generator IS PORT ( CLK : IN STD_LOGIC; - RESET : IN STD_LOGIC; + RESET : IN STD_LOGIC; ADS : IN STD_LOGIC; - RW : IN STD_LOGIC; + RW : IN STD_LOGIC; MIO : IN STD_LOGIC; - EN_WRRD : IN STD_LOGIC; -- negated - WAITSTATE_CNT : IN INTEGER RANGE 0 to 127; - - RDY : OUT STD_LOGIC; - MEM_WR : OUT STD_LOGIC; - MEM_RD : OUT STD_LOGIC; + EN_WRRD : IN STD_LOGIC; -- negated + WAITSTATE_CNT : IN INTEGER RANGE 0 to 127; + + RDY : OUT STD_LOGIC; + MEM_WR : OUT STD_LOGIC; + MEM_RD : OUT STD_LOGIC; IO_WR : OUT STD_LOGIC; IO_RD : OUT STD_LOGIC ); END wr_rd_generator; ARCHITECTURE Behavioral OF wr_rd_generator IS - SIGNAL SET_WAITSTATES : INTEGER RANGE 0 to 127; - - TYPE drv_state_type IS (st1_wait_for_ads, st2_wait_state); - SIGNAL drv_state, drv_next_state : drv_state_type; - - SIGNAL RDY_I : STD_LOGIC; - - SIGNAL WS_COUNT : INTEGER RANGE 0 to 127 := 0; - - SIGNAL LAST_CS : STD_LOGIC := '1'; - SIGNAL EXTRA_WS : STD_LOGIC := '0'; - CONSTANT NCOUNT : INTEGER := 2; - CONSTANT NACTIVE : STD_LOGIC := '1'; - -BEGIN + SIGNAL SET_WAITSTATES : INTEGER RANGE 0 to 127; - --SET_WAITSTATES <= WAITSTATE_CNT; + TYPE drv_state_type IS (st1_wait_for_ads, st2_wait_state); + SIGNAL drv_state, drv_next_state : drv_state_type; + + SIGNAL RDY_I : STD_LOGIC; + SIGNAL WS_COUNT : INTEGER RANGE 0 to 127 := 0; + SIGNAL LAST_CS : STD_LOGIC := '1'; + SIGNAL EXTRA_WS : STD_LOGIC := '0'; + CONSTANT NCOUNT : INTEGER := 2; + CONSTANT NACTIVE : STD_LOGIC := '1'; + +BEGIN + + --SET_WAITSTATES <= WAITSTATE_CNT; SYNC_PROC: PROCESS (CLK) - BEGIN - IF(RISING_EDGE(CLK)) THEN - IF (RESET = '1') THEN - drv_state <= st1_wait_for_ads; - -- reset output + BEGIN + IF(RISING_EDGE(CLK)) THEN + IF (RESET = '1') THEN + drv_state <= st1_wait_for_ads; + -- reset output WS_COUNT <= 0; SET_WAITSTATES <= 0; RDY_I <= '0'; -- flip flop - + EXTRA_WS <= '0'; LAST_CS <= '1'; - ELSE + ELSE IF drv_state = st1_wait_for_ads THEN IF drv_next_state = st2_wait_state THEN -- on toggle from s1 to s2 - + IF (LAST_CS /= EN_WRRD) AND (NACTIVE = '1') THEN SET_WAITSTATES <= WAITSTATE_CNT + NCOUNT; EXTRA_WS <= '1'; -- to check - ELSE + ELSE SET_WAITSTATES <= WAITSTATE_CNT; EXTRA_WS <= '0'; END IF; - + IF SET_WAITSTATES > 0 THEN -- go instantly high to indicate wait RDY_I <= '1'; - ELSE + ELSE RDY_I <= '0'; END IF; - + ELSE -- default low RDY_I <= '0'; END IF; @@ -97,51 +95,50 @@ BEGIN RDY_I <= '0'; -- toggle back on switch END IF; END IF; - + drv_state <= drv_next_state; - - + IF drv_state = st2_wait_state THEN WS_COUNT <= WS_COUNT + 1; - ELSE + ELSE WS_COUNT <= 0; END IF; - + LAST_CS <= EN_WRRD; - END IF; - END IF; - END PROCESS; - + END IF; + END IF; + END PROCESS; + OUTPUT_DECODE: PROCESS (drv_state, RW, MIO, WS_COUNT, EXTRA_WS) -- RW: 0 - read, 1 - write - VARIABLE RD : STD_LOGIC; - VARIABLE WR : STD_LOGIC; - VARIABLE allow_drive : STD_LOGIC; - BEGIN - --insert statements to decode internal output signals + VARIABLE RD : STD_LOGIC; + VARIABLE WR : STD_LOGIC; + VARIABLE allow_drive : STD_LOGIC; + BEGIN + --insert statements to decode internal output signals RD := '1'; WR := '1'; MEM_WR <= '1'; MEM_RD <= '1'; IO_WR <= '1'; IO_RD <= '1'; - + IF EXTRA_WS = '1' THEN IF WS_COUNT >= NCOUNT THEN allow_drive := '1'; - ELSE + ELSE allow_drive := '0'; END IF; - ELSE + ELSE allow_drive := '1'; END IF; - - IF (drv_state = st2_wait_state) AND (allow_drive = '1') then - IF RW = '1' THEN -- write + + IF (drv_state = st2_wait_state) AND (allow_drive = '1') THEN + IF RW = '1' THEN -- write WR := '0'; ELSE -- read - RD := '0'; + RD := '0'; END IF; - + -- 0 = IO, 1 = MEM IF MIO = '1' THEN MEM_WR <= WR; @@ -150,37 +147,35 @@ BEGIN IO_WR <= WR; IO_RD <= RD; END IF; - + ELSE -- not S2 MEM_WR <= '1'; MEM_RD <= '1'; IO_WR <= '1'; IO_RD <= '1'; - END IF; - END PROCESS; - + END IF; + END PROCESS; + NEXT_STATE_DECODE: PROCESS(drv_state, ADS, EN_WRRD, WS_COUNT, SET_WAITSTATES) - BEGIN - --declare default state for next_state to avoid latches - drv_next_state <= drv_state; -- default is to stay in current state - - CASE (drv_state) IS - WHEN st1_wait_for_ads => -- When ADS is 0 and RAMCS and 0 we activate - IF (ADS = '0') AND (EN_WRRD = '0') THEN - drv_next_state <= st2_wait_state; - END IF; - WHEN st2_wait_state => - IF ((ADS = '1') AND (WS_COUNT >= SET_WAITSTATES)) OR (EN_WRRD = '1') THEN -- End of cycle or EN for some reason deaserted) - drv_next_state <= st1_wait_for_ads; - END IF; - - WHEN OTHERS => - drv_next_state <= st1_wait_for_ads; - END CASE; - END PROCESS; - - RDY <= RDY_I; + BEGIN + --declare default state for next_state to avoid latches + drv_next_state <= drv_state; -- default is to stay in current state + + CASE (drv_state) IS + WHEN st1_wait_for_ads => -- When ADS is 0 and RAMCS and 0 we activate + IF (ADS = '0') AND (EN_WRRD = '0') THEN + drv_next_state <= st2_wait_state; + END IF; + WHEN st2_wait_state => + IF ((ADS = '1') AND (WS_COUNT >= SET_WAITSTATES)) OR (EN_WRRD = '1') THEN -- End of cycle or EN for some reason deaserted) + drv_next_state <= st1_wait_for_ads; + END IF; + WHEN OTHERS => + drv_next_state <= st1_wait_for_ads; + END CASE; + END PROCESS; -END Behavioral; + RDY <= RDY_I; +END Behavioral;