diff --git a/CHANGELOG.md b/CHANGELOG.md index ae4fa7a..6cf4ab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## Unreleased +- Peripheral: Timer0 (8-bit) is now supported. + - Supported Prescaling: 1/8/64/256/1024 + - Supported Mode: Normal Mode + - Currently not supported: PWM and external clock select + +- Timer interrupts are now available. + - Added new assembly instructions: - lpm(R0) (load program memory) - lpm(Z) (load program memory) @@ -9,11 +16,16 @@ - las (load and set byte in data space) - lac (load and clear byte in data space) - fmul (fractional multiply unsigned) + - reti (return from interrupt) - Bug fix for the preprocessor - Skip instructions are now compatible with 32-bit opcode - Jumps, skips, etc. are now able to wrap around FLASH memory +- Refactored System class (Core / Peripherals) +- Seperate IO space class +- IRQ Handler + ## v.0.0.2 - 2020-09-17 - 32-bit Decoder: 32-bit opcodes are now supported diff --git a/README.md b/README.md index 6addf70..9a23978 100644 --- a/README.md +++ b/README.md @@ -153,26 +153,31 @@ Note: You may open multiple files in interactive Debugging Mode. - [ ] ... # Features -- [x] Debugging Assembly -- [x] Advanced Disassembler, recovering Labels - [x] Backwards Stepping -- [x] Simple and fancy Commandline Design -- [x] GPR Visualization -- [x] SRAM Visualization -- [x] Loading .eep.hex into the Microcontroller -- [ ] EEPROM Visualization -- [x] SREG Visualization -- [ ] FLASH Visualization -- [ ] Relation between Code Segments -- [ ] I/O Support -- [ ] Seperate I/O Pin View +- [x] Advanced Disassembler, recovering Labels +- [x] Syntax Highlight for the disassembled Sourcecode +- [x] Interrupts supported - [x] Open and debug more than one file in the same session -- [x] Fast and easy to use -- [x] Short CLI Commands to debug faster -- [ ] Full Instruction Support +- [ ] Currently supporting ~ 93 assembly instructions + +- [x] Breakpoints +- [ ] Watchpoints +- [x] Examine Memory + +- [x] Interactive Mode +- [x] Disassembler Mode +- [x] Headless Mode + +- [ ] Peripherals + - [x] 8-bit Timer (partial) + - [ ] 16-bit Timer + - [ ] EEPROM + - [ ] UART + - [ ] SPI + - [ ] ... # Instructions -Currently MDX supports: ~ 72 Instructions. More Instructions are coming soon. +Currently MDX supports: ~ 93 Instructions. More Instructions are coming soon. # Contributing diff --git a/include/misc/mnemstr.h b/include/misc/mnemstr.h index cb93de0..1fff52a 100644 --- a/include/misc/mnemstr.h +++ b/include/misc/mnemstr.h @@ -12,7 +12,7 @@ #define N_MAPS 6 -#define N_FLOW 19 +#define N_FLOW 20 #define N_MISC 21 #define N_LOGIC 14 #define N_ACCESS 13 diff --git a/include/system/system.h b/include/system/system.h index 8349251..7850647 100644 --- a/include/system/system.h +++ b/include/system/system.h @@ -73,7 +73,6 @@ extern void sys_dump_data(const struct _system *this, array_t *buffer); /* IO Operations */ extern void sys_update_io(const struct _system *this, const uint64_t oldc); -extern void sys_exec_irs(struct _system *this, const int isr); /* EEPROM Operations */ diff --git a/src/disassembler/labelmap.c b/src/disassembler/labelmap.c index f267b9d..36c861f 100644 --- a/src/disassembler/labelmap.c +++ b/src/disassembler/labelmap.c @@ -47,9 +47,9 @@ struct _lmap* lmap_ctor(void) { lmap->p->labels = array_ctor(256, NULL, NULL); lmap->p->map = strmap_ctor(N_FLOW); - for(int i = 0; i < N_FLOW - 3; i++) { + for(int i = 0; i < N_FLOW - 4; i++) { - /* (N_FLOW - 3) excludes indirect jumps */ + /* (N_FLOW - 4) excludes indirect jumps */ const char *instr = mnemstr[FLOW][i]; strmap_put(lmap->p->map, mnemstr[FLOW][i]); diff --git a/src/disassembler/mnemonics.c b/src/disassembler/mnemonics.c index 968fe88..08d4e57 100644 --- a/src/disassembler/mnemonics.c +++ b/src/disassembler/mnemonics.c @@ -1490,6 +1490,21 @@ char* mnem_ret(const int opcode) { return mnemonic; } +char* mnem_reti(const int opcode) { + + queue_t *stream = queue_ctor(); + + char *fill = strfill(' ', 4, TAB); + queue_put(stream, 3, "reti", fill, "; PC <- DATA[SP]"); + + char *mnemonic = queue_str(stream); + + queue_dtor(stream); + free(fill); + + return mnemonic; +} + char* mnem_icall(const int opcode) { queue_t *stream = queue_ctor(); @@ -2258,8 +2273,8 @@ char* (*mnemonics[INSTR_MAX]) (const int opcode) = { mnem_dec, mnem_inc, mnem_add, mnem_adc, mnem_adiw, mnem_sub, mnem_subi, mnem_sbc, mnem_sbci, mnem_sbiw, mnem_push, mnem_pop, mnem_in, mnem_out, mnem_sbis, mnem_sbrc, mnem_clr, mnem_ld_x, mnem_ld_xi, mnem_ld_dx, mnem_ld_y, mnem_ld_yi, mnem_ld_dy, mnem_ldd_yq, mnem_ldd_zq, mnem_ld_z, mnem_ld_zi, mnem_st_x, mnem_st_xi, mnem_std_yq, mnem_std_zq, mnem_sts, mnem_sts32, mnem_xch, mnem_brne, mnem_breq, - mnem_brge, mnem_brpl, mnem_brlo, mnem_brlt, mnem_brcc, mnem_brcs, mnem_brvs, mnem_brts, mnem_brtc, mnem_brmi, mnem_rcall, mnem_ret, mnem_icall, mnem_call, - mnem_cp, mnem_cpi, mnem_cpc, mnem_lsr, mnem_asr, mnem_ror, mnem_swap, mnem_ori, mnem_or_asm, mnem_and_asm, mnem_andi, mnem_las, mnem_lac, mnem_com, mnem_neg, + mnem_brge, mnem_brpl, mnem_brlo, mnem_brlt, mnem_brcc, mnem_brcs, mnem_brvs, mnem_brts, mnem_brtc, mnem_brmi, mnem_rcall, mnem_ret, mnem_reti, mnem_icall, + mnem_call, mnem_cp, mnem_cpi, mnem_cpc, mnem_lsr, mnem_asr, mnem_ror, mnem_swap, mnem_ori, mnem_or_asm, mnem_and_asm, mnem_andi, mnem_las, mnem_lac, mnem_com, mnem_neg, mnem_bld, mnem_bst, mnem_lpm, mnem_lpm_z, mnem_ses, mnem_set, mnem_sev, mnem_sez, mnem_seh, mnem_sec, mnem_sei, mnem_sen, mnem_cls, mnem_clt, mnem_clv, mnem_clz, mnem_clh, mnem_clc, mnem_cli, mnem_cln, mnem_bclr, mnem_bset }; diff --git a/src/disassembler/opcode.c b/src/disassembler/opcode.c index c12c8c7..bec68b5 100644 --- a/src/disassembler/opcode.c +++ b/src/disassembler/opcode.c @@ -69,6 +69,7 @@ const int opcode[SET_SIZE][WORD] = { { 1, 1, 1, 1, 0, 0, K, K, K, K, K, K, K, 0, 1, 0 }, /* BRMI */ { 1, 1, 0, 1, K, K, K, K, K, K, K, K, K, K, K, K }, /* RCALL */ { 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0 }, /* RET */ +{ 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0 }, /* RETI */ { 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1 }, /* ICALL */ { 1, 0, 0, 1, 0, 1, 0, K, K, K, K, K, 1, 1, 1, K }, /* CALL */ { 0, 0, 0, 1, 0, 1, R, D, D, D, D, D, R, R, R, R }, /* CP */ diff --git a/src/instructions/instructions.c b/src/instructions/instructions.c index bfa775b..0e8d0b3 100644 --- a/src/instructions/instructions.c +++ b/src/instructions/instructions.c @@ -1230,6 +1230,30 @@ void ret(system_t *sys, const int opcode) { } } +void reti(system_t *sys, const int opcode) { + + uint8_t pcl, pch, pcm; + + switch(PC_BIT) { + + case 16: + + pch = sys_pop_stack(sys); + pcl = sys_pop_stack(sys); + + sys_set_pc(sys, (pch << 8) + pcl); + sys->cycles += 4; + + break; + + case 22: /* currently not supported */ break; + + default: return; + } + + sys_write_sreg(sys, IF, 0x01); +} + void icall(system_t *sys, const int opcode) { const int pc = sys_get_pc(sys); @@ -1848,8 +1872,8 @@ void (*instructions[INSTR_MAX]) (system_t *sys, const int opcode) = { dec, inc, add, adc, adiw, sub, subi, sbc, sbci, sbiw, push, pop, in, out, sbis, sbrc, clr, ld_x, ld_xi, ld_dx, ld_y, ld_yi, ld_dy, ldd_yq, ldd_zq, ld_z, ld_zi, st_x, st_xi, std_yq, std_zq, sts, sts32, xch, brne, breq, - brge, brpl, brlo, brlt, brcc, brcs, brvs, brts, brtc, brmi, rcall, ret, icall, call, - cp, cpi, cpc, lsr, asr, ror, swap, ori, or_asm, and_asm, andi, las, lac, com, neg, + brge, brpl, brlo, brlt, brcc, brcs, brvs, brts, brtc, brmi, rcall, ret, reti, icall, + call, cp, cpi, cpc, lsr, asr, ror, swap, ori, or_asm, and_asm, andi, las, lac, com, neg, bld, bst, lpm, lpm_z, ses, set, sev, sez, seh, sec, sei, sen, cls, clt, clv, clz, clh, clc, cli, cln, bclr, bset }; diff --git a/src/misc/mnemstr.c b/src/misc/mnemstr.c index f54a966..a6ff55d 100644 --- a/src/misc/mnemstr.c +++ b/src/misc/mnemstr.c @@ -8,7 +8,7 @@ const char *mnemstr[N_MAPS][32] = { /* Flow Mnemonics */ { "rjmp", "brne", "breq", "brge", "brpl", "brlo", "brlt", "brcc", "brcs", "brvs", "brts", "brtc", "brmi", "rcall", "jmp", "call", "ret", - "icall", "ijmp" }, + "icall", "ijmp", "reti" }, /* Misc Mnemonics */ { "nop", "bld", "bst", "ses", "set", "sev", "sez", "seh", "sec", "sei", "sen", diff --git a/src/system/system.c b/src/system/system.c index a63acb0..97d1b1e 100644 --- a/src/system/system.c +++ b/src/system/system.c @@ -27,6 +27,12 @@ struct _private { bool terminated; }; +/* Forward Declaration of static Functions */ + +static void sys_exec_irs(struct _system *this, const int isr); + +/* --- Extern --- */ + struct _system* sys_ctor(const char *file) { struct _system *sys; @@ -95,7 +101,7 @@ int sys_step(struct _system *this) { sys_update_io(this, old_cycles); - if((sreg & (0x01 << IF)) == 0x01) { + if((sreg & (0x01 << IF)) != 0x00) { int isr; @@ -252,17 +258,6 @@ void sys_update_io(const struct _system *this, const uint64_t oldc) { data_update_io(this->p->data, this->clock, (this->cycles - oldc)); } -void sys_exec_irs(struct _system *this, const int isr) { - - const uint64_t old_cycles = this->cycles; - this->cycles += 4; - - alu_write_sreg(this->p->alu, IF, 0); - sys_update_io(this, old_cycles); - - alu_set_pc(this->p->alu, isr); -} - void sys_write_eeprom(struct _system *this, const uint16_t addr, const int8_t value) { eeprom_write(this->p->eeprom, addr, value); @@ -307,3 +302,20 @@ entry_t* sys_dump_table(const struct _system *this) { return alu_dump_table(this->p->alu); } + +/* --- Static --- */ + +static void sys_exec_irs(struct _system *this, const int isr) { + + const uint64_t old_cycles = this->cycles; + const int pc = alu_get_pc(this->p->alu); + + data_push(this->p->data, pc & 0x00ff); + data_push(this->p->data, (pc & 0xff00) >> 8); + + alu_write_sreg(this->p->alu, IF, 0x00); + this->cycles += 4; + + sys_update_io(this, old_cycles); + alu_set_pc(this->p->alu, isr); +} diff --git a/test/peripherals/timer0/timer0_8bit.asm b/test/peripherals/timer0/timer0_8bit.asm new file mode 100644 index 0000000..16eba4a --- /dev/null +++ b/test/peripherals/timer0/timer0_8bit.asm @@ -0,0 +1,66 @@ +.INCLUDE "m32def.inc" + +; +; Demonstrating 8-bit Timer0 in ATmega32. +; +; MDX is now able to simulate hardware timers +; and interrupts. Currently, only timer0 +; (TCNT0) is available and PWM is not supported. +; But I am working on it ;) +; +; The following program initialize TCNT0, and +; enables Hardware Interrupts (TOIE0 in TIMSK). +; Whenever an overflow in TCNT0 occurs, the +; ISR (isr_tim0_ov) is executed. The ISR is +; writing to PORTB. +; +; Mode: Timer0 (8-bit), Normal Mode +; Prescaler: clk(cpu) / 1 +; +; This program was successfully simulated by MDX. +; + + +.def temp = r18 + +.ORG 0x0000 +rjmp stack_init + +.ORG OVF0addr +rjmp isr_tim0_ov + +stack_init: +ldi temp, LOW(RAMEND) +out SPL, temp +ldi temp, HIGH(RAMEND) +out SPH, temp +rjmp port_init + +port_init: +ldi r17, 0xff +out DDRB, r17 +out PORTB, r17 +rjmp enable_irq + +enable_irq: +ldi r16, 0x01 +out TIMSK, r16 +sei +rjmp enable_timer + +enable_timer: +ldi r16, (0x01 << CS00) +out TCCR0, r16 +rjmp loop + +loop: +rjmp loop + +; ISR (Timer0 Overflow) + +isr_tim0_ov: +out PORTB, r17 +com r17 +reti + + diff --git a/test/peripherals/timer0/timer0_8bit.hex b/test/peripherals/timer0/timer0_8bit.hex new file mode 100644 index 0000000..e84d8cd --- /dev/null +++ b/test/peripherals/timer0/timer0_8bit.hex @@ -0,0 +1,6 @@ +:020000020000FC +:0200000016C028 +:10002C0011C02FE52DBF28E02EBF00C01FEF17BB5E +:10003C0018BB00C001E009BF789400C001E003BF09 +:0A004C0000C0FFCF18BB10951895F7 +:00000001FF