diff options
author | Phillip Stevens <phillip.stevens@gmail.com> | 2021-12-08 00:41:11 +0300 |
---|---|---|
committer | Gaurav Aggarwal <aggarg@amazon.com> | 2021-12-08 23:00:55 +0300 |
commit | 3d14f8d0339053394bae9859b530e317e43a60c2 (patch) | |
tree | 0d238cf58d1623de5164e51403ce3efa70547a6a | |
parent | 7f6ba1d6ef5b14f92ef878d160c8b859a9900a9a (diff) |
Add z180 port - sdcc & sccz80 compiler support (#5)
This was originally contributed here - https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/52
Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
-rw-r--r-- | Z88DK/Z180/port.c | 283 | ||||
-rw-r--r-- | Z88DK/Z180/portmacro.h | 431 | ||||
-rw-r--r-- | Z88DK/Z180/readme.md | 13 |
3 files changed, 727 insertions, 0 deletions
diff --git a/Z88DK/Z180/port.c b/Z88DK/Z180/port.c new file mode 100644 index 0000000..59a815f --- /dev/null +++ b/Z88DK/Z180/port.c @@ -0,0 +1,283 @@ +/* + * FreeRTOS Kernel V10.4.3 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + + +#include <stdlib.h> + +#include "include/FreeRTOS.h" + +#if __SDCC +#include "include/sdcc/task.h" +#elif __SCCZ80 +#include "include/sccz80/task.h" +#endif + +/*-----------------------------------------------------------*/ + +/* We require the address of the pxCurrentTCB variable, but don't want to know +any details of its type. */ + +typedef void TCB_t; +extern volatile TCB_t * volatile pxCurrentTCB; +/*-----------------------------------------------------------*/ + +/* + * Macro to save all the general purpose registers, the save the stack pointer + * into the TCB. + * + * The first thing we do is save the flags then disable interrupts. This is to + * guard our stack against having a context switch interrupt after we have already + * pushed the registers onto the stack. + * + * The interrupts will have been disabled during the call to portSAVE_CONTEXT() + * so we need not worry about reading/writing to the stack pointer. + */ + +#define configTICK_RATE_HZ (256) /* Timer configured */ +#define configISR_ORG ASMPC /* ISR relocation */ +#define configISR_IVT 0xFFE6 /* PRT1 address */ + +#ifdef __SCCZ80 + +#define configSETUP_TIMER_INTERRUPT() \ + do{ \ + asm( \ + "EXTERN __CPU_CLOCK \n" \ + "EXTERN RLDR1L, RLDR1H \n" \ + "EXTERN TCR, TCR_TIE1, TCR_TDE1 \n" \ + "ld de,_timer_isr \n" \ + "ld hl,"string(configISR_IVT)" ; PRT1 address \n" \ + "ld (hl),e \n" \ + "inc hl \n" \ + "ld (hl),d \n" \ + "; we do configTICK_RATE_HZ ticks per second \n" \ + "ld hl,__CPU_CLOCK/"string(configTICK_RATE_HZ)"/20-1 \n" \ + "out0(RLDR1L),l \n" \ + "out0(RLDR1H),h \n" \ + "in0 a,(TCR) \n" \ + "or TCR_TIE1|TCR_TDE1 \n" \ + "out0 (TCR),a \n" \ + ); \ + }while(0) + +#define configRESET_TIMER_INTERRUPT() \ + do{ \ + asm( \ + "EXTERN TCR, TMDR1L \n" \ + "in0 a,(TCR) \n" \ + "in0 a,(TMDR1L) \n" \ + ); \ + }while(0) + +#define configSTOP_TIMER_INTERRUPT() \ + do{ \ + asm( \ + "EXTERN TCR, TCR_TIE1, TCR_TDE1 \n" \ + "; disable down counting and interrupts for PRT1\n" \ + "in0 a,(TCR) \n" \ + "xor TCR_TIE1|TCR_TDE1 \n" \ + "out0 (TCR),a \n" \ + ); \ + }while(0) + +#endif + +#ifdef __SDCC + +#define configSETUP_TIMER_INTERRUPT() \ + do{ \ + __asm \ + EXTERN __CPU_CLOCK \ + EXTERN RLDR1L, RLDR1H \ + EXTERN TCR, TCR_TIE1, TCR_TDE1 \ + ; address of ISR \ + ld de,_timer_isr \ + ld hl,configISR_IVT ; PRT1 address \ + ld (hl),e \ + inc hl \ + ld (hl),d \ + ; we do configTICK_RATE_HZ ticks per second \ + ld hl,__CPU_CLOCK/configTICK_RATE_HZ/20-1 \ + out0(RLDR1L),l \ + out0(RLDR1H),h \ + ; enable down counting and interrupts for PRT1 \ + in0 a,(TCR) \ + or TCR_TIE1|TCR_TDE1 \ + out0 (TCR),a \ + __endasm; \ + }while(0) + +#define configRESET_TIMER_INTERRUPT() \ + do{ \ + __asm \ + EXTERN TCR, TMDR1L \ + ; reset interrupt for PRT1 \ + in0 a,(TCR) \ + in0 a,(TMDR1L) \ + __endasm; \ + }while(0) + +#define configSTOP_TIMER_INTERRUPT() \ + do{ \ + __asm \ + EXTERN TCR, TCR_TIE1, TCR_TDE1 \ + ; disable down counting and interrupts for PRT1 \ + in0 a,(TCR) \ + xor TCR_TIE1|TCR_TDE1 \ + out0 (TCR),a \ + __endasm; \ + }while(0) + +#endif + +/*-----------------------------------------------------------*/ + +/* + * Perform hardware setup to enable ticks from Timer. + */ +static void prvSetupTimerInterrupt( void ) __preserves_regs(iyh,iyl); +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) +{ + /* Place the parameter on the stack in the expected location. */ + *pxTopOfStack-- = ( StackType_t ) pvParameters; + + /* Place the task return address on stack. Not used */ + *pxTopOfStack-- = ( StackType_t ) 0; + + /* The start of the task code will be popped off the stack last, so place + it on first. */ + *pxTopOfStack-- = ( StackType_t ) pxCode; + + /* Now the registers. */ + *pxTopOfStack-- = ( StackType_t ) 0xAFAF; /* AF */ + *pxTopOfStack-- = ( StackType_t ) 0x0404; /* IF */ + *pxTopOfStack-- = ( StackType_t ) 0xBCBC; /* BC */ + *pxTopOfStack-- = ( StackType_t ) 0xDEDE; /* DE */ + *pxTopOfStack-- = ( StackType_t ) 0xEFEF; /* HL */ + *pxTopOfStack-- = ( StackType_t ) 0xFAFA; /* AF' */ + *pxTopOfStack-- = ( StackType_t ) 0xCBCB; /* BC' */ + *pxTopOfStack-- = ( StackType_t ) 0xEDED; /* DE' */ + *pxTopOfStack-- = ( StackType_t ) 0xFEFE; /* HL' */ + *pxTopOfStack-- = ( StackType_t ) 0xCEFA; /* IX */ + *pxTopOfStack = ( StackType_t ) 0xADDE; /* IY */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +BaseType_t xPortStartScheduler( void ) __preserves_regs(a,b,c,d,e,iyh,iyl) __naked +{ + /* Setup the relevant timer hardware to generate the tick. */ + prvSetupTimerInterrupt(); + + /* Restore the context of the first task that is going to run. */ + portRESTORE_CONTEXT(); + + /* Should not get here. */ + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler( void ) __preserves_regs(b,c,d,e,h,l,iyh,iyl) +{ + /* + * It is unlikely that the Z80 port will get stopped. + * If required simply disable the tick interrupt here. + */ + configSTOP_TIMER_INTERRUPT(); +} +/*-----------------------------------------------------------*/ + +/* + * Manual context switch. The first thing we do is save the registers so we + * can use a naked attribute. This is called by the application, so we don't have + * to check which bank is loaded. + */ +void vPortYield( void ) __preserves_regs(a,b,c,d,e,h,l,iyh,iyl) __naked +{ + portSAVE_CONTEXT(); + vTaskSwitchContext(); + portRESTORE_CONTEXT(); +} +/*-----------------------------------------------------------*/ + +/* + * Manual context switch callable from ISRs. The first thing we do is save + * the registers so we can use a naked attribute. + */ +void vPortYieldFromISR(void) __preserves_regs(a,b,c,d,e,h,l,iyh,iyl) __naked +void vPortYieldFromISR(void) +{ + portSAVE_CONTEXT_IN_ISR(); + vTaskSwitchContext(); + portRESTORE_CONTEXT_IN_ISR(); +} +/*-----------------------------------------------------------*/ + +/* + * Initialize Timer (PRT1 for YAZ180, and SCZ180 HBIOS). + */ +void prvSetupTimerInterrupt( void ) __preserves_regs(iyh,iyl) +{ + configSETUP_TIMER_INTERRUPT(); +} +/*-----------------------------------------------------------*/ + +void timer_isr(void) __preserves_regs(a,b,c,d,e,h,l,iyh,iyl) __naked +{ +#if configUSE_PREEMPTION == 1 + /* + * Tick ISR for preemptive scheduler. We can use a naked attribute as + * the context is saved at the start of timer_isr(). The tick + * count is incremented after the context is saved. + * + * Context switch function used by the tick. This must be identical to + * vPortYield() from the call to vTaskSwitchContext() onwards. The only + * difference from vPortYield() is the tick count is incremented as the + * call comes from the tick ISR. + */ + portSAVE_CONTEXT_IN_ISR(); + configRESET_TIMER_INTERRUPT(); + xTaskIncrementTick(); + vTaskSwitchContext(); + portRESTORE_CONTEXT_IN_ISR(); +#else + /* + * Tick ISR for the cooperative scheduler. All this does is increment the + * tick count. We don't need to switch context, this can only be done by + * manual calls to taskYIELD(); + */ + portSAVE_CONTEXT_IN_ISR(); + configRESET_TIMER_INTERRUPT(); + xTaskIncrementTick(); + portRESTORE_CONTEXT_IN_ISR(); +#endif +} // configUSE_PREEMPTION diff --git a/Z88DK/Z180/portmacro.h b/Z88DK/Z180/portmacro.h new file mode 100644 index 0000000..f8f2f02 --- /dev/null +++ b/Z88DK/Z180/portmacro.h @@ -0,0 +1,431 @@ +/* + * FreeRTOS Kernel V10.4.3 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given Z80 (Z180, Z80N) hardware and SCCZ80 or SDCC compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions. */ +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT int + +typedef uint16_t StackType_t; +typedef int8_t BaseType_t; +typedef uint8_t UBaseType_t; + +#if configUSE_16_BIT_TICKS == 1 + typedef uint16_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff +#else + typedef uint32_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffffffffUL +#endif +/*-----------------------------------------------------------*/ + +/* General purpose stringify macros. */ + +#define string(a) __string(a) +#define __string(a) #a +/*-----------------------------------------------------------*/ + +/* Critical section management using sccz80 compiler. */ + +#ifdef __SCCZ80 + +#define portENTER_CRITICAL() \ + do{ \ + asm( \ + "ld a,i \n" \ + "di \n" \ + "push af \n" \ + ); \ + }while(0) + +#define portEXIT_CRITICAL() \ + do{ \ + asm( \ + "pop af \n" \ + "; di ; unneeded \n" \ + "jp PO,ASMPC+4 \n" \ + "ei \n" \ + ); \ + }while(0) + +#define portDISABLE_INTERRUPTS() \ + do{ \ + asm( \ + "di \n" \ + ); \ + }while(0) + +#define portENABLE_INTERRUPTS() \ + do{ \ + asm( \ + "ei \n" \ + ); \ + }while(0) + +#define portNOP() \ + do{ \ + asm( \ + "nop \n" \ + ); \ + }while(0) + +/* + * Macros to save all the registers, and save the stack pointer into the TCB. + */ + +#define portSAVE_CONTEXT() \ + do{ \ + asm( \ + "push af \n" \ + "ld a,i \n" \ + "di \n" \ + "push af ; iff1:iff2\n" \ + "push bc \n" \ + "push de \n" \ + "push hl \n" \ + "exx \n" \ + "ex af,af \n" \ + "push af \n" \ + "push bc \n" \ + "push de \n" \ + "push hl \n" \ + "push ix \n" \ + "push iy \n" \ + "ld hl,0 \n" \ + "add hl,sp \n" \ + "ld de,(_pxCurrentTCB) \n"\ + "ex de,hl \n" \ + "ld (hl),e \n" \ + "inc hl \n" \ + "ld (hl),d \n" \ + ); \ + }while(0) + +#define portRESTORE_CONTEXT() \ + do{ \ + asm( \ + "ld hl,(_pxCurrentTCB) \n" \ + "ld e,(hl) \n" \ + "inc hl \n" \ + "ld d,(hl) \n" \ + "ex de,hl \n" \ + "ld sp,hl \n" \ + "pop iy \n" \ + "pop ix \n" \ + "pop hl \n" \ + "pop de \n" \ + "pop bc \n" \ + "pop af \n" \ + "ex af,af \n" \ + "exx \n" \ + "pop hl \n" \ + "pop de \n" \ + "pop bc \n" \ + "pop af ; iff1:iff2\n" \ + "; di ; unneeded \n" \ + "jp PO,ASMPC+4 \n" \ + "ei \n" \ + "pop af \n" \ + "ret \n" \ + ); \ + }while(0) + +#define portSAVE_CONTEXT_IN_ISR() \ + do{ \ + asm( \ + "PHASE "string(configISR_ORG)" \n" \ + "._timer_isr_start \n" \ + "push af \n" \ + "ld a,0x7F \n" \ + "inc a ; set PE \n" \ + "push af ; iff1:iff2\n" \ + "push bc \n" \ + "push de \n" \ + "push hl \n" \ + "exx \n" \ + "ex af,af \n" \ + "push af \n" \ + "push bc \n" \ + "push de \n" \ + "push hl \n" \ + "push ix \n" \ + "push iy \n" \ + "ld hl,0 \n" \ + "add hl,sp \n" \ + "ld de,(_pxCurrentTCB) \n" \ + "ex de,hl \n" \ + "ld (hl),e \n" \ + "inc hl \n" \ + "ld (hl),d \n" \ + ); \ + }while(0) + +#define portRESTORE_CONTEXT_IN_ISR()\ + do{ \ + asm( \ + "ld hl,(_pxCurrentTCB) \n" \ + "ld e,(hl) \n" \ + "inc hl \n" \ + "ld d,(hl) \n" \ + "ex de,hl \n" \ + "ld sp,hl \n" \ + "pop iy \n" \ + "pop ix \n" \ + "pop hl \n" \ + "pop de \n" \ + "pop bc \n" \ + "pop af \n" \ + "ex af,af \n" \ + "exx \n" \ + "pop hl \n" \ + "pop de \n" \ + "pop bc \n" \ + "pop af ; iff1:iff2\n" \ + "; di ; unneeded \n" \ + "jp PO,ASMPC+4 \n" \ + "ei \n" \ + "pop af \n" \ + "reti \n" \ + "._timer_isr_end \n" \ + "DEPHASE \n" \ + ); \ + }while(0) + +#endif +/*-----------------------------------------------------------*/ + +/* Critical section management using sdcc compiler. */ + +#ifdef __SDCC + +#define portENTER_CRITICAL() \ + do{ \ + __asm \ + ld a,i \ + di \ + push af \ + __endasm; \ + }while(0) + +#define portEXIT_CRITICAL() \ + do{ \ + __asm \ + pop af \ + ; di ; unneeded \ + jp PO,ASMPC+4 \ + ei \ + __endasm; \ + }while(0) + +#define portDISABLE_INTERRUPTS() \ + do{ \ + __asm \ + di \ + __endasm; \ + }while(0) + +#define portENABLE_INTERRUPTS() \ + do{ \ + __asm \ + ei \ + __endasm; \ + }while(0) + +#define portNOP() \ + do{ \ + __asm \ + nop \ + __endasm; \ + }while(0) + +/* + * Macros to save all the registers, and save the stack pointer into the TCB. + */ + +#define portSAVE_CONTEXT() \ + do{ \ + __asm \ + push af \ + ld a,i \ + di \ + push af ; iff1:iff2 \ + push bc \ + push de \ + push hl \ + exx \ + ex af,af \ + push af \ + push bc \ + push de \ + push hl \ + push ix \ + push iy \ + ld hl,0 \ + add hl,sp \ + ld de,(_pxCurrentTCB) \ + ex de,hl \ + ld (hl),e \ + inc hl \ + ld (hl),d \ + __endasm; \ + }while(0) + +#define portRESTORE_CONTEXT() \ + do{ \ + __asm \ + ld hl,(_pxCurrentTCB) \ + ld e,(hl) \ + inc hl \ + ld d,(hl) \ + ex de,hl \ + ld sp,hl \ + pop iy \ + pop ix \ + pop hl \ + pop de \ + pop bc \ + pop af \ + ex af,af \ + exx \ + pop hl \ + pop de \ + pop bc \ + pop af ; iff1:iff2 \ + ; di ; unneeded \ + jp PO,ASMPC+4 \ + ei \ + pop af \ + ret \ + __endasm; \ + }while(0) + +#define portSAVE_CONTEXT_IN_ISR() \ + do{ \ + __asm \ + PHASE configISR_ORG \ + _timer_isr_start: \ + push af \ + ld a,0x7F \ + inc a ; set PE \ + push af ; iff1:iff2 \ + push bc \ + push de \ + push hl \ + exx \ + ex af,af \ + push af \ + push bc \ + push de \ + push hl \ + push ix \ + push iy \ + ld hl,0 \ + add hl,sp \ + ld de,(_pxCurrentTCB) \ + ex de,hl \ + ld (hl),e \ + inc hl \ + ld (hl),d \ + __endasm; \ + }while(0) + +#define portRESTORE_CONTEXT_IN_ISR()\ + do{ \ + __asm \ + ld hl,(_pxCurrentTCB) \ + ld e,(hl) \ + inc hl \ + ld d,(hl) \ + ex de,hl \ + ld sp,hl \ + pop iy \ + pop ix \ + pop hl \ + pop de \ + pop bc \ + pop af \ + ex af,af \ + exx \ + pop hl \ + pop de \ + pop bc \ + pop af ; iff1:iff2 \ + ; di ; unneeded \ + jp PO,ASMPC+4 \ + ei \ + pop af \ + reti \ + _timer_isr_end: \ + DEPHASE \ + __endasm; \ + }while(0) + +#endif +/*-----------------------------------------------------------*/ + +/* Architecture specifics. */ + +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portBYTE_ALIGNMENT 1 +/*-----------------------------------------------------------*/ + +/* Kernel utilities. */ +extern void vPortYield( void ); +#define portYIELD() vPortYield() + +extern void vPortYieldFromISR( void ); +#define portYIELD_FROM_ISR() vPortYieldFromISR() +/*-----------------------------------------------------------*/ + +/* Task function macros as described on the FreeRTOS.org WEB site. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) + +#ifdef __cplusplus +} +#endif + +#endif /* PORTMACRO_H */ diff --git a/Z88DK/Z180/readme.md b/Z88DK/Z180/readme.md new file mode 100644 index 0000000..89af17a --- /dev/null +++ b/Z88DK/Z180/readme.md @@ -0,0 +1,13 @@ +<h1>z180 support</h1> + +Description +----------- +This PR establishes support for a Zilog z180 port, using the Programmable Reload Timer 1, configured at 256 Hz. + +Because of the generality of the z180, the address of the Interrupt Vector for PRT1 is configurable, and must be configured by the `crt0.asm` outside of this port. A configuration assumption has been made. + +The two compilers ([used by the z88dk](https://github.com/z88dk/z88dk)) are supported. The sccz80 compiler and the sdcc compiler. The PR is located under Z88dk. + +Background +----------- +This PR is based on running code for the [SC130](https://smallcomputercentral.wordpress.com/sc130-z180-motherboard/)/[SC131](https://smallcomputercentral.wordpress.com/sc131-z180-pocket-computer/) and [YAZ180](https://github.com/feilipu/yaz180) platforms, and is maintained by the z88dk team in this [z88dk-libraries](https://github.com/feilipu/z88dk-libraries/tree/master/freertos) repository. |